sqlc와 golang-migrate를 사용하여 PostgreSQL 처리

23685 단어 Gotech
Go Advent Calendar 2021째 보도다.

개시하다


sqlc는 SQL에서 Go 코드를 생성하는 프로그램 라이브러리입니다.일반적인 ORM은 대부분 코드를 통해 SQL을 생성하고, sqlc는 그것과 완전히 상반된 방법을 채택한 독특한 프로그램 라이브러리이다.
이 보도는 PostgreSQL을 처리하는 Go 응용 프로그램의 구축을 sqlc와 Golang-migrate를 사용합니다.
  • kyleconroy/sqlc: Generate type safe Go from SQL
  • golang-migrate/migrate: Database migrations. CLI and Golang library.
  • 디렉토리 구조


    .
    ├── db
    │   ├── db.go
    │   ├── migrations
    │   │   ├── 000001_create_users_table.down.sql
    │   │   └── 000001_create_users_table.up.sql
    │   ├── models.go
    │   ├── queries
    │   │   └── users.sql
    │   └── users.sql.go
    ├── generate.go
    └── sqlc.yaml
    

    db/migrations/*


    마이그레이션 파일을 구성합니다.
    이 파일들을 사용한 후 구글-migrate에서 이동합니다.
    000001_create_users_table.down.sql
    CREATE TABLE IF NOT EXISTS users (
    	id serial PRIMARY KEY,
    	username VARCHAR (50) UNIQUE NOT NULL,
    	password VARCHAR (50) NOT NULL,
    	email VARCHAR (300) UNIQUE NOT NULL
    );
    
    000001_create_users_table.up.sql
    DROP TABLE IF EXISTS users;
    

    db/queries/*


    질의 파일을 구성합니다.
    각자의 조회에서 주석으로 sqlc의 초대장을 기술합니다.
  • Query annotations — sqlc 1.11.0 documentation
  • user.sql
    -- name: GetUser :one
    SELECT * FROM users WHERE id = $1;
    
    -- name: ListUsers :many
    SELECT * FROM users ORDER BY id;
    
    -- name: CountUsers :one
    SELECT count(*) FROM users;
    
    -- name: CreateUser :exec
    INSERT INTO users (username, password, email) VALUES ($1, $2, $3);
    
    -- name: UpdateUser :exec
    UPDATE users SET username = $2, password = $3, email = $4 WHERE id = $1;
    
    -- name: DeleteUser :exec
    DELETE FROM users WHERE id = $1;
    
    INSERTUPDATE는 문장을 추가하여 조회 제출에 지정RETURNING하면 창설과 업데이트된 줄을 되돌려받을 수 있습니다.
    -- name: CreateUser :one
    INSERT INTO users (username, password, email) VALUES ($1, $2, $3) RETURNING *;
    
    -- name: UpdateUser :one
    UPDATE users SET username = $2, password = $3, email = $4 WHERE id = $1 RETURNING *;
    

    :one


    sqlc를 통해 생성하기 위해 설정 파일을 준비했습니다.
    version: "1"
    packages:
      - name: "db" # 生成されるパッケージ名
        path: "db" # 生成されるディレクトリ
        queries: "./db/queries/" # クエリファイルのあるディレクトリ
        schema: "./db/migrations/" # マイグレーションファイルのあるディレクトリ
        engine: "postgresql"
    

    sqlc.yaml

    generate.go에서 sqlc 기반 코드를 생성할 수 있습니다.sqlc generate 생성을 통해 아래 지시를 미리 삽입합니다.
    //go:generate go install github.com/kyleconroy/sqlc/cmd/sqlc@latest
    //go:generate sqlc generate
    
    이후 go generate만 진행하면 되며 설치 등에 신경 쓸 필요가 없다.
    $ go generate .
    

    go generate

    db/* 이후에는 3가지 파일이 생성됩니다.
  • sqlc generate
  • db/db.go
  • db/models.go
  • db/*.sql.go


    성명은 사무 인터페이스와 조회 방법의 구조를 정의하는 데 사용됩니다.
    // Code generated by sqlc. DO NOT EDIT.
    
    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,
    	}
    }
    

    db/db.go


    해당 테이블의 구조를 선언합니다.
    // Code generated by sqlc. DO NOT EDIT.
    
    package db
    
    import ()
    
    type User struct {
    	ID       int32
    	Username string
    	Password string
    	Email    string
    }
    
    또한 sqlc는 db/models.go도 지원한다.
    000002_alter_users_table.up.sql
    ALTER TABLE users ADD COLUMN address varchar(300) NOT NULL;
    
    위에서 말한 바와 같이 열을 추가하고 새로 생성할 때 구조에 대응하는 필드가 증가합니다.
    type User struct {
    	ID       int32
    	Username string
    	Password string
    	Email    string
    +	Address  string
    }
    

    ALTER TABLE


    각 질의에 대한 방법을 정의합니다.
    users.sql.go
    func (q *Queries) CountUsers(ctx context.Context) (int64, error)
    func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) error
    func (q *Queries) DeleteUser(ctx context.Context, id int32) error
    func (q *Queries) GetUser(ctx context.Context, id int32) (User, error)
    func (q *Queries) ListUsers(ctx context.Context) ([]User, error)
    func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) error
    

    응용 프로그램 코드


    여기까지는 준비가 다 되었으니 응용 프로그램 코드를 실제로 쓰겠습니다.
    qlc와golang-migrate는 각각 여러 가지 사용 방법이 있는데 이번에는 DB 실례를 이전과 조회에서 반복적으로 사용하기 위해db/*.sql.go 방법을 사용합니다.

    *sql.데이터베이스 가져오기


    *sql.DB에서 얻기sql.Open().드라이브는 pgx를 사용합니다.
  • jackc/pgx: PostgreSQL driver and toolkit for Go
  • import _ "github.com/jackc/pgx/v4/stdlib"
    
    db, err := sql.Open("pgx", dataSourceName)
    

    Golang-migrate를 사용하여 마이그레이션


    마이그레이션에 사용*sql.DB
    import (
    	"github.com/golang-migrate/migrate/v4"
    	"github.com/golang-migrate/migrate/v4/database/postgres"
    	_ "github.com/golang-migrate/migrate/v4/source/file"
    )
    
    // 1. *sql.DB を渡してドライバを作成
    driver, err := postgres.WithInstance(sqldb, &postgres.Config{}) // sqldb = *sql.DB
    
    // 2. 作成したドライバを元にマイグレーションインスタンスを取得
    m, err := migrate.NewWithDatabaseInstance(
    	"file://db/migrations", // マイグレーションファイルのあるディレクトリ
    	"postgres",
    	driver,
    )
    
    // 3. マイグレーションを適用
    err := m.Up()
    
    이렇게 응용 프로그램에 마이그레이션을 삽입하는 경우 실제적으로 여러 번 마이그레이션을 수행하는 것을 피해야 한다.

    sqlc로 생성된 코드 발행 조회


    sqlc로 생성된 *sql.DB 포장된 구조기에서 db의 실례를 얻었다.
    얻은 실례가 모든 조회 방법을 정의했기 때문에 발행 조회가 필요한 과정에서 순환적으로 사용할 수 있다.
    // *sql.DB を渡して *Queries のインスタンスを取得
    queries = db.New(sqldb) // sqldb = *sql.DB
    
    // *Queries のメソッドを使ってクエリを発行
    users, err := queries.ListUsers(ctx)
    

    끝말


    복잡한 SQL을 포함하는 응용 프로그램에서는 ORM의 각종 기능으로 이를 실현하는 것보다 sqlc를 사용하는 것이 편리하다.앞으로 적당한 프로젝트가 있다면 사용을 연구하고 싶습니다.

    좋은 웹페이지 즐겨찾기