bobデータ取得チートシート
1. 全件取得(全レコード取得)
code:go
// ========== 全件取得(全レコード) ==========
// --- SQL ---
// master_booksの全行を取得
SELECT * FROM master_books;
// --- ActiveRecord ---
MasterBook.all
// --- Bob自動生成Go(推奨) ---
// 全件はsm不要で取得可能
dbmodels.MasterBooks.Query().All(ctx, db)
// --- sm使用例 ---
// 全件にsmは不要だが、記述は可能
dbmodels.MasterBooks.Query().All(ctx, db)
2. 1件取得(主キー / 先頭)
code:go
// ========== 1件取得(主キー検索) ==========
// --- SQL ---
SELECT * FROM master_books WHERE id=1;
// --- ActiveRecord ---
MasterBook.find(1)
// --- Bob自動生成Go(推奨) ---
// ✅ 訂正:FindMasterBookメソッドが生成されていれば使用可能
dbmodels.FindMasterBook(ctx, db, 1) // もし生成されていれば
// または
dbmodels.MasterBooks.Query(
dbmodels.SelectWhere.MasterBooks.ID.EQ(1),
).One(ctx, db)
// --- sm使用例 ---
// ✅ 訂正:psql.Rawでラップが必要
dbmodels.MasterBooks.Query(
sm.Where(psql.Raw("id = ?", 1)),
).One(ctx, db)
// ========== 1件取得(先頭) ==========
// --- SQL ---
SELECT * FROM master_books LIMIT 1;
// --- ActiveRecord ---
MasterBook.first
// --- Bob自動生成Go(推奨) ---
dbmodels.MasterBooks.Query().One(ctx, db)
// --- sm使用例 ---
dbmodels.MasterBooks.Query().One(ctx, db)
dbmodels.MasterBooks.Query(sm.Limit(1)).One(ctx, db)
3. 条件付き取得(WHERE, LIKE, AND, OR, NOT, 除外)
部分一致/AND/OR/NOT/除外検索などの条件式は、自動生成Where(SelectWhere...)でもsmでも両方対応可。
自動生成Whereは型安全&補完・typo防止。SQLに慣れていればsm.WhereでもOK。
code:go
// ========== 条件付き取得(部分一致) ==========
// --- SQL ---
SELECT * FROM master_books WHERE title ILIKE '%foo%';
// --- ActiveRecord ---
MasterBook.where("title ILIKE ?", "%foo%")
// --- Bob自動生成Go(推奨) ---
dbmodels.MasterBooks.Query(
dbmodels.SelectWhere.MasterBooks.Title.ILike("%foo%"),
).All(ctx, db)
// --- sm使用例 ---
dbmodels.MasterBooks.Query(
sm.Where("title ILIKE ?", "%foo%"),
).All(ctx, db)
// ========== 条件付き取得(AND条件) ==========
// --- SQL ---
SELECT * FROM master_books WHERE author_id=2 AND title ILIKE '%foo%';
// --- ActiveRecord ---
MasterBook.where(author_id: 2).where("title ...")
// --- Bob自動生成Go(推奨) ---
dbmodels.MasterBooks.Query(
dbmodels.SelectWhere.MasterBooks.AuthorID.EQ(2),
dbmodels.SelectWhere.MasterBooks.Title.ILike("%foo%"),
).All(ctx, db)
// --- sm使用例 ---
// ✅ 訂正:psql.Rawでラップ
dbmodels.MasterBooks.Query(
sm.Where(psql.Raw("title ILIKE ?", "%foo%")),
).All(ctx, db)
// ========== 条件付き取得(OR条件) ==========
// --- SQL ---
SELECT * FROM master_books WHERE title='abc' OR title='def';
// --- ActiveRecord ---
MasterBook.where(title: "abc","def")
// --- Bob自動生成Go ---
// ✅ 訂正:OrメソッドでOR条件を構築
// psql.Quoteはカラム名を作るためのもので、EQメソッドはbob.Expressionを期待しています。文字列"abc"は直接渡せません。
// 方法1: psql.Argを使う(推奨)
dbmodels.MasterBooks.Query(
sm.Where(
psql.Quote("master_books", "title").EQ(psql.Arg("abc")).Or(
psql.Quote("master_books", "title").EQ(psql.Arg("def")),
),
),
).All(ctx, m.dbClient.Get(ctx))
// 方法2: シンプルにpsql.Rawを使う(簡単)
dbmodels.MasterBooks.Query(
sm.Where(psql.Raw("title = ? OR title = ?", "abc", "def")),
).All(ctx, m.dbClient.Get(ctx))
// 方法3: Bob自動生成のSelectWhereを使う(最も型安全)
dbmodels.MasterBooks.Query(
sm.Where(psql.Raw("title = ? OR title = ?", "abc", "def")),
).All(ctx, m.dbClient.Get(ctx))
// 方法4: psql.Orを使う
dbmodels.MasterBooks.Query(
sm.Where(
psql.Or(
psql.Quote("master_books", "title").EQ(psql.Arg("abc")),
psql.Quote("master_books", "title").EQ(psql.Arg("def")),
),
),
).All(ctx, m.dbClient.Get(ctx))
// 方法5: INを使う(複数値の場合は効率的)
dbmodels.MasterBooks.Query(
dbmodels.SelectWhere.MasterBooks.Title.In("abc", "def"),
).All(ctx, m.dbClient.Get(ctx))
📚 psql.Quoteとpsql.Argの役割
- psql.Quote("table", "column") → カラム参照を作る(table.column)
- psql.Arg(value) → 値をExpressionに変換する
- psql.Raw(sql, args...) → 生SQLをExpressionに変換する
Bob ORMでOR条件を書く場合:
1. 単純なOR → psql.Raw("title = ? OR title = ?", "abc", "def")
2. 同じカラムの複数値 → .In("abc", "def") が最適
3. 複雑なOR → expr.Or() か psql.Or()
推奨は方法2(psql.Raw)か方法4(In)です! シンプルで読みやすいです。
// ========== 条件付き取得(NOT条件) ==========
// --- SQL ---
SELECT * FROM master_books WHERE NOT (author_id=2);
// --- ActiveRecord ---
MasterBook.where.not(author_id: 2)
// --- Bob自動生成Go ---
// 複合NOTは型安全APIに実装なし → sm必須
// --- sm使用例 ---
dbmodels.MasterBooks.Query(
sm.Where("NOT author_id=?", 2),
).All(ctx, db)
// ========== 条件付き取得(除外検索) ==========
// --- SQL ---
SELECT * FROM master_books WHERE author_id <> 2;
// --- ActiveRecord ---
MasterBook.where.not(author_id: 2)
// --- Bob自動生成Go ---
// ✅ 訂正:NEメソッドで否定
dbmodels.MasterBooks.Query(
dbmodels.SelectWhere.MasterBooks.AuthorID.NE(2),
).All(ctx, db)
// --- sm使用例 ---
dbmodels.MasterBooks.Query(
sm.Where(psql.Raw("NOT author_id = ?", 2)),
).All(ctx, db)
4. to-oneリレーション(master_books→author)(has one, belongs to, JOIN)
例:本(master_books)が著者(authors)1名を持つ
code:go
// ========== to-oneリレーション(JOIN検索) ==========
// --- SQL ---
SELECT * FROM master_books
JOIN authors ON authors.id=master_books.author_id
WHERE authors.name='村上春樹';
// --- ActiveRecord ---
MasterBook.joins(:author).where(authors: { name: "村上春樹" })
// --- Bob自動生成Go(JOINヘルパー) ---
// ✅ 訂正:InnerJoinのタイポ修正
dbmodels.MasterBooks.Query(
dbmodels.SelectJoins.MasterBooks.InnerJoin.Author,
dbmodels.SelectWhere.Authors.Name.EQ("村上春樹"),
).All(ctx, db)
// --- sm使用例 ---
// ✅ 訂正:sm.InnerJoinメソッドを使用
dbmodels.MasterBooks.Query(
sm.InnerJoin("authors").On(
psql.Raw("authors.id = master_books.author_id"),
),
sm.Where(psql.Raw("authors.name = ?", "村上春樹")),
).All(ctx, db)
// ========== to-oneリレーション(Preload) ==========
// --- SQL ---
-- 1. SELECT * FROM master_books;
-- 2. SELECT * FROM authors WHERE id IN (...);
// --- ActiveRecord ---
MasterBook.includes(:author).all
// --- Bob自動生成Go(推奨) ---
// ✅ 訂正:Preloadの正しい使い方(未確認、要検証)
books, _ := dbmodels.MasterBooks.Query(
dbmodels.Preload.MasterBook.Author(),
).All(ctx, db)
// books0.R.Author でアクセス
// ========== to-oneリレーション(個別Load) ==========
// --- SQL ---
SELECT * FROM master_books WHERE id=1;
SELECT * FROM authors WHERE id=...;
// --- ActiveRecord ---
mb = MasterBook.first
mb.author.name
// --- Bob自動生成Go ---
// ✅ 訂正:LoadメソッドがあるかBob ORMの生成コード確認が必要
book, _ := dbmodels.MasterBooks.Query(
dbmodels.SelectWhere.MasterBooks.ID.EQ(1),
).One(ctx, db)
// book.LoadAuthor(ctx, db) // もし生成されていれば
// fmt.Println(book.R.Author.Name)
5. to-manyリレーション(author→master_books)(has many, JOIN, preload)
例:著者(authors)が複数の本を持つ
code:go
// ========== to-manyリレーション(JOIN検索) ==========
// --- SQL ---
SELECT * FROM authors
JOIN master_books ON authors.id=master_books.author_id
WHERE authors.id=1;
// --- ActiveRecord ---
Author.joins(:master_books).where(id: 1)
// --- Bob自動生成Go(JOINヘルパー) ---
// ✅ 訂正:正しいJOIN構文
dbmodels.Authors.Query(
dbmodels.SelectJoins.Authors.InnerJoin.MasterBooks,
dbmodels.SelectWhere.Authors.ID.EQ(1),
).All(ctx, db)
// --- sm使用例 ---
dbmodels.Authors.Query(
sm.InnerJoin("master_books").On(
psql.Raw("authors.id = master_books.author_id"),
),
sm.Where(psql.Raw("authors.id = ?", 1)),
).All(ctx, db)
6. ソート(ORDER BY)(sm必須)
code:go
// ========== ORDER BY(降順) ==========
// --- SQL ---
SELECT * FROM master_books ORDER BY created_at DESC;
// --- ActiveRecord ---
MasterBook.order(created_at: :desc)
// --- Bob自動生成Go ---
// ✅ 訂正:OrderByメソッドが存在する
dbmodels.MasterBooks.Query(
sm.OrderBy("master_books.created_at").Desc(),
).All(ctx, db)
// --- sm使用例 ---
dbmodels.MasterBooks.Query(
sm.OrderBy("created_at DESC"),
).All(ctx, db)
7. LIMIT・OFFSET(ページング系)(sm必須)
code:go
// ========== LIMIT ==========
// --- SQL ---
SELECT * FROM master_books LIMIT 20;
// --- ActiveRecord ---
MasterBook.limit(20)
// --- sm使用例 ---
dbmodels.MasterBooks.Query(sm.Limit(20)).All(ctx, db)
// ========== LIMIT + OFFSET ==========
// --- SQL ---
SELECT * FROM master_books LIMIT 20 OFFSET 20;
// --- ActiveRecord ---
MasterBook.limit(20).offset(20)
// --- sm使用例 ---
dbmodels.MasterBooks.Query(
sm.Limit(20), sm.Offset(20),
).All(ctx, db)
8. カラム指定(SELECT)(sm必須)
code:go
// ========== カラム指定(特定列) ==========
// --- SQL ---
SELECT id, title FROM master_books;
// --- ActiveRecord ---
MasterBook.select(:id, :title)
// --- sm使用例 ---
dbmodels.MasterBooks.Query(
sm.Columns("id", "title"),
).All(ctx, db)
// ========== カラム指定(JOIN先列含む) ==========
// --- SQL ---
SELECT mb.*, a.name AS author_name
FROM master_books mb
JOIN authors a ON a.id=mb.author_id;
// --- ActiveRecord ---
MasterBook.joins(:author).select("master_books.*, authors.name as author_name")
// --- sm使用例 ---
dbmodels.MasterBooks.Query(
sm.InnerJoin("authors ON authors.id=master_books.author_id"),
sm.Columns("master_books.*", "authors.name AS author_name"),
).All(ctx, db)
9. 複数条件の組み合わせ
(※3と同様。AND/OR/NOT組み合わせ)
10. COUNT・集計
code:go
// --- SQL ---
SELECT COUNT(*) FROM master_books;
// --- ActiveRecord ---
MasterBook.count
// --- Bob自動生成Go(推奨) ---
// ✅ 訂正:Countメソッドの確認が必要
count, err := dbmodels.MasterBooks.Query().Count(ctx, db)
// --- sm使用例 ---
count, err := dbmodels.MasterBooks.Query(
sm.Where(psql.Raw("author_id = ?", 1)),
).Count(ctx, db)
11. exists(レコード存在有無チェック)
code:go
// --- SQL ---
SELECT EXISTS(SELECT 1 FROM master_books WHERE id=1);
// --- ActiveRecord ---
MasterBook.exists?(id: 1)
// --- Bob自動生成Go(推奨) ---
// ✅ 訂正:Existsメソッドの確認が必要
exists, err := dbmodels.MasterBooks.Query(
dbmodels.SelectWhere.MasterBooks.ID.EQ(1),
).Exists(ctx, db)
dbmodels.MasterBooks.Query(
sm.Where(psql.Raw("id=?", 1)),
).Exists(ctx, db)
12. サブリレーションのPreload(多段Preload)
code:go
// --- SQL ---
// 本→著者→著者の他の本(多段)
// --- ActiveRecord ---
MasterBook.includes(author: :master_books).all
// --- Bob自動生成Go(推奨) ---
dbmodels.MasterBooks.Query().Preload(
dbmodels.Preload.MasterBook.Author(
dbmodels.Preload.Author.MasterBooks(),
),
).All(ctx, db)
13. 個別リレーションのロード(LoadXXX)
code:go
// --- SQL ---
SELECT * FROM master_books WHERE id=1;
SELECT * FROM authors WHERE id=...;
// --- ActiveRecord ---
book = MasterBook.find(1)
book.author
// --- Bob自動生成Go(推奨) ---
book, _ := dbmodels.MasterBooks.Query(sm.Where("id=?",1)).One(ctx, db)
book.LoadAuthor(ctx, db)
author.LoadMasterBooks(ctx, db)
code:go
✅ LoadAuthorの正しい使い方
unc (m *masterBook) GetBookWithAuthor(ctx context.Context, id int64) (*model.MasterBook, error) {
// 1. まず本を取得
book, err := dbmodels.MasterBooks.Query(
dbmodels.SelectWhere.MasterBooks.ID.EQ(id),
).One(ctx, m.dbClient.Get(ctx))
if err != nil {
return nil, err
}
// 2. 著者情報をロード
err = book.LoadAuthor(ctx, m.dbClient.Get(ctx))
if err != nil {
return nil, err
}
// 3. book.R.Authorでアクセス可能になる
if book.R != nil && book.R.Author != nil {
fmt.Printf("Book: %s, Author: %s\n", book.Title, book.R.Author.Name)
}
return (*model.MasterBook)(book), nil
}
📚 LoadAuthorの仕組み
// LoadAuthorを呼ぶと...
book.LoadAuthor(ctx, exec)
// 内部で以下のようなSQLが実行される
// SELECT * FROM authors WHERE id = {book.AuthorID}
// 結果がbook.R.Authorに格納される
book.R.Author // ← ここでアクセス可能
💡 ポイント
1. m.dbClient.Get(ctx)を使う(db.Client{}ではない)
2. LoadAuthor後はbook.R.Authorでアクセス
3. SliceにもLoadAuthorメソッドがある(一括ロード)
4. nilチェックを忘れずに(book.R != nil && book.R.Author != nil)
📝 重要な訂正ポイント
1. sm.Whereは必ずpsql.Rawでラップ
2. JOINはsm.InnerJoin().On()を使用
3. SelectJoinsのタイポ修正(nnerJoin → InnerJoin)
4. NE(not equal)メソッドで不等号を表現
5. Preload/Loadメソッドは生成コードの確認が必要