SQLBoiler とは
タイトル通り、Go言語のORMです。とりあえず一次ソース貼っておくので一緒に見ましょう。一次ソースです
GoのORMはGORMしか使用経験がありませんが、サクッと自分の思ったことをまとめました。
SQLBoilerを使用したソースコードはこちら。
特徴
- DBを作成してマンドを打つと構造体を自動で生成してくれて、InsertやQueryなどができるようになる
- (メリット)他のORMよりパフォーマンスが良い(README参照)
- (メリット)Goのstructとしても活用しやすい
- (デメリット)ソースが少ない
実装手順
- DB作成
- DB接続
- 導入
- tomlファイル作成
- SQL文記述
- データのやりとり
開発環境
Mac OS Catalina 10.15.5
Go 1.14
MySQL 8.0.19
1.DB作成
(この記事にたどり着くような人は1と2は見なくてもサクッとできそうですが、、わかるわ。と思ったら手順3まで飛ばしてください。)
今回はMySQLを使用します。
をしてください。この手順にある処理はググったらいっぱい出てくると思うので詳しくは書きません。mysqlに入っていろいろするだけです。僕は結構優しいのでリンクは一応貼ってます。
権限付与はデータベースレベルで
grant all on DB名.* to 'ユーザー名' with grant option;
とかでいけると思います。
2. DB接続
次に、DBに接続します。
func New() *sql.DB {
db, err := sql.Open("mysql", "ユーザー名:パスワード@/DB名?charset=utf8mb4&parseTime=true")
if err != nil {
panic(err)
}
return db
}
3.導入
go get -u github.com/volatiletech/sqlboiler
go get github.com/volatiletech/sqlboiler/drivers/sqlboiler-mysql
4.tomlファイル作成
ルートディレクトリにtomlファイルを作ります。
touch sqlboiler.toml
必要事項を記述します。
- pkgname...作成したいパッケージ名を指定
- output...ルートディレクトリから見て、ファイルを生成したいディレクトリの場所
- dbname, user, pass ...DB名、ユーザー名、パスワード
- [mysql]は使用しているデータベースの種類を指定しています
pkgname="entity"
output="domain/entity"
[mysql]
dbname = "exampledb"
host = "localhost"
port = 3306
user = "root"
pass = "password"
sslmode= "false"
5.SQL文記述
SQLの文法をもとに下のようなファイルを作成しました。記事も後半になって僕が優しくなくなってきたので解説はしません。
関係は user:review が1:多で、CONSTRAINT..の部分で外部キー接続もしています。
CREATE TABLE `users` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
`deleted_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `reviews` (
`id` bigint NOT NULL AUTO_INCREMENT,
`text` text NOT NULL,
`user_id` bigint NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
`deleted_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `user_reviews_fk` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ユーザー名、パスワード、DB名を入れてスキーマを作成し、
$ mysqldef -uroot -ppassword exampledb < schema.sql
実行します。
$ sqlboiler mysql
上記2つのコマンドはSQLに変更を加えるときに使うので、Makefileとかのタスクランナー で自動化しておくと良いと思います。
自分の指定したディレクトリ以下に大量のファイルが生成されたら成功です。自分の作成したテーブルのファイルを見てるとこんなんがあると思います。
// 省略
type User struct {
ID int64 `boil:"id" json:"id" toml:"id" yaml:"id"`
Name string `boil:"name" json:"name" toml:"name" yaml:"name"`
CreatedAt time.Time `boil:"created_at" json:"created_at" toml:"created_at" yaml:"created_at"`
UpdatedAt time.Time `boil:"updated_at" json:"updated_at" toml:"updated_at" yaml:"updated_at"`
DeletedAt null.Time `boil:"deleted_at" json:"deleted_at,omitempty" toml:"deleted_at" yaml:"deleted_at,omitempty"`
R *userR `boil:"-" json:"-" toml:"-" yaml:"-"`
L userL `boil:"-" json:"-" toml:"-" yaml:"-"`
}
// 省略
6. データのやり取り
ファイルの生成ができたら、いよいよデータのやりとりを行います。
INSERTもできますが今回はSELECTを扱います。事前にデータを入れているReviewsテーブルの(削除されていない)id=1のデータを取ってきます。
(ルーティングの記述は省略しています。)
func handler(w http.ResponseWriter, r *http.Request) {
conn := db.New()
ctx := r.Context()
var id int64 = 1
review, err := entity.Reviews(
// entityパッケージのReviewsテーブルからIDカラムを条件にidと等しいデータをSELECT
entity.ReviewWhere.ID.EQ(id),
entity.ReviewWhere.DeletedAt.IsNull(),
).One(ctx, conn)
if err != nil {
fmt.println(err)
return
}
fmt.Println("----------review----------")
fmt.Println(review)
return
}
詳しい文法については一次ソースを参照してもらえるとわかるのではないかと思います。(上の例はQueryBuildingあたりに書いてる)
あとは実行すると、Reviewがprintされるはずです。
$ go run main go
手順としては終了ですが、最後に外部キーの例だけ載せておきます。
上記例でDBで外部キーで紐づけている前提で、
review, err := entity.Reviews(
entity.ReviewWhere.ID.EQ(id),
entity.ReviewWhere.DeletedAt.IsNull(),
qm.Load("User")
).One(ctx, conn)
fmt.Println(review.R.User)
とすると、UsersテーブルのUserをEagerLoadingで取ってくることができます。(has_manyの関係なら複数形にする)
以上になります。
間違い誤字脱字等あればご指摘いただけると幸いです🙇♂️