sqlc 从 SQL 生成类型安全的代码
简介⌗
sqlc 是一款基于 Go 语言开发的开源代码生成器,基于 DDL 为 Go 项目生成 CURD 的代码。在开始之前,你需要编写 Schema 和 Query SQL。
如果你有现成的数据库,想要快速生成 Schema,则可以使用 atlas 来导出你的 Schema:
atlas schema inspect -u "mysql://root:pass@localhost:3306/example" --format '{{ sql . }}' > schema.sql
安装⌗
macOS 上的安装方式:
brew install sqlc
其他平台可以参考官方文档。
配置⌗
首先需要为项目创建 sqlc.yaml
:
version: "2"
sql:
- engine: "mysql"
queries: "query.sql"
schema: "schema.sql"
gen:
go:
out: "tutorial" # 生成代码的目录
package: "tutorial" # Go 中的包名,可以根据自己的需要自定义
文件后缀可以是
yaml
、yml
和json
。
定义 Schema⌗
创建 schema.sql
文件定义如下(或使用 atlas 导出现有数据库结构):
-- Create "users" table
CREATE TABLE `users` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
`password` varchar(255) NULL,
`created_at` timestamp NULL,
`updated_at` timestamp NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `users_email_unique` (`email`)
) CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
定义 Query⌗
创建 query.sql
文件,并定义相关逻辑的 DML:
-- name: GetUser :one
SELECT * FROM users
WHERE id = ? LIMIT 1;
-- name: ListUsers :many
SELECT * FROM users
ORDER BY id DESC;
-- name: CreateUser :execresult
INSERT INTO users (
name, email, password
) VALUES (
?, ?, ?
);
-- name: DeleteUser :exec
DELETE FROM users
WHERE id = ?;
注意这里面的
-- name: {NAME} :{}
用来声明方法名称和返回类型的。
生成代码⌗
sqlc generate
生成后目录结构如下:
.
├── query.sql
├── schema.sql
├── sqlc.yaml
└── tutorial
├── db.go
├── models.go
└── query.sql.go
2 directories, 6 files
db.go
文件中的内容:
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.26.0
package tutorial
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
文件中的代码如下:
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.26.0
package tutorial
import (
"database/sql"
)
type User struct {
ID uint64
Name string
Email string
Password sql.NullString
CreatedAt sql.NullTime
UpdatedAt sql.NullTime
}
query.sql.go
文件中代码如下:
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.26.0
// source: query.sql
package tutorial
import (
"context"
"database/sql"
)
const createUser = `-- name: CreateUser :execresult
INSERT INTO users (
name, email, password
) VALUES (
?, ?, ?
)
`
type CreateUserParams struct {
Name string
Email string
Password sql.NullString
}
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (sql.Result, error) {
return q.db.ExecContext(ctx, createUser, arg.Name, arg.Email, arg.Password)
}
const deleteUser = `-- name: DeleteUser :exec
DELETE FROM users
WHERE id = ?
`
func (q *Queries) DeleteUser(ctx context.Context, id uint64) error {
_, err := q.db.ExecContext(ctx, deleteUser, id)
return err
}
const getUser = `-- name: GetUser :one
SELECT id, name, email, password, created_at, updated_at FROM users
WHERE id = ? LIMIT 1
`
func (q *Queries) GetUser(ctx context.Context, id uint64) (User, error) {
row := q.db.QueryRowContext(ctx, getUser, id)
var i User
err := row.Scan(
&i.ID,
&i.Name,
&i.Email,
&i.Password,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const listUsers = `-- name: ListUsers :many
SELECT id, name, email, password, created_at, updated_at FROM users
ORDER BY id DESC
`
func (q *Queries) ListUsers(ctx context.Context) ([]User, error) {
rows, err := q.db.QueryContext(ctx, listUsers)
if err != nil {
return nil, err
}
defer rows.Close()
var items []User
for rows.Next() {
var i User
if err := rows.Scan(
&i.ID,
&i.Name,
&i.Email,
&i.Password,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
总结⌗
sqlc 目前只能支持 Go 项目的代码生成,也有提供 Kotlin、Python 和 TypeScript,但目前这些都处于 Beta 阶段。不过 sqlc 提供了其他语言插件的能力,可以预见的是,以后生态将会逐步完善。
另外 atlas 的工具也是一个比较好的 DDL 管理工具。
I hope this is helpful, Happy hacking…