feat(exporter): 支持从order_info表导出数据并适配不同表结构

修改SQL构建逻辑以同时支持从order和order_info表导出数据
根据主表类型自动适配不同的字段名和关联条件
This commit is contained in:
zhouyonggao 2025-11-26 18:16:01 +08:00
parent 7e7fdbc4cc
commit 741722b6b1
2 changed files with 192 additions and 130 deletions

View File

@ -14,9 +14,9 @@ type BuildRequest struct {
}
func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{}, error) {
if req.MainTable != "order" {
return "", nil, errors.New("unsupported main table")
}
if req.MainTable != "order" && req.MainTable != "order_info" {
return "", nil, errors.New("unsupported main table")
}
cols := []string{}
need := map[string]bool{}
for _, tf := range req.Fields {
@ -71,44 +71,49 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
sb := strings.Builder{}
sb.WriteString("SELECT ")
sb.WriteString(strings.Join(cols, ","))
sb.WriteString(" FROM `order`")
sb.WriteString(" FROM `" + req.MainTable + "`")
// JOINs based on need
// order_detail
if need["order_detail"] {
sb.WriteString(" LEFT JOIN `order_detail` ON `order_detail`.order_number = `order`.order_number")
}
// order_cash
if need["order_cash"] {
sb.WriteString(" LEFT JOIN `order_cash` ON `order_cash`.order_number = `order`.order_number")
}
// order_voucher
if need["order_voucher"] {
sb.WriteString(" LEFT JOIN `order_voucher` ON `order_voucher`.order_number = `order`.order_number")
}
if need["order_detail"] && req.MainTable == "order" {
sb.WriteString(" LEFT JOIN `order_detail` ON `order_detail`.order_number = `order`.order_number")
}
// order_cash
if need["order_cash"] {
if req.MainTable == "order_info" {
sb.WriteString(" LEFT JOIN `order_cash` ON `order_cash`.order_no = `order_info`.order_no")
} else {
sb.WriteString(" LEFT JOIN `order_cash` ON `order_cash`.order_number = `order`.order_number")
}
}
// order_voucher
if need["order_voucher"] {
if req.MainTable == "order_info" {
sb.WriteString(" LEFT JOIN `order_voucher` ON `order_voucher`.order_no = `order_info`.order_no")
} else {
sb.WriteString(" LEFT JOIN `order_voucher` ON `order_voucher`.order_number = `order`.order_number")
}
}
// plan
if need["plan"] || need["key_batch"] {
sb.WriteString(" LEFT JOIN `plan` ON `plan`.id = `order`.plan_id")
}
// key_batch depends on plan
if need["key_batch"] {
sb.WriteString(" LEFT JOIN `key_batch` ON `key_batch`.plan_id = `plan`.id")
}
// code_batch depends on key_batch
if need["code_batch"] {
sb.WriteString(" LEFT JOIN `code_batch` ON `code_batch`.key_batch_id = `key_batch`.id")
}
// voucher depends on order_voucher
if need["voucher"] {
sb.WriteString(" LEFT JOIN `voucher` ON `voucher`.channel_activity_id = `order_voucher`.channel_activity_id")
}
// voucher_batch depends on voucher
if need["voucher_batch"] {
sb.WriteString(" LEFT JOIN `voucher_batch` ON `voucher_batch`.voucher_id = `voucher`.id")
}
// merchant_key_send depends on order.key
if need["merchant_key_send"] {
sb.WriteString(" LEFT JOIN `merchant_key_send` ON `order`." + escape("key") + " = `merchant_key_send`.key")
}
if req.MainTable == "order" {
if need["plan"] || need["key_batch"] {
sb.WriteString(" LEFT JOIN `plan` ON `plan`.id = `order`.plan_id")
}
if need["key_batch"] {
sb.WriteString(" LEFT JOIN `key_batch` ON `key_batch`.plan_id = `plan`.id")
}
if need["code_batch"] {
sb.WriteString(" LEFT JOIN `code_batch` ON `code_batch`.key_batch_id = `key_batch`.id")
}
if need["voucher"] {
sb.WriteString(" LEFT JOIN `voucher` ON `voucher`.channel_activity_id = `order_voucher`.channel_activity_id")
}
if need["voucher_batch"] {
sb.WriteString(" LEFT JOIN `voucher_batch` ON `voucher_batch`.voucher_id = `voucher`.id")
}
if need["merchant_key_send"] {
sb.WriteString(" LEFT JOIN `merchant_key_send` ON `order`." + escape("key") + " = `merchant_key_send`.key")
}
}
args := []interface{}{}
where := []string{}
@ -127,8 +132,8 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
if _, ok := req.Filters["merchant_out_biz_no_eq"]; ok {
need["merchant_key_send"] = true
}
if v, ok := req.Filters["creator_in"]; ok {
ids := []interface{}{}
if v, ok := req.Filters["creator_in"]; ok {
ids := []interface{}{}
switch t := v.(type) {
case []interface{}:
ids = t
@ -146,20 +151,28 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
}
ph := strings.Repeat("?,", len(ids))
ph = strings.TrimSuffix(ph, ",")
where = append(where, "`order`.creator IN ("+ph+")")
args = append(args, ids...)
}
if v, ok := req.Filters["create_time_between"]; ok {
if req.MainTable == "order_info" {
where = append(where, "`order_info`.user_id IN ("+ph+")")
} else {
where = append(where, "`order`.creator IN ("+ph+")")
}
args = append(args, ids...)
}
if v, ok := req.Filters["create_time_between"]; ok {
var arr []interface{}
b, _ := json.Marshal(v)
json.Unmarshal(b, &arr)
if len(arr) != 2 {
return "", nil, errors.New("create_time_between requires 2 values")
}
where = append(where, "`order`.create_time BETWEEN ? AND ?")
args = append(args, arr[0], arr[1])
}
if v, ok := req.Filters["type_eq"]; ok {
if req.MainTable == "order_info" {
where = append(where, "`order_info`.create_time BETWEEN ? AND ?")
} else {
where = append(where, "`order`.create_time BETWEEN ? AND ?")
}
args = append(args, arr[0], arr[1])
}
if v, ok := req.Filters["type_eq"]; ok {
var tv int
switch t := v.(type) {
case float64:
@ -176,88 +189,132 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
tv = tv*10 + int(c-'0')
}
}
if tv == 1 || tv == 2 || tv == 3 {
where = append(where, "`order`.type = ?")
args = append(args, tv)
}
}
if v, ok := req.Filters["out_trade_no_eq"]; ok {
s := toString(v)
if s != "" {
where = append(where, "`order`.out_trade_no = ?")
args = append(args, s)
}
}
if v, ok := req.Filters["account_eq"]; ok {
s := toString(v)
if s != "" {
where = append(where, "`order`.account = ?")
args = append(args, s)
}
}
if v, ok := req.Filters["plan_id_eq"]; ok {
s := toString(v)
if s != "" {
where = append(where, "`order`.plan_id = ?")
args = append(args, s)
}
}
if v, ok := req.Filters["key_batch_id_eq"]; ok {
s := toString(v)
if s != "" {
where = append(where, "`order`.key_batch_id = ?")
args = append(args, s)
}
}
if v, ok := req.Filters["product_id_eq"]; ok {
s := toString(v)
if s != "" {
where = append(where, "`order`.product_id = ?")
args = append(args, s)
}
}
if v, ok := req.Filters["reseller_id_eq"]; ok {
s := toString(v)
if s != "" {
where = append(where, "`order`.reseller_id = ?")
args = append(args, s)
}
}
if v, ok := req.Filters["code_batch_id_eq"]; ok {
s := toString(v)
if s != "" {
where = append(where, "`order`.code_batch_id = ?")
args = append(args, s)
}
}
if v, ok := req.Filters["order_cash_cash_activity_id_eq"]; ok {
s := toString(v)
if s != "" {
where = append(where, "`order_cash`.cash_activity_id = ?")
args = append(args, s)
}
}
if v, ok := req.Filters["order_voucher_channel_activity_id_eq"]; ok {
s := toString(v)
if s != "" {
where = append(where, "`order_voucher`.channel_activity_id = ?")
args = append(args, s)
}
}
if v, ok := req.Filters["voucher_batch_channel_activity_id_eq"]; ok {
s := toString(v)
if s != "" {
where = append(where, "`voucher_batch`.channel_activity_id = ?")
args = append(args, s)
}
}
if v, ok := req.Filters["merchant_out_biz_no_eq"]; ok {
s := toString(v)
if s != "" {
where = append(where, "`merchant_key_send`.out_biz_no = ?")
args = append(args, s)
}
}
if tv == 1 || tv == 2 || tv == 3 {
if req.MainTable == "order_info" {
where = append(where, "`order_info`.type = ?")
} else {
where = append(where, "`order`.type = ?")
}
args = append(args, tv)
}
}
if v, ok := req.Filters["out_trade_no_eq"]; ok {
s := toString(v)
if s != "" {
if req.MainTable == "order_info" {
where = append(where, "`order_info`.out_order_no = ?")
} else {
where = append(where, "`order`.out_trade_no = ?")
}
args = append(args, s)
}
}
if v, ok := req.Filters["account_eq"]; ok {
s := toString(v)
if s != "" {
if req.MainTable == "order_info" {
where = append(where, "`order_info`.account = ?")
} else {
where = append(where, "`order`.account = ?")
}
args = append(args, s)
}
}
if v, ok := req.Filters["plan_id_eq"]; ok {
s := toString(v)
if s != "" {
if req.MainTable == "order_info" {
where = append(where, "`order_info`.activity_id = ?")
} else {
where = append(where, "`order`.plan_id = ?")
}
args = append(args, s)
}
}
if v, ok := req.Filters["key_batch_id_eq"]; ok {
s := toString(v)
if s != "" {
if req.MainTable == "order_info" {
where = append(where, "`order_info`.key_batch_name = ?")
} else {
where = append(where, "`order`.key_batch_id = ?")
}
args = append(args, s)
}
}
if v, ok := req.Filters["product_id_eq"]; ok {
s := toString(v)
if s != "" {
if req.MainTable == "order_info" {
where = append(where, "`order_info`.goods_id = ?")
} else {
where = append(where, "`order`.product_id = ?")
}
args = append(args, s)
}
}
if v, ok := req.Filters["reseller_id_eq"]; ok {
s := toString(v)
if s != "" {
if req.MainTable == "order_info" {
where = append(where, "`order_info`.merchant_id = ?")
} else {
where = append(where, "`order`.reseller_id = ?")
}
args = append(args, s)
}
}
if v, ok := req.Filters["code_batch_id_eq"]; ok {
s := toString(v)
if s != "" {
if req.MainTable == "order_info" {
where = append(where, "`order_info`.supplier_product_id = ?")
} else {
where = append(where, "`order`.code_batch_id = ?")
}
args = append(args, s)
}
}
if v, ok := req.Filters["order_cash_cash_activity_id_eq"]; ok {
s := toString(v)
if s != "" {
if req.MainTable == "order_info" {
where = append(where, "`order_cash`.activity_id = ?")
} else {
where = append(where, "`order_cash`.cash_activity_id = ?")
}
args = append(args, s)
}
}
if v, ok := req.Filters["order_voucher_channel_activity_id_eq"]; ok {
s := toString(v)
if s != "" {
if req.MainTable == "order_info" {
where = append(where, "`order_voucher`.channel_batch_no = ?")
} else {
where = append(where, "`order_voucher`.channel_activity_id = ?")
}
args = append(args, s)
}
}
if v, ok := req.Filters["voucher_batch_channel_activity_id_eq"]; ok {
s := toString(v)
if s != "" {
if req.MainTable == "order" { // only marketing schema has voucher_batch
where = append(where, "`voucher_batch`.channel_activity_id = ?")
args = append(args, s)
}
}
}
if v, ok := req.Filters["merchant_out_biz_no_eq"]; ok {
s := toString(v)
if s != "" {
if req.MainTable == "order" { // marketing only
where = append(where, "`merchant_key_send`.out_biz_no = ?")
}
args = append(args, s)
}
}
if len(where) > 0 {
sb.WriteString(" WHERE ")
sb.WriteString(strings.Join(where, " AND "))

View File

@ -374,3 +374,8 @@ job_id=47 sql=UPDATE export_jobs SET status=?, started_at=? WHERE id= ? args=[ru
{"bytes":77,"duration_ms":16,"kind":"access","level":"INFO","method":"","path":"","query":"","remote":"","status":200,"trace_id":"","ts":"2025-11-26T17:54:11+08:00"}
{"bytes":1614,"duration_ms":16,"kind":"access","level":"INFO","method":"","path":"","query":"","remote":"","status":200,"trace_id":"","ts":"2025-11-26T17:54:11+08:00"}
{"bytes":1040,"duration_ms":51,"kind":"access","level":"INFO","method":"","path":"","query":"","remote":"","status":200,"trace_id":"","ts":"2025-11-26T17:54:16+08:00"}
{"bytes":1040,"duration_ms":55,"kind":"access","level":"INFO","method":"","path":"","query":"","remote":"","status":200,"trace_id":"","ts":"2025-11-26T18:12:45+08:00"}
{"bytes":914,"duration_ms":108,"kind":"access","level":"INFO","method":"","path":"","query":"","remote":"","status":200,"trace_id":"","ts":"2025-11-26T18:12:48+08:00"}
{"bytes":1614,"duration_ms":10,"kind":"access","level":"INFO","method":"","path":"","query":"","remote":"","status":200,"trace_id":"","ts":"2025-11-26T18:12:48+08:00"}
{"bytes":914,"duration_ms":107,"kind":"access","level":"INFO","method":"","path":"","query":"","remote":"","status":200,"trace_id":"","ts":"2025-11-26T18:12:51+08:00"}
{"bytes":1040,"duration_ms":51,"kind":"access","level":"INFO","method":"","path":"","query":"","remote":"","status":200,"trace_id":"","ts":"2025-11-26T18:15:41+08:00"}