あいつの日誌β

働きながら旅しています。

MySQL で sql.NullString なあいつを JSON に Marshalling する

追記: c.Bind とかする時に type error が起きたりするので Unmarshal も追加

あらすじ

MySQL で nullable なカラムレコードを入れるために struct の定義をこうしたらレコードには null が入らずに空文字が入ってしまいます。 Something.Code には Unique 制約をつけたいので空文字ではなく Null を挿入したい。

type Something struct {
    ID int `json:"id"`
    Code string `json:"code"`
    Name string `json:"name"`
}

この問題自体は以下のように sql.NullString を使えば解決します。

type Something struct {
    ID int `json:"id"`
    Code sql.NullString `json:"code"`
    Name string `json:"name"`
}

s := Something{ID: 1, Code: sql.NullString{"", false}, Name: "something"}

なのですがこれを JSON にすると以下のようになるけどそうじゃないんだという場合にどうすればいいのかというお話です。

{
   "id" : 1,
   "code" : { "String" : "", "Valid" : false },
   "name" : "somethen"
}

結果

型を定義しました。

type NullString struct {
    sql.NullString
}

func (s *NullString) MarshalJSON() ([]byte, error) {
    if s.Valid {
        return json.Marshal(s.String)
    } else {
        return json.Marshal(nil)
    }
}

func (s *NullString) UnmarshalJSON(data []byte) error {
    var str string
    json.Unmarshal(data, &str)
    s.String = str 
    s.Valid = str != ""
    return nil 
}

func NewNullString(s string) NullString {
    return NullString{sql.NullString{s, s != ""}}
}

type Something struct {
    ID int `json:"id"`
    Code NullString `json:"code"`
    Name string `json:"name"`
}

s := Something{ID: 1, Code: NewNullString(""), Name: "something"}

めでたし。

{
   "id" : 1,
   "code" : null,
   "name" : "something"
}