DBいじるためのGoコードをスキーマから自動生成してくれるxoってツールを使ってみた

# はじめに
GoからDBをさわるためのxoってツールがある。いまいち、使い方がよくわかってなかったので、試してみた。

# xo
DBをさわるときに便利なコードを、スキーマから生成してくれるらしい。

[xo/xo: Command line tool to generate idiomatic Go code for SQL databases supporting PostgreSQL, MySQL, SQLite, Oracle, and Microsoft SQL Server](https://github.com/xo/xo)


> xo is a command-line tool to generate Go code based on a database schema or a custom query.

# 環境
このとき作った環境を使う

[Dockerを使ってPostgreSQL+Goの開発環境を作ってみた - Qiita](https://qiita.com/optimisuke/items/911cd8756bdbfeb4815a)

# インストール
READMEにしたがって実行した。

[xo/xo: Command line tool to generate idiomatic Go code for SQL databases supporting PostgreSQL, MySQL, SQLite, Oracle, and Microsoft SQL Server](https://github.com/xo/xo)

```
go get -u golang.org/x/tools/cmd/goimports
go get -u github.com/xo/xo
```

# ファイル生成
QuickstartにPostgreSQLのやりかた書かれてた。

`models`フォルダを作る前にやったら、フォルダがないとおこられた。

```
/go/src/work/xo# xo pgsql://root@db/db1 -o models
error: output path must be a directory and already exist when not writing to a single file
```

次は、sslが有効になってないとおこられた。PostgreSQL立ち上げるときの設定かな。disableにしといたらいいか。

```
/go/src/work# xo pgsql://root@db/root -o models
error: pq: SSL is not enabled on the server
```

これで、`models`フォルダにファイルを生成できた。

```
xo pgsql://root@db/root?sslmode=disable -o models
```

フォルダ構成は、こんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/7e251b89-3e0b-6279-d533-ab2192c6b40d.png)


# 使ってみる
生成されたコードを使ってみる。

まず、パッケージ名は生成先のフォルダ名になる。

```go
// Package models contains the types for schema 'public'.
package models
```

ここを参考にさせてもらった。
[DBから直接golangのモデルを生成するxoのご紹介 — そこはかとなく書くよん。](http://tdoc.info/blog/2016/07/06/xo.html)

パスは`$GOPATH`からのパスで指定したらいけた。ここらへん、よくわかってない。

```go

package main

import (
	"database/sql"
	"work/models"

	_ "github.com/lib/pq"
)

func main() {
	db, err := sql.Open("postgres", "host=db port=5432 user=root sslmode=disable")
	defer db.Close()
	if err != nil {
		panic(err)
	}

	e := &models.Employee{
		EmpNumber: sql.NullInt64{
			Int64: 4432,
			Valid: true,
		},
	}

	if err = e.Insert(db); err != nil {
		panic(err)
	}
}

```

実行してみる。

```
go run main.go
```

行けたっぽい。

# Posticoで確認
PosticoっていうGUIクライアントで確認した。
データ入ったみたい。
よかったよかった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/8f6b6c71-aa9b-4939-afd2-9a60461af0ff.png)

# 生成ファイルの中身
構造体が作られてる。`json`のタグもある。

```go
// Employee represents a row from 'public.employee'.
type Employee struct {
	EmpID     int           `json:"emp_id"`     // emp_id
	EmpNumber sql.NullInt64 `json:"emp_number"` // emp_number

	// xo fields
	_exists, _deleted bool
}
```

`Insert()`の中身はSQLでクエリが書かれてるだけ。

```go
// Insert inserts the Employee to the database.
func (e *Employee) Insert(db XODB) error {
	var err error

	// if already exist, bail
	if e._exists {
		return errors.New("insert failed: already exists")
	}

	// sql insert query, primary key provided by sequence
	const sqlstr = `INSERT INTO public.employee (` +
		`emp_number` +
		`) VALUES (` +
		`$1` +
		`) RETURNING emp_id`

	// run query
	XOLog(sqlstr, e.EmpNumber)
	err = db.QueryRow(sqlstr, e.EmpNumber).Scan(&e.EmpID)
	if err != nil {
		return err
	}

	// set existence
	e._exists = true

	return nil
}
```

# おわりに
雰囲気わかった。思ったよりシンプルやった。
`go mod`とか`error`とか`gomock`がよくわかってないので、そっちももうちょい試してみたい。`sqlx`ってのも。