Files
backend_v2/scripts/i18n/main.go
toom1996 30c9f21da4 update
2026-08-26 10:45:21 +08:00

107 lines
3.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Command i18n_migrate 落地方案 A 的 i18n 列(加列 + 回填)。
//
// 项目已移除 AutoMigrate,表结构由外部 SQL 托管(见 scripts/sql/002_i18n_columns.sql,
// 那是给人 review 的规范底稿)。本程序是「没有 mysql 客户端时」的执行器:
// - ALTER 走 ensureColumn:先查 information_schema,缺才加,可安全重跑(幂等)。
// - 回填 UPDATE 内联且幂等,重跑无害。
//
// 不写任何业务逻辑。
package main
import (
"fmt"
"log"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
const dsn = "root:root@tcp(127.0.0.1:3306)/db?charset=utf8mb4&parseTime=True&loc=Local"
const han = "[一-鿿]"
func main() {
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal("open:", err)
}
// 1) 幂等加列(与 002_i18n_columns.sql 对齐)
ensureColumn(db, "brand", "name_en", "VARCHAR(255) NOT NULL DEFAULT '' AFTER name")
ensureColumn(db, "brand", "name_cn", "VARCHAR(255) NOT NULL DEFAULT '' AFTER name_en")
ensureColumn(db, "brand_runway", "title_en", "VARCHAR(255) NOT NULL DEFAULT '' AFTER title")
ensureColumn(db, "brand_runway", "title_cn", "VARCHAR(255) NOT NULL DEFAULT '' AFTER title_en")
ensureColumn(db, "brand_runway", "description_en", "VARCHAR(1024) NOT NULL DEFAULT '' AFTER description")
ensureColumn(db, "brand_runway", "description_cn", "VARCHAR(1024) NOT NULL DEFAULT '' AFTER description_en")
// 2) 回填品牌名:从 name / show_name 拆拉丁与中文(幂等)
db.Exec(fmt.Sprintf(`
UPDATE brand SET
name_en = CASE
WHEN TRIM(REGEXP_REPLACE(name, '%s', '')) <> '' THEN TRIM(REGEXP_REPLACE(name, '%s', ''))
WHEN show_name LIKE '%%/%%' THEN TRIM(SUBSTRING_INDEX(show_name, '/', 1))
ELSE ''
END,
name_cn = CASE
WHEN show_name LIKE '%%/%%' AND SUBSTRING_INDEX(show_name, '/', -1) REGEXP '%s'
THEN TRIM(SUBSTRING_INDEX(show_name, '/', -1))
WHEN show_name REGEXP '%s' THEN TRIM(show_name)
WHEN name REGEXP '%s' THEN TRIM(name)
ELSE ''
END`, han, han, han, han, han))
// 3) 回填走秀:title / description 当前全英文,直接进 *_en(幂等)
db.Exec(`UPDATE brand_runway SET title_en = title, description_en = description, title_cn = '', description_cn = ''`)
// 4) 校验
printCounts(db)
fmt.Println("migration done.")
}
func ensureColumn(db *gorm.DB, table, col, def string) {
var n int64
db.Raw("SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='db' AND TABLE_NAME=? AND COLUMN_NAME=?", table, col).Scan(&n)
if n > 0 {
fmt.Printf(" skip %s.%s (exists)\n", table, col)
return
}
stmt := fmt.Sprintf("ALTER TABLE %s ADD COLUMN %s %s", table, col, def)
fmt.Println(" +", stmt)
if r := db.Exec(stmt); r.Error != nil {
log.Fatalf("alter %s.%s failed: %v", table, col, r.Error)
}
}
func printCounts(db *gorm.DB) {
type c struct {
Tot, En, Cn, Both, Dcn int64
}
var b c
db.Raw(`SELECT COUNT(*) tot,
SUM(CASE WHEN name_en<>'' THEN 1 ELSE 0 END) en,
SUM(CASE WHEN name_cn<>'' THEN 1 ELSE 0 END) cn,
SUM(CASE WHEN name_en<>'' AND name_cn<>'' THEN 1 ELSE 0 END) both_cnt
FROM brand`).Scan(&b)
fmt.Printf(" brand: total=%d name_en=%d name_cn=%d both=%d\n", b.Tot, b.En, b.Cn, b.Both)
var r c
db.Raw(`SELECT COUNT(*) tot,
SUM(CASE WHEN title_en<>'' THEN 1 ELSE 0 END) en,
SUM(CASE WHEN title_cn<>'' THEN 1 ELSE 0 END) cn,
SUM(CASE WHEN description_cn<>'' THEN 1 ELSE 0 END) dcn
FROM brand_runway WHERE is_deleted=0`).Scan(&r)
fmt.Printf(" runway: total=%d title_en=%d title_cn=%d desc_cn=%d\n", r.Tot, r.En, r.Cn, r.Dcn)
type s struct {
Name string
ShowName string
NameEn string
NameCn string
}
var samples []s
db.Raw("SELECT name, show_name, name_en, name_cn FROM brand WHERE name REGEXP ? OR show_name REGEXP ? ORDER BY id LIMIT 8", han, han).Scan(&samples)
fmt.Println(" brand samples:")
for _, x := range samples {
fmt.Printf(" name=%-18q show=%-26q -> en=%-18q cn=%-18q\n", x.Name, x.ShowName, x.NameEn, x.NameCn)
}
}