sqlc とは
SQLクエリから型安全なGoのコードを生成するツールです。
これにより、SQLクエリとアプリケーションコード間の不整合を減らし、データベース操作の安全性と効率を向上させることができます。
sqlc generate とは
sqlc の主要な機能の一つで、事前に定義されたSQLクエリからGoのコードを生成します。
sqlc generate コマンドの実行例
ディレクトリ構成&コード
$ tree
.
├── db
│ ├── db.go ← sqlc generateコマンドで生成されたファイル
│ ├── models.go ← sqlc generateコマンドで生成されたファイル
│ ├── create_user.sql.go ← sqlc generateコマンドで生成されたファイル
│ ├── migration
│ │ └── 001_create_users_table.up.sql
│ └── sql
│ └── create_user.sql
├── go.mod
├── go.sum
├── main.go
├── sqlc.yaml
001_create_users_table.up.sql
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
create_user.sql
-- name: CreateUser :exec
INSERT INTO users (email, password_hash) VALUES ($1, $2);
sqlc.yml
version: "1"
packages:
- name: "db"
path: "./db"
queries: "./db/sql"
schema: "./db/migration"
engine: "postgresql"
sqlc generate コマンド 実行
sqlc.ymlファイル配下で、sqlc generate コマンドを実行すると、db.go
models.go
create_user.sql.go
が生成されます。
db.go
- 目的:データベース操作を行うための基本的な機能を提供する。
- 利用方法:データベースへの接続やクエリの実行に利用します。
db.go
package db
import (
"context"
"database/sql"
)
type DBTX interface {
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
return &Queries{
db: tx,
}
}
models.go
- 目的:データベースのテーブル構造をGoの構造体として表現する。
- 利用方法:データベースから取得したデータをGoのオブジェクトとして扱うために使用します。
models.go
package db
import (
"database/sql"
)
type User struct {
ID int32
Email string
PasswordHash string
CreatedAt sql.NullTime
UpdatedAt sql.NullTime
}
create_user.sql.go
- 目的:特定のSQLクエリを実行するための関数を提供する。
- 利用方法:このファイルに含まれる関数を呼び出して、データベースにユーザーを作成するなどの具体的な操作を行います。
create_user.sql.go
package db
import (
"context"
)
const createUser = `-- name: CreateUser :exec
INSERT INTO users (email, password_hash) VALUES ($1, $2)
`
type CreateUserParams struct {
Email string
PasswordHash string
}
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) error {
_, err := q.db.ExecContext(ctx, createUser, arg.Email, arg.PasswordHash)
return err
}
使用例
db.goファイル(db.New)の関数を呼び出してオブジェクトを作成し、create_user.sql.goファイル(dbQueries.CreateUser)の関数で特定のSQLクエリが実行される。
main.go
// ~~省略~~
// db.Queriesオブジェクトを作成
dbQueries := db.New(conn)
// ユーザーを作成
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
err = dbQueries.CreateUser(context.Background(), db.CreateUserParams{
Email: email,
PasswordHash: string(hashedPassword),
})
// ~~省略~~
まとめ
- db.go はデータベース接続と一般的な操作を管理するために使用されます。
- models.go はデータベースのテーブル構造をGoの構造体で表現するために使用されます。
- create_user.sql.go は特定のSQLクエリ(この場合はユーザー作成)を実行するための関数を提供します。