🐈
sqlboiler ~参照編まとめ~
sqlboilerの参照系のクエリ構築の記事になります。
ポイントとしてはクエリに利用するテーブル名やカラム名などはタイプセーフに扱いましょう。
タイプセーフにクエリを構築することで、テーブル構造が変わった際の変更忘れもコンパイルエラーを起こして、安全に開発することができます。
クエリ構築の概念
sqlboilerでのクエリ構築は主に、Query Mod Systemにより制御されます。
Query Mod SystemはStarterとFinisherによるクエリ構築を提供しています。
Starter
sqlboilerで生成されたmodelの複数名になります。(UsersやStaffsなど)
Finisher
StarterとWhereなどの取得条件の後にくる関数で、Finisherをセットすることで最終的なクエリ結果をsqlboilerのmodelで返します。
下記はusersテーブルから全てのデータをUsersmodelとして取得している例になります。
import (
"context"
qm "github.com/volatiletech/sqlboiler/v4/queries/qm"
"github.com/sqlboiler_sample/models" // sqlboilerのgenerateコマンドで作成されたmodel群
)
var err error
// contextのセット(以下省略)
ctx := context.Context()
// dbコネクションのセット(以下省略)
if dbConn, err = sql.Open("devdb", fmt.Sprintf("connection_%d", time.Now().UnixNano())); err != nil {
panic(err)
}
// Strat().Finisher();の形でクエリ結果をmodelの形で取得する
var users []*models.Users
if users, err = models.Users().All(ctx, db); err != nil {
fmt.Println(err.Error())
}
通常のクエリ
該当レコードを1つ取得
var err error
var user *models.User
if user, err = models.Users().One(ctx, db); err != nil {
fmt.Println(err.Error())
}
該当レコードを全て取得
var err error
var users models.UserSlice
if users, err = models.Users().All(ctx, db); err != nil {
fmt.Println(err.Error())
}
該当レコード数を取得
var err error
var usersCount int64
if usersCount, err = models.Users().Count(ctx, db); err != nil {
fmt.Println(err.Error())
}
該当レコードの存在有無を取得
var err error
var userExists bool
if userExists, err = models.Users().Exists(ctx, db); err != nil {
fmt.Println(err.Error())
}
複雑なクエリ
上記のような単純なクエリだけでなく、複雑なクエリが必要になることもあります。
通常のSQLと同じように、whereやgroup_by, limit, offsetなどSQLで使える基本的なものは
sqlboilerでも使えます。
var err error
var users models.UserSlice
if users, err = models.Users(
qm.Select("id", "name"),
qm.InnerJoin("credit_cards c on c.user_id = users.id"),
qm.Where("age > ?", 30),
qm.AndIn("c.kind in ?", "visa", "mastercard"),
qm.Or("email like ?", `%aol.com%`),
qm.GroupBy("id", "name"),
qm.Having("count(c.id) > ?", 2),
qm.Limit(5),
qm.Offset(6),
).All(ctx, db); err != nil {
fmt.Println(err.Error())
}
important! 【タイプセーフに使う】
上記処理をタイプセーフに書き換えるとこうなります。
var err error
var users models.UserSlice
if users, err = models.Users(
ID
qm.Select(UserColumns.ID, UserColumns.Name), // 「テーブル名Columns」のように、各テーブルのカラムがstructとして生成されます
InnerJoin(
fmt.Sprintf("%s on %s.%s = %s.%s", TableNames.CreditCards, TableNames.CreditCards CreditCardColumns.ID, TableNames.Users, UserColumns.ID),
),
qm.Where(fmt.Sprintf("%s > ?", UserColumns.Age), 30),
qm.AndIn(fmt.Sprintf("%s.%s in ?", CreditCardColumns.Kind), "visa", "mastercard"),
qm.Or(fmt.Sprintf("%s like ?", UserColumns.Email), `%aol.com%`),
qm.GroupBy(UserColumns.ID, UserColumns.Name),
qm.Having(fmt.Sprintf("count(%s) > ?", CreditCardColumns.ID), 2),
qm.Limit(5),
qm.Offset(6),
).All(ctx, db); err != nil {
fmt.Println(err.Error())
}
この記事に書いてあることができたら・・・
「Issue」のタスクをこなすことができます❗️
IssueではIssue単位で企業のお仕事ができるサービスです
Ex.
Firebaseでメールアドレス確認メール文章変更の実装
単価3,000円で受けて10時間ほどで実装した場合
3,000円 × 10時間 = 30,000円
Discussion