✨
Goでsqlcを作成する
Goでsqlcを作成する
GoのORMの一つとしてsqclがあります。
sqlcではORM独自の書き方ではなく、生のSQLで書くことができます
設定ファイルや生成のコマンドまで基本的なことを書いていきます
基本的な話
sqlc.yaml の設定項目
設定項目 | 説明 |
---|---|
engine |
データベースエンジン(mysql、postgresql等)を指定 |
queries |
SQLクエリファイルの場所を指定 |
gen |
コード生成の設定を行う |
emit |
コード生成時の出力形式や動作を制御 |
emitオプションの詳細
生成内容 | 説明 |
---|---|
何を生成するか | JSONタグ、インターフェース、プリペアドステートメント等 |
どのような形式で生成するか | ポインタ型、パブリック関数、正確なテーブル名等 |
どのような動作にするか | 空スライス返却、DB引数付きメソッド等 |
version: "2"
sql:
- engine: "postgresql"
queries: "queries.sql"
schema: "../../db/migrations"
gen:
go:
package: "sqlc"
out: "gen"
sql_package: "database/sql"
emit_json_tags: true # JSONタグ生成
emit_prepared_queries: false # プリペアドステートメント生成(あんまりちゃんとわかってない)
emit_interface: false # インターフェース生成
emit_exact_table_names: false # テーブル名そのまま使用
emit_empty_slices: false # 空スライス返却
emit_exported_queries: false # publicメソッド生成
emit_result_struct_pointers: false # 結果構造体ポインタ返却
emit_params_struct_pointers: false # パラメータ構造体ポインタ受取
emit_methods_with_db_argument: false # DB引数付きメソッド生成
Get操作の実装
Get操作のクエリ定義
queries/notes.sql
にGet用のクエリを追加:
一応そのテーブルの全てのカラムを...みたいな表現もできます
しかしテーブル設計の部分を見ないと「*」が何かわからないのでちゃんと書いたほうがいいかもしれません
また-- name: GetNote :one
のGetNote
の部分は自動生成したときのメソッドになるので命名を気をつけなければなりません
-- name: GetNote :one
SELECT * FROM notes WHERE note_id = ?;
-- name: GetAllNotes :many
SELECT * FROM notes;
生成される構造体
type Note struct {
NoteID int32 `json:"note_id"`
Title sql.NullString `json:"title"`
Content sql.NullString `json:"content"`
CreatedAt sql.NullTime `json:"created_at"`
UpdatedAt sql.NullTime `json:"updated_at"`
}
生成されるGet操作コード
// 単一のノートを取得
func (q *Queries) GetNote(ctx context.Context, noteID int32) (Note, error) {
row := q.queryRow(ctx, q.getNoteStmt, getNote, noteID)
var i Note
err := row.Scan(
&i.NoteID,
&i.Title,
&i.Content,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
// テーブル全体を取得
func (q *Queries) GetAllNotes(ctx context.Context) ([]Note, error) {
rows, err := q.query(ctx, q.getAllNotesStmt, getAllNotes)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Note
for rows.Next() {
var i Note
if err := rows.Scan(
&i.NoteID,
&i.Title,
&i.Content,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
return items, nil
}
開発フロー
-
スキーマ変更
# マイグレーションファイルの作成・実行 migrate create -ext sql -dir migrations add_notes_table migrate -database "mysql://user:pass@tcp(localhost:3306)/dbname" -path migrations up
-
クエリ追加・修正
# queries/notes.sqlを編集後 sqlc generate
まとめ
今回は簡単なクエリに絞りましたが、多くの人がわかるSQLで書いた内容が自動生成でよしなにやってくれる点はかなりいいと思いました
生成する構造体のタグなども設定のboolで変更可能なので自由に決められる点などもありました
静的なクエリを生成するのであればかなり開発体験がいいですが、動的クエリの場合の書き方がまだそこまで網羅的にかけていないので色々触っていきます
Discussion