ApexEloquent
「クエリ構築」と「クエリ実行」を分離する Apex 向けデータアクセス OSS。ドメインは Scribe でクエリの設計図を描き、IEloquent が実行を引き受けます。
Why ApexEloquent
クエリ構築と実行の分離Query Delegation Pattern
Salesforce 開発で広く採用される Selector Pattern は、クエリを共有でき、ビジネスロジックにクエリを書かずにメソッド経由でデータを取得できる利点があります。しかし長期運用では「ちょっと違うクエリが欲しい」たびにメソッドや変数を継ぎ足すパッチが繰り返され、徐々にそのシンプルさが失われていきます。さらに、テスト自体が DB を必要とする 結合テストしか書けない という制約も付いてまわります。
ApexEloquent は、Repository パターンを Apex のために再設計し、クエリの「構築」と「実行」を別々に行う Query Delegation Pattern を採用しました。ドメイン層は Scribe でクエリの設計図を描き、それを IEloquent.get(scribe) に渡すと、本番では Eloquent が SOQL を発行します。
テスト時は IEloquent を MockEloquent に DI で差し替えるだけで、DB を介さない単体テストが書けるようになる、長期の開発を妨げないフレームワークです。
ScribeIEloquentEloquent / MockEloquentCore Building Blocks
3 つのコア機能
Scribe
型付きでメソッドチェーンを積み上げる immutable なクエリビルダー。SELECT / WHERE / 並び替え / 集計 / GROUP BY / HAVING まで 1 つの API で組み立てます。各メソッドが新しい Scribe を返すので、同じ条件から件数取得用と一覧取得用のクエリを派生させるのも自然です。
IEloquent (Eloquent / MockEloquent)
Scribe を受け取って SOQL を実行するインターフェース。DML (insert / update / upsert / delete) も bulk のオーバーロード付きで統一的に扱えます。本番は Eloquent、テストは MockEloquent を Layered Constructor Pattern で DI 差し替え。
IEntry (Entry / MockEntry)
SObject と AggregateResult を同じ get(field) で扱える統一ラッパー。MockEntry は数式・ロールアップ・親リレーション・auto-number といった書き込み不可項目も自由に設定できます。
Why This Design
ApexEloquent の独自設計
非書き込みフィールド・親子・AggregateResult までモック可能
数式項目・ロールアップ・親リレーション・auto-number など、通常は書き込み不可な項目もモックでは自由に値を入れられます。親子の階層も、集計クエリの戻りも、同じ IEntry インターフェースで一貫してモックできます。
ORM 機能とモック機能の同時提供
多くの ORM ライブラリはクエリ構築までしか面倒を見ず、テスト時の DB レス化は別ライブラリや手作りモックの組み合わせが必要になります。ApexEloquent はクエリ構築から、ビルトインのモック機能で組まれた DB レスの高速な単体テストまでを、ノンストップで書き上げることができます。
MockEntry Deep Dive を読む →モック注入時の SELECT 漏れもテスト段階で検知
本物の SOQL で取得した SObject は、SELECT していないフィールドにアクセスすると即エラーになります。ところがテストで SObject を注入するパターンでは、未取得フィールドへのアクセスがスルーされて単体テストでは気付けず、結合テストや本番で初めて表面化します。ApexEloquent は Scribe の SELECT 句を覚えていて、モック注入の場合でも未取得フィールドへのアクセスを 単体テスト段階で例外として 叩き出します。
Spy + failOn でリトライ系もテスト
Spy プロパティで、レコードの作成・更新・削除が正しく行われたかを DB レスで検証可能です。さらに failOn メソッドでは、エラーを意図したタイミングで投げることができるので、プロダクションコードを汚さずに catch ブロックの検証ができます。
データ取得と DML、IEntry、Mock を読む →Deep Dives
設計の動機・独自機能を深掘りする
ApexEloquent がなぜこの形に至ったか、 他の OSS にない独自機能はどう効くかを、 5 つのドキュメントで掘り下げています。
Query Delegation Pattern
Selector Pattern の長期運用課題から出発し、クエリ構築 (Scribe) と実行 (IEloquent) を分離する設計哲学を整理します。
Apex における Repository パターンの試行錯誤と内蔵化
Apex で Repository を愚直に書いたときの問題、Salesforce 公式の Selector Pattern との関係、ApexEloquent が IEloquent として「内蔵 Repository」 を提供する理由。
Apex の生 SOQL から、チェーンメソッドで組み立てる ORM へ
生 SOQL 中心の Apex 開発で支払っている代償 (可読性 / 動的条件 / 型安全性 / リレーション / テスト) を、Scribe + IEloquent でどう軽くするかを実例ベースで解説する移行入門。
MockEntry: Apex のテストデータ作成を成立させる仕組み
書き込み不可項目 (数式 / ロールアップ / auto-number / リレーション名) と親子関係構築の困難という Apex のテスト 2 大課題を、MockEntry の override map / 専用ファクトリ / 集計結果モックでどう解決するか。
モックテストの偽陽性を検知する: SELECT 漏れの安全網
「テストでは通って本番で落ちる」 タイプの偽陽性問題を、ApexEloquent が Scribe との連携で構造的に塞いでいる仕組みを、主オブジェクト / 親リレーション / 子サブクエリ / 集計エイリアスの 4 ケースで実証。他 OSS にない ApexEloquent 独自の安全網。
Where It Sits in Apex Stem
Apex Stem における位置づけ
ApexEloquent は Apex Stem を構成する 4 つの OSS のうち、Data Access を担います。Handler-Usecase Architecture の Usecase 層で DB アクセスを伴う際に登場し、テスト戦略 の「Usecase 単体テスト ↔ ApexEloquent」の対応を担う中核です。
- Handler-Usecase Architecture: ApexEloquent が呼ばれる Usecase 層の責務
- Layered Constructor Pattern:
IEloquentを Usecase に DI する設計 - テスト戦略:
MockEloquentを中心に据えた Usecase 単体テスト - Apex Stem 導入ガイド: 動くコード付きの 4 ステップ
Start with the Developer Guide
開発者ガイドでは、Scribe でクエリを組み立てる、データを取得して DML を流す、リレーションを扱う、の 3 つの使い方を実際のコードで通します。API リファレンスも併せて参照できます。