entを試してみた
仕事で使いそうだったのでORマッパーのentを試してみた。 公式はこちら。
検証用のディレクトリ作成
mkdir test cd test go mod init test
検証用のDB(postgres)を作成
検証用のDBを作成する
touch docker-compose.yml
以下のようにDBを起動するだけの定義を作成する。
docker-compose.yml
version: "3.8" services: db: image: postgres:15.1-alpine ports: - 5432:5432 volumes: - ./.data/postgres:/var/lib/postgresql/data environment: POSTGRES_USER: user POSTGRES_PASSWORD: pass POSTGRES_DB: testdb
DBを起動する。
docker-compose up -d
ライブラリのインストール
entのインストール
go get -d [entgo.io/ent/cmd/ent](http://entgo.io/ent/cmd/ent)
postgresのドライバのインストール
go get github.com/lib/pq
スキーマを追加
以下のコマンドでUserスキーマの元になるファイルが生成することができる。
今回はuserテーブルを生成するので、Userを指定。
スキーマファイルはent配下に作成される。
ent new User
ent/schema/user.goなどが作成されている。
生成されたファイルを修正してスキーマを定義
ent/schema.user.goを以下のように修正し、userテーブルにnameとageの項目を追加する。
// Fields of the User. func (User) Fields() []ent.Field { return []ent.Field{ field.String("name").Default("unknown"), field.Int("age").Positive(), } }
定義したスキーマから各テーブル毎の実装を生成する
go generate ./ent
上記のコマンドでgenerate.goやuser_create.goなどの実装ファイルが生成される。
マイグレーション用のプログラムを実装
entはスキーマをマイグレーションする機能があるので、マイグレーション用の処理を記述
DB接続を取得する実装
db/db.go
package db import ( "fmt" "test/ent" ) func NewDBClient() *ent.Client { user := "user" password := "pass" port := "5432" host := "localhost" dbName := "testdb" url := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable", user, password, host, port, dbName) client, err := ent.Open("postgres", url) if err != nil { fmt.Printf("failed connecting to postgres: %v", err) } return client } func CloseDB(client *ent.Client) { err := client.Close() if err != nil { fmt.Printf("failed close to db: %v", err) } }
マイグレーション処理の実装
go runコマンドで実行する予定なので、packageをmainにしています。
migrate/migrate.go
package main import ( "context" "fmt" "test/db" "test/ent/migrate" _ "github.com/lib/pq" ) func main() { client := db.NewDBClient() ctx := context.Background() err := client.Schema.Create( ctx, migrate.WithDropIndex(true), migrate.WithDropColumn(true), ) if err != nil { fmt.Printf("failed creating schema resources: %v", err) } db.CloseDB(client) }
スキーママイグレーション実行
以下のようにしてマイグレーションプログラムを実行
go run migrate/migrate.go
実際にマイグレーションされたか確認する
マイグレーションを下のように確認
docker-compose exec db /bin/sh # psql -h localhost -U user -d testdb testdb=# \d users; Table "public.users" Column | Type | Collation | Nullable | Default --------+-------------------+-----------+----------+---------------------------------- id | bigint | | not null | generated by default as identity name | character varying | | not null | 'unknown'::character varying age | bigint | | not null | Indexes: "users_pkey" PRIMARY KEY, btree (id)
CRUD操作
下記のようなプログラムで基本的なCRUDを確認。
main.go
package main import ( "context" "fmt" "log" "test/db" "test/ent/user" _ "github.com/lib/pq" ) func main() { client := db.NewDBClient() ctx := context.Background() // 1件追加 usr, err := client.Debug().User. Create(). SetName("user1"). SetAge(33). Save(ctx) if err != nil { fmt.Printf("failed creating user: %v", err) return } // 1件更新 updatedUser, err := client.Debug().User.Update().Where(user.ID(usr.ID)).SetAge(29).Save(ctx) if err != nil { fmt.Printf("failed updating user: %v", err) return } log.Printf("user: %+v", updatedUser) // 名前がuser1のユーザーを取得 users, err := client.Debug().User.Query().Where(user.Name("user1")).All(ctx) if err != nil { fmt.Printf("failed getting users: %v", err) return } for _, usr := range users { fmt.Printf("user: %+v", usr) } // 1件削除 _, err = client.Debug().User.Delete().Where(user.Name("user1")).Exec(ctx) if err != nil { fmt.Printf("failed deleting user: %v", err) return } // DB接続を閉じる db.CloseDB(client) }
上記を実行するとログとして各処理で発行されるクエリを確認して意図したクエリが発行されたことが確認できる。 最後にデータを削除しているのでDB上にはデータは残らないことに注意。
>> go run main.go 2023/04/28 22:32:37 driver.Query: query=INSERT INTO "users" ("name", "age") VALUES ($1, $2) RETURNING "id" args=[user1 33] 2023/04/28 22:32:37 driver.Exec: query=UPDATE "users" SET "age" = $1 WHERE "users"."id" = $2 args=[29 1] 2023/04/28 22:32:37 user: 1 2023/04/28 22:32:37 driver.Query: query=SELECT "users"."id", "users"."name", "users"."age" FROM "users" WHERE "users"."name" = $1 args=[user1] user: User(id=1, name=user1, age=29)2023/04/28 22:32:37 driver.Exec: query=DELETE FROM "users" WHERE "users"."name" = $1 args=[user1]
次に
次の記事でテーブル同士を関連させて動作確認してみた。 https://miyazi888.hatenablog.com/entry/2023/05/07/221705