feat: 支持无SKU目录导入策略 (#141)

This commit is contained in:
chengma
2026-08-11 11:03:18 +08:00
parent 6386d76488
commit 4259be0e55
17 changed files with 766 additions and 73 deletions
+52
View File
@@ -5,11 +5,14 @@ import (
"crypto/sha256"
"database/sql"
"encoding/binary"
"encoding/json"
"fmt"
"path/filepath"
"sort"
"strings"
"time"
"cmautobuy/admin/spec"
)
// SQLiteMigrationSummary 只包含表名和数量,可以安全写入终端或工单。
@@ -117,6 +120,9 @@ func MigrateSQLiteToMySQL(source, target *sql.DB, dryRun bool) (*SQLiteMigration
return nil, err
}
}
if err := normalizeMigratedShopeeSKUs(tx); err != nil {
return nil, err
}
if err := tx.Commit(); err != nil {
return nil, &SQLiteMigrationError{Stage: "无法提交 MySQL 导入事务", Cause: err}
}
@@ -126,6 +132,52 @@ func MigrateSQLiteToMySQL(source, target *sql.DB, dryRun bool) (*SQLiteMigration
return summary, nil
}
// normalizeMigratedShopeeSKUs 补齐 MySQL v8 新增、历史 SQLite 没有的规格身份列。
func normalizeMigratedShopeeSKUs(tx *sql.Tx) error {
rows, err := tx.Query(`SELECT sku_id,spec_raw,color,size,advice,sku_code,updated_at FROM shopee_skus`)
if err != nil {
return &SQLiteMigrationError{Stage: "无法读取待转换 SKU", Table: "shopee_skus", Cause: err}
}
type item struct {
id, raw, updated string
color, size, advice, code sql.NullString
}
var list []item
for rows.Next() {
var row item
if err := rows.Scan(&row.id, &row.raw, &row.color, &row.size, &row.advice, &row.code, &row.updated); err != nil {
rows.Close()
return err
}
list = append(list, row)
}
if err := rows.Close(); err != nil {
return err
}
for _, row := range list {
key, err := spec.SpecKey(row.raw)
if err != nil {
return &SQLiteMigrationError{Stage: "历史 SKU 规格原文无效", Table: "shopee_skus", Cause: err}
}
if len([]rune(key)) > 191 {
return &SQLiteMigrationError{Stage: "历史 SKU 规格键过长", Table: "shopee_skus"}
}
sources, times := map[string]string{}, map[string]string{}
for name, value := range map[string]string{"color": row.color.String, "size": row.size.String, "advice": row.advice.String, "sku_code": row.code.String} {
if value != "" {
sources[name] = "report"
times[name] = row.updated
}
}
sourcesJSON, _ := json.Marshal(sources)
timesJSON, _ := json.Marshal(times)
if _, err := tx.Exec(`UPDATE shopee_skus SET shopee_sku_id=sku_id,spec_key=?,source='report',field_sources=?,field_observed_at=? WHERE sku_id=?`, key, string(sourcesJSON), string(timesJSON), row.id); err != nil {
return &SQLiteMigrationError{Stage: "无法补齐 MySQL v8 SKU 身份", Table: "shopee_skus", Cause: err}
}
}
return nil
}
// VerifySQLiteToMySQL 比较逐表数量和全部迁移列的确定性摘要,不输出业务内容。
func VerifySQLiteToMySQL(source, target *sql.DB) (*SQLiteMigrationSummary, error) {
if err := validateLegacySQLite(source); err != nil {