🐈

sqlboiler ~参照編まとめ~

2021/06/21に公開

sqlboilerの参照系のクエリ構築の記事になります。

ポイントとしてはクエリに利用するテーブル名やカラム名などはタイプセーフに扱いましょう。
タイプセーフにクエリを構築することで、テーブル構造が変わった際の変更忘れもコンパイルエラーを起こして、安全に開発することができます。

クエリ構築の概念

sqlboilerでのクエリ構築は主に、Query Mod Systemにより制御されます。
Query Mod SystemはStarterFinisherによるクエリ構築を提供しています。

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