likes
comments
collection
share

sqlc 加 golang-migrate 使用记录

作者站长头像
站长
· 阅读数 24

demo repo

sqlc

这个库的核心思想就是把 sql 代码转为 Go 代码。

使用流程

因此我使用这个库的流程大概为:

  1. 写好要用的 sql 代码
  2. 运行 sqlc generate
  3. 使用自动生成的增删改成函数。

代码如下(Getting started with SQLite):


ctx := context.Background()

db, err := sql.Open("sqlite3", "changeme.db")
if err != nil {
        return err
}

// create tables
if _, err := db.ExecContext(ctx, ddl); err != nil {
        return err
}

queries := tutorial.New(db)

坑:部分更新

这里面我遇到一个坑,那就是更新函数的参数如果没有被填满(比如需要传 name 和 bio,但你只传了 name),那么没有传参的字段就会自动归零(bio 变成空字符串)。

解决办法是在 sql 里这样写:

-- name: UpdateAuthor :one
UPDATE authors
set
  name = coalesce(@name, name),
  bio = coalesce(@bio, bio)
WHERE id = ?
RETURNING *;

但这样写有另一个问题,那就是无法把字段设置为 null。目前我不知道怎么解决。

坑:nullString v.s. *string

如果数据库字段的类型为 string,而且可以为空,那么 sqlc 默认会在 Go 中用 sql.NullString 表示其类型,结构如下:

type NullString struct {
	String string
	Valid  bool // Valid is true if String is not NULL
}

这个类型很难用,因为其输出的 JSON 字符串中也会有 String 和 Valid 字段。

解决办法是在 sqlc.yaml 里添加如下配置(请主要看 sql.gen.go.overrides 部分):

version: 2
sql:
  - engine: "sqlite"
    schema:
      - "db/schema.sql"
      - "db/migrations/"
    queries:
      - "db/queries"
    gen:
      go:
        package: "main"
        out: "."
        emit_json_tags: true
        overrides:
          - db_type: "text"
            go_type:
              type: "string"
              pointer: true
            nullable: true
          - db_type: "INTEGER"
            go_type:
              type: "int64"
              pointer: true
            nullable: true
          - db_type: "DATE"
            go_type:
              import: "time"
              type: "Time"
              pointer: true
            nullable: true
          - db_type: "DATETIME"
            go_type:
              import: "time"
              type: "Time"
              pointer: true
            nullable: true
          - db_type: "TIMESTAMP"
            go_type:
              import: "time"
              type: "Time"
              pointer: true
            nullable: true

这样一来,如果数据库字段的类型为 string,而且可以为空,那么在 Go 中对应的类型就是 *string 了,比 sql.NullString 好用!

golang-migrate/migate

这个库是用来做数据库迁移的,因为 sqlc 并没有提供此类功能,所以需要安装这个库。

大概用法如下:

go install -tags '<sqlite3_此处请根据需求修改>' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
migrate create -dir .\migrations\ -ext sql <migration1_这里可以改成任意名字>
migrate -path ./migrations -database sqlite3:///D:\\Fang\\repos\\sqlc-tutorial-1\\xxx.db up

用起来还行。