package dts import ( "context" "database/sql/driver" "encoding/json" "errors" "fmt" "strings" "gorm.io/driver/mysql" "gorm.io/gorm" "gorm.io/gorm/clause" "gorm.io/gorm/schema" ) // Slice give a generic data type for json encoded slice data. type Slice[T any] []T func NewSlice[T any](s []T) Slice[T] { return s } // Value return json value, implement driver.Valuer interface func (j Slice[T]) Value() (driver.Value, error) { return json.Marshal(j) } // Scan scan value into Slice[T], implements sql.Scanner interface func (j *Slice[T]) Scan(value interface{}) error { var bytes []byte switch v := value.(type) { case []byte: bytes = v case string: bytes = []byte(v) default: return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value)) } return json.Unmarshal(bytes, &j) } // GormDataType gorm common data type func (Slice[T]) GormDataType() string { return "slices" } // GormDBDataType gorm db data type func (Slice[T]) GormDBDataType(db *gorm.DB, field *schema.Field) string { switch db.Dialector.Name() { case "sqlite": return "JSON" case "mysql": return "JSON" case "postgres": return "JSONB" } return "" } func (j Slice[T]) GormValue(ctx context.Context, db *gorm.DB) clause.Expr { data, _ := json.Marshal(j) switch db.Dialector.Name() { case "mysql": if v, ok := db.Dialector.(*mysql.Dialector); ok && !strings.Contains(v.ServerVersion, "MariaDB") { return gorm.Expr("CAST(? AS JSON)", string(data)) } } return gorm.Expr("?", string(data)) }