Gorp, sql.NullString and JSON
Using the Gorp package provides the ability for a struct to be populated directly from an SQL backend. Go also provides the ability for this same struct to be populated directly from JSON data. It’s a nice combination but has some gotchas to watch out for.
Recently I struck a problem where a column in my database that was NULL
was causing me some grief. I was unsure at first how to handle the database constraints while continuing to be able to unmarshall JSON the way I had been.
To illustrate, I have the following struct which maps to a table in my Postgresql database:
type User struct {
Id int `db:"id"`
Username string `db:"username"`
Passhash string `db:"passhash"`
Email string `db:"email"`
}
Database columns id
,username
andpasshash
are all defined as NOT NULL
however email
isn’t.
If I attempt to retrieve a record from the database, I see the following error:
err sql: Scan error on column index 3: unsupported driver -> Scan pair: <nil> -> *string
To rectify this I need to set Email
to type sql.NullString
. I can now retrieve data from the database without error. However if I attempt to unmarshall some JSON into this struct, I see this error:
json: cannot unmarshal string into Go value of type sql.NullString
What to do?
The answer is to wrap sql.NullString
inside a new type, then implement the json.Unmarshaler interface. You might think to try something like:
type NullString sql.NullString
type User struct {
Id int `db:"id"`
Username string `db:"username"`
Passhash string `db:"passhash"`
Email NullString `db:"email"`
}
func (s *NullString) UnmarshalJSON(data []byte) (error) {
s.String = strings.Trim(string(data),`"`)
s.Valid = true
return nil
}
However when I attempt to retrieve a record from the database I see a new error:
sql: Scan error on column index 3: unsupported driver -> Scan pair: []uint8 -> *db.NullString
The trick is to change the NullString
definition slightly like so:
type NullString struct {
sql.NullString
}
sql.NullString
is acting as an anonymous or embedded field.