From 45e8c1285d788823962a08d5975cd96c92ff0c88 Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Wed, 19 Aug 2026 14:10:24 +0800 Subject: [PATCH] fix(#40): remove illegal literal default on TEXT column image_url Co-Authored-By: Claude Opus 5 --- server/app/goauto/migrations/migrate_test.go | 26 ++++++++++++++++++++ server/app/goauto/models/schema.go | 5 +++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/server/app/goauto/migrations/migrate_test.go b/server/app/goauto/migrations/migrate_test.go index dfa94e5..75bca33 100644 --- a/server/app/goauto/migrations/migrate_test.go +++ b/server/app/goauto/migrations/migrate_test.go @@ -3,6 +3,7 @@ package migrations_test import ( "fmt" "reflect" + "regexp" "strings" "sync" "testing" @@ -333,3 +334,28 @@ func TestShopeeProductSalePriceMustNotBeNegative(t *testing.T) { t.Fatal("negative sale price was accepted") } } + +// MySQL rejects a literal DEFAULT clause on TEXT/BLOB/JSON columns +// ("BLOB, TEXT, GEOMETRY or JSON column '...' can't have a default value"). +// SQLite does not enforce this, so the SQLite-backed tests in this file never +// catch it; ShopeeProduct.ImageURL hit exactly this error against a live +// MySQL 8.4 database before this test was added. This scans every model field +// via reflection instead of requiring a MySQL connection. +func TestMySQLTextJSONBlobColumnsHaveNoLiteralDefault(t *testing.T) { + modelTypes := []any{ + &models.AgentDevice{}, &models.PDDProduct{}, &models.CollectionRule{}, &models.CollectionTask{}, + &models.CollectionDimension{}, &models.CollectionDimensionValue{}, &models.CollectionColorPrice{}, + &models.CollectionSKU{}, &models.CollectionSKUValue{}, &models.ShopeeProduct{}, + } + typePattern := regexp.MustCompile(`type:(text|json|blob)`) + for _, model := range modelTypes { + value := reflect.TypeOf(model).Elem() + for i := 0; i < value.NumField(); i++ { + tag := value.Field(i).Tag.Get("gorm") + if typePattern.MatchString(strings.ToLower(tag)) && strings.Contains(tag, "default:") { + t.Errorf("%s.%s: TEXT/JSON/BLOB column must not carry a literal gorm default tag (MySQL rejects it): %s", + value.Name(), value.Field(i).Name, tag) + } + } + } +} diff --git a/server/app/goauto/models/schema.go b/server/app/goauto/models/schema.go index c8bab44..bb1bf4d 100644 --- a/server/app/goauto/models/schema.go +++ b/server/app/goauto/models/schema.go @@ -252,7 +252,10 @@ type ShopeeProduct struct { // ImageURL holds the SYB-provided reference image URL. It is written by the // #41 import and may be overridden manually; the product domain never joins // syb_products at read time. - ImageURL string `json:"imageUrl" gorm:"type:text;not null;default:''"` + // MySQL rejects a literal DEFAULT on TEXT/BLOB/JSON columns, so this stays + // NOT NULL without a DB-level default; Go's zero value ("") is inserted + // explicitly on every create, which satisfies NOT NULL without needing one. + ImageURL string `json:"imageUrl" gorm:"type:text;not null"` // SalePriceCent is the reference selling price in integer cents, consistent // with the priceCent convention from #31. It is the value seen at the latest // import or manual edit, not an authoritative transaction price.