Search code examples
mysqljsongomarshallinggo-gorm

gorm: json of json not work


Sample:

{
  "id": 1
  "data": {"1": 2}
}

Struct definition:

type Item struct {
  id int `json:"id"`
  data interface{} `json:"data"`
}

I need to parse the payload from a http post, so I used interface{} for data, json.Unmarshal() is successful, but gorm produces error while calling db.Create(item):

(sql: converting Exec argument #5's type: unsupported type map[string]interface {}, a map)

Instead, I change from interface{} to string, calling json.Unmarshal() to parse json POST payload produces error.

unmarshal type error: expected=string, got=object

Basically, one requires interface{}, one requires string.

Anyone encountered this?


Solution

  • The solution is defining a custom type that implements sql.Valuer, sql.Scanner, json.Marshaler and json.Unmarshaler interfaces. Sample of my implementation:

    type Data string
    
    func (t *Data) MarshalJSON() ([]byte, error) {
        return []byte(*t), nil
    }
    
    func (t *Data) UnmarshalJSON(data []byte) error {
        *t = Data(data)
        return nil
    }
    
    func (t Data) Value() (driver.Value, error) {
        return string(t), nil
    }
    
    func (t *Data) Scan(src interface{}) error {
        s, ok := src.([]byte)
        if !ok {
            return nil
        }
        *t = Data(s)
        return nil
    }
    
    // Data implements the below interfaces to satisfy both
    // json parser and sql parser
    var _ json.Marshaler = (*Data)(nil)
    var _ json.Unmarshaler = (*Data)(nil)
    var _ sql.Scanner = (*Data)(nil)
    var _ driver.Valuer = (*Data)(nil)