[golang]null許可DBカラムをjson変換する

# はじめ
最近golangを書き始めています。
JSONを返却するAPIを書いている時に、NULL許可カラムの扱いに困りました。

# そのAPIはどんなことやってたの？

- DBからデータ取得
- structにマッピング
- json変換してレスポンス返却

はい、きっとよくあるやつです。

# 何がどう困ったか

userテーブルでmiddle_nameカラムはNULL許可で、マッピングさせる structは、sample1のように定義しました。

```
id          `int`
first_name  `varchar(255)`
middle_name `varchar(255) DEFAULT NULL`
last_name   `varchar(255)`
```

``` sample1.go
type User struct {
	Id uint32 `json:"id"`
	FirstName string `json:"first_name"`
	MiddleName string `json:"middle_name"`
	LastName string `json:"last_name"`
}
```

すると、DBのMiddleNameカラムデータがNULLの時に、string型にマッピングできません。

# sql.NullString型にする

```sample2.go
type User struct {
	Id uint32 `json:"id"`
	FirstName string `json:"first_name"`
	MiddleName sql.NullString `json:"middle_name"`
	LastName string `json:"last_name"`
}
```

goのsqlパッケージにNullStringってのがあって、
DBのNULLデータをいい感じにstructにマッピングしてくれます。 やったぜ！

あとは、`json.Marshall`でjson変換するだけ♪

json変換した結果、sql.NullString型自体がjson化されていて、(´・ω・｀)ガッカリ。

``` unexpected.go
{
   "id" : 1,
   "first_name" : "Dennis",
   "middle_name" : { "String" : "", "Valid" : false }, 
   "last_name" : "Suratna"
}

```

``` expected.go
{
   "id" : 1,
   "first_name" : "Dennis",
   "middle_name" : null, 
   "last_name" : "Suratna"
}

```

# null値を変換してくれるライブラリーを使う

`gopkg.in/guregu/null.v3`
nullとzeroというパッケージがあるらしく、jsonのmarshalがかかると
null -> 0 or 空文字（"") に変換してくれるらしい。


sampleコード書いてみました。

``` sample.go
package main

import (
	null "gopkg.in/guregu/null.v3"
	zero "gopkg.in/guregu/null.v3/zero"
	"database/sql"
	"encoding/json"
	"fmt"
)

type DBUser struct {
	Id uint32 `json:"id"`
	FirstName string `json:"first_name"`
	MiddleName sql.NullString `json:"middle_name"`
	LastName string `json:"last_name"`
	Salary sql.NullInt64 `json:"salary"`
}

type JsonNullUser struct {
	Id uint32 `json:"id"`
	FirstName string `json:"first_name"`
	MiddleName null.String `json:"middle_name"`
	LastName string `json:"last_name"`
	Salary null.Int `json:"salary"`
}

type JsonZeroUser struct {
	Id uint32 `json:"id"`
	FirstName string `json:"first_name"`
	MiddleName zero.String `json:"middle_name"`
	LastName string `json:"last_name"`
	Salary zero.Int `json:"salary"`
}

func main() {

	// --- sql.nullString
	user1 := &DBUser {
		Id: 1,
		FirstName: "Min",
		LastName: "Oh",
	}
	user1Json, _ := json.Marshal(user1)
	fmt.Println(string(user1Json)) // (1)


	// --- null.String, null.Int
	user2 := &JsonNullUser{
		Id: 2,
		FirstName: "Mark",
		LastName: "Parker",
	}

	user2Json, _ := json.Marshal(user2)
	fmt.Println(string(user2Json)) // (2)
	

	user21 := &JsonNullUser{
		Id: 21,
		FirstName: "Mark",
		MiddleName: null.NewString("", true),
		LastName: "Parker",
		Salary: null.NewInt(0, true),
	}

	user21Json, _ := json.Marshal(user21)
	fmt.Println(string(user21Json)) // (3)

	user3 := &JsonNullUser{
		Id: 3,
		FirstName: "Jack",
		MiddleName: null.NewString("Junior", true),
		LastName: "Paul",
		Salary: null.NewInt(30, true),
	}

	user3Json, _ := json.Marshal(user3)
	fmt.Println(string(user3Json)) // (4)

	// --- zero.String, zeroInt
	user4 := &JsonZeroUser{
		Id: 4,
		FirstName: "Mark",
		LastName: "Parker",
	}
	user4Json, _ := json.Marshal(user4)
	fmt.Println(string(user4Json)) // (5)

	user41 := &JsonZeroUser{
		Id: 41,
		FirstName: "Mark",
		MiddleName: zero.NewString("", true),
		LastName: "Parker",
		Salary: zero.NewInt(0, true),
	}
	user41Json, _ := json.Marshal(user41)
	fmt.Println(string(user41Json)) // (6)

	user5 := &JsonZeroUser{
		Id: 5,
		FirstName: "Jack",
		MiddleName: zero.NewString("Junior", true),
		LastName: "Paul",
		Salary: zero.NewInt(30, true),
	}

	user5Json, _ := json.Marshal(user5)
	fmt.Println(string(user5Json)) //  (7)
```

実行結果

```
(1) {"id":1,"first_name":"Min","middle_name":{"String":"","Valid":false},"last_name":"Oh","salary":{"Int64":0,"Valid":false}}
(2) {"id":2,"first_name":"Mark","middle_name":null,"last_name":"Parker","salary":null}
(3) {"id":21,"first_name":"Mark","middle_name":"","last_name":"Parker","salary":0}
(4) {"id":3,"first_name":"Jack","middle_name":"Junior","last_name":"Paul","salary":30}
(5) {"id":4,"first_name":"Mark","middle_name":"","last_name":"Parker","salary":0}
(6) {"id":41,"first_name":"Mark","middle_name":"","last_name":"Parker","salary":0}
(7) {"id":5,"first_name":"Jack","middle_name":"Junior","last_name":"Paul","salary":30}
```

今回は、zeroパッケージは不要でnullパッケージだけで用が足りそうです。

# 参考
http://dennissuratna.com/marshalling-nullable-string-db-value-to-json-in-go/
http://qiita.com/guregu/items/726f34f80de4e9ba7539#guregunull