I was trying to create a GORM model for a postgres database, containing a type with a custom Scanner
and Valuer
that converts a string slice to and from a string, to be saved as a single database column. If the slice is either empty or nil, I want the database column to also be nil (as opposed to an empty string).
type MultiString []string
func (s *MultiString) Scan(src interface{}) error {
str, ok := src.(string)
if !ok {
return errors.New("failed to scan multistring field - source is not a string")
}
*s = strings.Split(str, ",")
return nil
}
func (s MultiString) Value() (driver.Value, error) {
if s == nil || len(s) == 0 {
return nil, nil
}
return strings.Join(s, ","), nil
}
The problem arises when I try and call AutoMigrate
on the following struct:
type Person struct {
ID int
Name string
Kids *MultiString
}
I get the following errors multiple times:
[error] unsupported data type: &[]
In the - This is incorrect, as Value
method, replace the returned nil
with sql.NullString{}
Value
should not return another Valuer
.
The problem is that GORM is unsure of what the datatype should be for the newly defined type, so it tried to figure it out. Instead, the type should be explicitly defined, either with a tag in the model or by implementing a gorm method on the new type
Tag in the model
type MyModel struct {
...
MyText MultiString `gorm:"type:text"`
}
This tells GORM to use the type text
for the DB column type. With this strategy, the tag must be applied every time the new type is used in a model.
GORM Methods
Two GORM methods can be implemented on the new data type to tell GORM what database type should be used:
GormDataType() string
GormDBDataType(db *gorm.DB, field *schema.Field) string
Examples:
func (MultiString) GormDataType() string {
return "text"
}
func (MultiString) GormDBDataType(db *gorm.DB, field *schema.Field) string {
// returns different database type based on driver name
switch db.Dialector.Name() {
case "mysql", "sqlite":
return "text"
}
return ""
}
This one is useful for if the data type differs between what type of database you're using.