package database import ( "database/sql/driver" "encoding/json" "fmt" "time" ) // StringSlice is a JSON-serialized string slice stored as a MySQL TEXT/JSON column. type StringSlice []string func (s StringSlice) Value() (driver.Value, error) { if s == nil { return "[]", nil } b, err := json.Marshal(s) return string(b), err } func (s *StringSlice) Scan(src any) error { var raw []byte switch v := src.(type) { case string: raw = []byte(v) case []byte: raw = v default: return fmt.Errorf("StringSlice: unsupported type %T", src) } return json.Unmarshal(raw, s) } // ─── Products ──────────────────────────────────────────────────────────────── // ProductRow is the GORM model for the `products` table. type ProductRow struct { ID string `gorm:"primaryKey;size:36"` Name string `gorm:"size:255;not null"` Price float64 `gorm:"not null;default:0"` DiscountPrice float64 `gorm:"default:0"` Tags StringSlice `gorm:"type:json"` CoverURL string `gorm:"size:500"` ScreenshotURLs StringSlice `gorm:"type:json"` VerificationURL string `gorm:"size:500;default:''"` Description string `gorm:"type:text"` Active bool `gorm:"default:true;index"` RequireLogin bool `gorm:"default:false"` MaxPerAccount int `gorm:"default:0"` TotalSold int `gorm:"default:0"` ViewCount int `gorm:"default:0"` DeliveryMode string `gorm:"size:20;default:'auto'"` ShowNote bool `gorm:"default:false"` ShowContact bool `gorm:"default:false"` CreatedAt time.Time `gorm:"index"` } func (ProductRow) TableName() string { return "products" } // ProductCodeRow stores individual codes for a product (one row per code). type ProductCodeRow struct { ID uint `gorm:"primaryKey;autoIncrement"` ProductID string `gorm:"size:36;not null;index"` Code string `gorm:"type:text;not null"` } func (ProductCodeRow) TableName() string { return "product_codes" } // ─── Orders ────────────────────────────────────────────────────────────────── type OrderRow struct { ID string `gorm:"primaryKey;size:36"` ProductID string `gorm:"size:36;not null;index"` ProductName string `gorm:"size:255;not null"` UserAccount string `gorm:"size:255;index"` UserName string `gorm:"size:255"` Quantity int `gorm:"not null;default:1"` DeliveredCodes StringSlice `gorm:"type:json"` Status string `gorm:"size:20;not null;default:'pending';index"` DeliveryMode string `gorm:"size:20;default:'auto'"` Note string `gorm:"type:text"` ContactPhone string `gorm:"size:50"` ContactEmail string `gorm:"size:255"` NotifyEmail string `gorm:"size:255"` CreatedAt time.Time } func (OrderRow) TableName() string { return "orders" } // ─── Site settings ─────────────────────────────────────────────────────────── // SiteSettingRow stores arbitrary key-value pairs for site-wide settings. type SiteSettingRow struct { Key string `gorm:"primaryKey;size:64"` Value string `gorm:"type:text"` } func (SiteSettingRow) TableName() string { return "site_settings" } // ─── Wishlists ─────────────────────────────────────────────────────────────── type WishlistRow struct { ID uint `gorm:"primaryKey;autoIncrement"` AccountID string `gorm:"size:255;not null;index:idx_wishlist,unique"` ProductID string `gorm:"size:36;not null;index:idx_wishlist,unique"` } func (WishlistRow) TableName() string { return "wishlists" } // ─── Chat messages ─────────────────────────────────────────────────────────── type ChatMessageRow struct { ID string `gorm:"primaryKey;size:36"` AccountID string `gorm:"size:255;not null;index"` AccountName string `gorm:"size:255"` Content string `gorm:"type:text;not null"` SentAt time.Time `gorm:"not null"` FromAdmin bool `gorm:"default:false"` } func (ChatMessageRow) TableName() string { return "chat_messages" }