litedbmodel 2.2.2 → 2.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +2 -1
  2. package/dist/DBModel.d.ts.map +1 -1
  3. package/dist/DBModel.js +3 -0
  4. package/dist/DBModel.js.map +1 -1
  5. package/dist/Middleware.d.ts +19 -2
  6. package/dist/Middleware.d.ts.map +1 -1
  7. package/dist/Middleware.js +1 -0
  8. package/dist/Middleware.js.map +1 -1
  9. package/dist/decorators.d.ts.map +1 -1
  10. package/dist/decorators.js +8 -0
  11. package/dist/decorators.js.map +1 -1
  12. package/dist/drivers/MysqlHelper.d.ts +1 -1
  13. package/dist/drivers/MysqlHelper.d.ts.map +1 -1
  14. package/dist/drivers/MysqlHelper.js.map +1 -1
  15. package/dist/drivers/PostgresHelper.d.ts +1 -1
  16. package/dist/drivers/PostgresHelper.d.ts.map +1 -1
  17. package/dist/drivers/PostgresHelper.js.map +1 -1
  18. package/dist/drivers/SqliteHelper.d.ts +1 -1
  19. package/dist/drivers/SqliteHelper.d.ts.map +1 -1
  20. package/dist/drivers/SqliteHelper.js.map +1 -1
  21. package/dist/index.cjs +99 -33
  22. package/dist/scp/connection-routing.d.ts +38 -1
  23. package/dist/scp/connection-routing.d.ts.map +1 -1
  24. package/dist/scp/connection-routing.js +64 -5
  25. package/dist/scp/connection-routing.js.map +1 -1
  26. package/dist/scp/dbmodel-runtime.d.ts +2 -1
  27. package/dist/scp/dbmodel-runtime.d.ts.map +1 -1
  28. package/dist/scp/dbmodel-runtime.js +2 -1
  29. package/dist/scp/dbmodel-runtime.js.map +1 -1
  30. package/dist/scp/decorator-adapter.d.ts +22 -0
  31. package/dist/scp/decorator-adapter.d.ts.map +1 -1
  32. package/dist/scp/decorator-adapter.js +26 -0
  33. package/dist/scp/decorator-adapter.js.map +1 -1
  34. package/dist/scp/emit/emitter.d.ts +21 -10
  35. package/dist/scp/emit/emitter.d.ts.map +1 -1
  36. package/dist/scp/emit/emitter.js +119 -51
  37. package/dist/scp/emit/emitter.js.map +1 -1
  38. package/dist/scp/emit/endpoint.d.ts +3 -8
  39. package/dist/scp/emit/endpoint.d.ts.map +1 -1
  40. package/dist/scp/exec-context.d.ts +39 -17
  41. package/dist/scp/exec-context.d.ts.map +1 -1
  42. package/dist/scp/exec-context.js +69 -35
  43. package/dist/scp/exec-context.js.map +1 -1
  44. package/dist/scp/grouping.d.ts.map +1 -1
  45. package/dist/scp/grouping.js +0 -0
  46. package/dist/scp/grouping.js.map +1 -1
  47. package/dist/scp/index.cjs +251 -629
  48. package/dist/scp/index.d.ts +6 -11
  49. package/dist/scp/index.d.ts.map +1 -1
  50. package/dist/scp/index.js +10 -28
  51. package/dist/scp/index.js.map +1 -1
  52. package/dist/scp/index.mjs +251 -617
  53. package/dist/scp/leaf-transport.d.ts +127 -39
  54. package/dist/scp/leaf-transport.d.ts.map +1 -1
  55. package/dist/scp/leaf-transport.js +30 -24
  56. package/dist/scp/leaf-transport.js.map +1 -1
  57. package/dist/scp/leaves.d.ts +57 -20
  58. package/dist/scp/leaves.d.ts.map +1 -1
  59. package/dist/scp/leaves.js +224 -65
  60. package/dist/scp/leaves.js.map +1 -1
  61. package/dist/scp/makesql/compile-select.d.ts +28 -1
  62. package/dist/scp/makesql/compile-select.d.ts.map +1 -1
  63. package/dist/scp/makesql/compile-select.js +19 -17
  64. package/dist/scp/makesql/compile-select.js.map +1 -1
  65. package/dist/scp/makesql/index.d.ts +2 -2
  66. package/dist/scp/makesql/index.d.ts.map +1 -1
  67. package/dist/scp/makesql/index.js +4 -6
  68. package/dist/scp/makesql/index.js.map +1 -1
  69. package/dist/scp/makesql/tx.d.ts +27 -69
  70. package/dist/scp/makesql/tx.d.ts.map +1 -1
  71. package/dist/scp/makesql/tx.js +26 -448
  72. package/dist/scp/makesql/tx.js.map +1 -1
  73. package/dist/scp/middleware.d.ts +4 -4
  74. package/dist/scp/middleware.d.ts.map +1 -1
  75. package/dist/scp/middleware.js +2 -2
  76. package/dist/scp/middleware.js.map +1 -1
  77. package/dist/scp/relation.d.ts +31 -12
  78. package/dist/scp/relation.d.ts.map +1 -1
  79. package/dist/scp/relation.js +16 -6
  80. package/dist/scp/relation.js.map +1 -1
  81. package/dist/scp/typed-object.d.ts +23 -19
  82. package/dist/scp/typed-object.d.ts.map +1 -1
  83. package/dist/scp/typed-object.js +24 -30
  84. package/dist/scp/typed-object.js.map +1 -1
  85. package/dist/scp/write-bundle.d.ts +21 -70
  86. package/dist/scp/write-bundle.d.ts.map +1 -1
  87. package/dist/scp/write-bundle.js +15 -79
  88. package/dist/scp/write-bundle.js.map +1 -1
  89. package/dist/types.d.ts +12 -0
  90. package/dist/types.d.ts.map +1 -1
  91. package/dist/types.js.map +1 -1
  92. package/docs/architecture.md +452 -0
  93. package/docs/design/phase-a-execution-context.md +2 -0
  94. package/package.json +14 -3
  95. package/dist/scp/writes.d.ts +0 -251
  96. package/dist/scp/writes.d.ts.map +0 -1
  97. package/dist/scp/writes.js +0 -176
  98. package/dist/scp/writes.js.map +0 -1
  99. package/docs/proposal/contracts-architecture-feasibility.md +0 -328
  100. package/docs/proposal/contracts-architecture.md +0 -579
  101. package/docs/proposal/litedbmodel-v2-scp-architecture.md +0 -433
  102. package/docs/proposal/sql-dynamic-expansion-spec.md +0 -175
  103. package/docs/proposal/v0-coverage-matrix.md +0 -157
  104. package/docs/proposal/v2-completeness-plan.md +0 -90
  105. package/docs/proposal/v2-sql-parity-checklist.md +0 -162
@@ -1,328 +0,0 @@
1
- # SQL Contracts Architecture — フィージビリティ分析(訂正第2版)
2
-
3
- `contracts-architecture.md` の提案に対する実現可能性の調査・分析。
4
- 既存の兄弟プロジェクト(graphddb / dsl-contracts / litedbmodel.rs / litedbmodel-gen)と
5
- 現行 litedbmodel(ts) の実装を突き合わせて評価した。SCP(Semantic Contract Programming,
6
- [dsl-contracts/semantic-contract-programming.md](../../../dsl-contracts/semantic-contract-programming.md))を上位の配線層とする。
7
-
8
- > **訂正履歴**
9
- > - 初版: 「ORM API 非公開=litedbmodel の公開 API 廃止」と誤読 →「公開IF反転で互換不能」と誤結論。
10
- > - 訂正第1版: litedbmodel は CQRS 内側の振る舞い記述基盤と訂正。ただし「eager と capture の
11
- > 二重意味論ゆえ別ライブラリ必須」「Dialect 非依存 SQL IR が最難関」「LazyLoading は IR と両立不能」
12
- > と判断していた。
13
- > - **訂正第2版(本版): 上記3判断をすべて訂正。**
14
- > ① graphddb 自身が TS では eager 利用(呼び出し時に動的コンパイル→同一 IR/plan 経路で実行)であり、
15
- > 「二重意味論」は存在しない。in-place 進化は成立する。
16
- > ② IR は **Dialect 依存(dialect SQL + param バインディング + wire オペレーション)**が正。
17
- > 原提案の「Runtime は SQL を生成しない / Static Flatten」に立ち返る。
18
- > ③ LazyLoading は「事前コンパイル済み relation IR の実行時起動」として **IR 化可能**。
19
- > graphddb の `options.hydrate` と整合させる。
20
-
21
- ---
22
-
23
- ## 結論(TL;DR)
24
-
25
- 1. **アーキテクチャは実現可能。当初想定よりさらに低リスク。**
26
- 骨格(Contract → Planner → IR → 多言語 thin Runtime → Conformance)は graphddb が本番実装済み。
27
- IR を dialect 解決済みにすることで、残っていた最難関(Dialect 非依存 SQL IR の設計)も消滅する。
28
-
29
- 2. **単一意味論に統合できる: 「宣言 → IR → Runtime」が唯一の実行経路。**
30
- TS では呼び出し時に動的コンパイル(eager UX、キャッシュ可)、多言語へは同じコンパイル経路の
31
- AOT 出力(bundle)。graphddb と同じ構図。**eager/capture の対立は存在しない**。
32
- 対立軸は「引数が宣言データか、制御フローcoded かつホスト言語埋め込みか」だけ。
33
-
34
- 3. **litedbmodel の in-place 進化(メジャーバージョン)が既定路線として成立する。**
35
- condition タプル・Values・SKIP は既に宣言データであり、`find()` の内部を
36
- 「文字列即ビルド」→「IR コンパイル→runtime 実行」に差し替えられる。
37
- `await user.posts` も残せる(§9)。別プロダクト切り直しは意味論の要請ではなく、
38
- **API 破壊量が既存ユーザに対して大きすぎる場合の製品判断**(その場合もコア資産は移転)。
39
-
40
- 4. **LazyLoading は typed-object でも成立する(prototype + 事前コンパイル済み relation IR)。**
41
- 不変条件は「Runtime は SQL を生成しない」であり、「Runtime は実行タイミングを決めない」ではない。
42
-
43
- 5. **残る本質的な制約は1つ: ホスト TS に埋め込まれた命令的な *オペレーション間配線* は移植できない。**
44
- 多言語へ持ち出す配線は SCP(Wire/DAG)で宣言する。自由 TS から呼ぶか SCP で配線するかは
45
- プロジェクト方針(両者は同じ IR+Runtime を使うため、自由 TS → SCP への昇格はリファクタで済む)。
46
-
47
- ---
48
-
49
- ## 1. 位置づけ(前提の確認)
50
-
51
- ```
52
- 外部境界 = CQRS Contract(Query / Command)
53
- └ 振る舞いの記述 = litedbmodel API(find/create/update, conditions, SKIP, relations)
54
- ↓ コンパイル(TS 内で動的 or AOT)
55
- IR = dialect SQL + param binding + wire ops + assembly + relation ops(§5)
56
- ↓
57
- thin Runtime(TS / Go / Rust / Python / PHP): validate → slot 評価 → bind → execute → assemble
58
- ```
59
-
60
- - litedbmodel は CQRS の**内側**で Command/Query の振る舞いを書くオーサリング基盤(廃止しない)。
61
- - SCP 準拠で書かれたロジック(宣言的引数 + SCP 配線)は IR 化されるので多言語へ移行可能。
62
- - 通常の開発では litedbmodel の利用を SCP 内部に閉じるよう記述する。外の自由 TS から直接呼ぶことも
63
- でき(eager UX)、その場合も同じ IR+Runtime 経路を通る — ただし配線がホスト TS に残るため
64
- その部分は TS 専用。
65
-
66
- ---
67
-
68
- ## 2. 単一意味論: eager UX と IR コンパイルの統合(訂正)
69
-
70
- **訂正第1版の誤り:** 「eager と capture の二重意味論の同居は保守コスト高 → 別層で切るべき」。
71
-
72
- **事実:** graphddb は TS では eager に使える。呼び出し時に planner が走り、静的ジェネレータと
73
- TS ホストランタイムが**同じ** `deriveExecutionPlan` を共有する(`src/relation/execution-plan.ts`)。
74
- つまり意味論は常に1つ(宣言→plan/IR→実行)で、消費モードが2つあるだけ:
75
-
76
- | 消費モード | コンパイル時点 | 用途 |
77
- |---|---|---|
78
- | 動的(eager UX) | 呼び出し時(結果はキャッシュ可) | TS アプリからの直接利用 |
79
- | AOT(bundle 出力) | ビルド時 | 多言語 Runtime / SCP 配線 / conformance |
80
-
81
- litedbmodel も同じ統合ができる。鍵は **`find(conds, opts)` の引数がすでに宣言データ**であること
82
- (condition タプル、`sql` fragment、SKIP、Values、relation 宣言 — すべて構造を持つ値であり制御フローではない)。
83
- 変えるのは内部だけ: 「conditions → SQL 文字列即ビルド」を「conditions → IR → runtime 実行」へ。
84
-
85
- **移植可能性の境界(唯一残るもの):**
86
- オペレーション間の配線。`find` の結果を TS の if/for で加工して次の `find` を組む自由 TS は
87
- ホスト専用。多言語に持ち出す配線は SCP の Wire/DAG(`{result.*}` 参照 + Expression IR)で宣言する。
88
- 1オペレーション単位は常に IR 化されているため、自由 TS で書いたロジックの SCP 昇格は
89
- 「配線部分を Wire に移す」リファクタで済み、別世界への書き直しにならない。
90
-
91
- ---
92
-
93
- ## 3. in-place か別プロダクトか(訂正)
94
-
95
- **訂正:** 「別ライブラリ必須」の根拠(二重意味論)は撤回。graphddb 自身が contract DSL・planner・
96
- runtime・codegen を**1パッケージ**に同居させ、eager TS 利用と bundle 出力を両立している。
97
- in-place の前例はむしろ graphddb 側にある。
98
-
99
- **既定路線: litedbmodel のメジャーバージョンとして in-place 進化。**
100
- ユーザから見た継続性が高い:
101
-
102
- | API 面 | 移行後 | 破壊度 |
103
- |---|---|---|
104
- | `find/findOne/count/create/update/delete` + condition タプル/SKIP | ほぼそのまま(内部が IR 経路になる) | 小 |
105
- | `await user.posts`(lazy relation) | 残る(§9: prototype + 事前コンパイル IR) | 小 |
106
- | 結果オブジェクト | DBModel インスタンス → **typed-object**(own props はデータのみ) | **中〜大** |
107
- | インスタンス側カスタムメソッド | typed-object には無い → `options.hydrate` factory で載せ替え(graphddb 同形) | 中 |
108
- | `sql` タグ / dbDynamic / dbRaw | Dynamic Slot 語彙として存続(lower 可能サブセット内) | 小 |
109
- | 完全動的な Raw SQL 実行(`execute`/`query`) | TS 専用 escape hatch として存続(契約化すれば方言別 SQL を IR に同梱可) | 小 |
110
- | Middleware / TypeCast | Runtime 関心事として存続 | 小 |
111
-
112
- **別プロダクト切り直しの発動条件(製品判断):** typed-object 化(結果がクラスインスタンスでなくなる)
113
- が既存ユーザに受け入れ不能な場合のみ。その場合も SqlBuilder・relation バッチ SQL・driver 層・
114
- TypeCast はコア資産としてそのまま移転する。**意味論上はどちらでも成立する**ので、
115
- これはアーキテクチャではなく npm パッケージ運用の判断。
116
-
117
- ---
118
-
119
- ## 4. IR の形: Dialect 依存(訂正・最重要)
120
-
121
- **訂正第1版の誤り:** 「Dialect 非依存 SQL IR を設計し、各言語 Runtime が方言へコンパイル」。
122
- これは原提案からの逸脱だった。原提案は `Dialect SQL → Runtime`(**Runtime は SQL を生成しない**、
123
- Compile → Static Flatten → Runtime Expansion)と明記している。
124
-
125
- **正しいフロー:**
126
-
127
- ```
128
- litedbmodel API で記述
129
- → condition / values / relation を解析
130
- → dialect SQL(static flatten 済み)
131
- + param バインディング仕様
132
- + param のオペレーション(wire 接続で解決する部分 = {result.*} / Expression IR)
133
- を IR 化
134
- → Runtime で実行(SQL 生成なし)
135
- ```
136
-
137
- **IR(1オペレーション)が持つもの:**
138
-
139
- - **dialect SQL**: 静的に確定する部分は完全に flatten した SQL テキスト。動的部分を含む場合は
140
- **fragment tree**(事前コンパイル済み SQL 断片の順序付き木 + AND/OR 構造 + 各断片の存在規則)。
141
- **プレースホルダは全方言 `?` で統一**(Postgres も IR 内は `?`。現行 litedbmodel の内部表現 —
142
- `sql` タグ・各 SqlBuilder — と同じ規約であり、資産とそのまま整合)。
143
- - **params 配列**: SQL テキストの `?` と1:1 対応。各要素は
144
- ①外部入力参照 `prop.x`(validate 対象) ②wire 参照 `{result.field}`(前段オペレーション結果)
145
- ③オペレータ IR `{add: [prop.y, 1]}`(閉じた語彙の純粋式・入れ子可)。
146
-
147
- ```
148
- "SELECT ... WHERE x = ? AND y < ?", [prop.x, {add: [prop.y, 1]}]
149
- ```
150
-
151
- - **動的断片の存在規則**: SKIP 評価(`input.x ?? SKIP` → 断片ごと落とす)、条件付き SET 句など。
152
- - **order / pagination の変種**: 事前コンパイル済みの選択肢集合(自由文字列は不可)。
153
- - **assembly 仕様**: 行 → 論理モデルへの組み立て(relation の items 付与位置を含む)。
154
- - **relation ops**: モデル宣言から導出した全 relation バッチクエリ(§9)。
155
-
156
- **Runtime の責務(全言語共通・SQL 知識不要):**
157
-
158
- ```
159
- validate → 断片選択(SKIP/存在規則)→ 配列展開(IN (?) → (?,?,...))
160
- → param オペレータ評価(wire 参照の解決を含む)
161
- → 【最終1パス】? → $N 変換(Postgres のみ。左から機械的に番号付け。MySQL/SQLite は恒等)
162
- → bind → execute → assemble
163
- ```
164
-
165
- `$N` 変換を「param が完全にフラットになった最後」に置くことで、断片の採否・配列展開のたびに
166
- 番号を振り直す問題が**設計から消滅**する。変換は生成テキストの `?` を左から数えるだけの
167
- 機械処理であり、全言語で自明に一致する。
168
-
169
- **この設計にする根拠(前例):**
170
- - 原提案自身(Static Flatten / Runtime Expansion / Runtime は SQL を生成しない)。
171
- - litedbmodel.rs: `#[derive(Model)]` が compile 時に静的 SQL を展開し、動的条件だけ実行時に合成
172
- (fast path は事前展開 SQL をそのまま返す)。
173
- - graphddb: operations.json はバックエンド形(DynamoDB API 形)に**解決済み**のテンプレートを持ち、
174
- 各言語 runtime はテンプレート bind と実行だけを行う。dialect SQL はその正確な RDB 類似物。
175
-
176
- **リスクの縮小(conformance の分解):**
177
- 方言軸は **コンパイル時に TS 側で1回**検証する(既存 SqlBuilder + golden SQL テスト。方言差の
178
- 吸収資産 — RETURNING / ON CONFLICT / UNNEST / ANY / LATERAL — はここで再利用)。
179
- 言語軸は「同一 IR + 同一入力 → 同一の最終 SQL テキスト + 同一の assemble 結果」の機械的検証。
180
- **3方言 × 5言語 = 15セルの行列が「3 + 5」に分解**され、訂正第1版で最難関としたリスクが解消する。
181
-
182
- **残る本当の難所(正直な評価):**
183
- - 動的断片の存在規則と AND/OR 構造木の仕様化(SKIP の合成順序、空 WHERE の縮退、括弧規則)。
184
- litedbmodel.rs の実装が参考になるが、多言語で決定的に一致させる仕様書が必要。
185
- (プレースホルダ番号振り直しは `?` 統一 + 最終1パス `$N` 変換の設計で解消済み。)
186
- - **オペレータ IR の語彙と意味論**: → **[dsl-contracts/expression-ir.md](../../../dsl-contracts/expression-ir.md)
187
- で確定済み**。許可される TS 構文の閉集合とモノモーフィック IR、i64 checked / NaN・Inf は Failure /
188
- `%` は被除数符号 / 文字列比較は code point 順、等の規範。SCP Expression と同一語彙を共有する
189
- (conformance の対象は SQL テキストだけでなく bind 値も含む)。
190
- - **`?` の純度保証**: コンパイラは生成 SQL テキストに placeholder 以外の `?` を出さないことを保証する。
191
- 契約付き Raw SQL(ユーザ記述)にはエスケープ規約(例: `??`)を定める。
192
- - 実行時にしか形が決まらない完全動的 SQL は事前コンパイル不能 → 契約付き Raw SQL
193
- (Input/Output/Effect を宣言し、方言別 SQL 文字列を不透明なまま IR に同梱)へ隔離。
194
-
195
- ---
196
-
197
- ## 5. 再利用マップ
198
-
199
- ### litedbmodel 資産 → 新アーキテクチャでの位置
200
- - **方言別 SqlBuilder** → **コンパイラの方言バックエンド**(IR 生成時に1回走る。Runtime からは消える)
201
- - **LazyRelation のバッチ SQL**(LATERAL / ROW_NUMBER / `= ANY` / 複合キー unnest)→ relation ops の
202
- 事前コンパイル内容としてそのまま(§9)
203
- - **driver 層**(プール・reader/writer・retry・keepAlive)→ TS Runtime
204
- - **TypeCast / Middleware** → Runtime 関心事
205
- - **SKIP / dbDynamic / dbCast / sql`` / Conditions** → Dynamic Slot 語彙(lower 可能サブセットの中核)
206
-
207
- ### graphddb から借りる骨格
208
- - contract DSL(`publicQueryModel`/`publicCommandModel`)、2層 IR + JSON bundle、planner、
209
- relation 実行 DAG(`deriveExecutionPlan`)、codegen、golden conformance、
210
- `options.hydrate`(§9)、RetryPolicy の階層解決(scp-error の優先順位仕様の元)
211
-
212
- ### dsl-contracts / SCP
213
- - Portability Guard(lower 可能サブセットの強制)、Contract Service IF、
214
- SCP Wire/DAG = オペレーション間配線の宣言層、Error Policy(Kind=IR / Tuning=Runtime)
215
-
216
- ### 新規に作るもの
217
- - RDB 用 Access Pattern Contract(Query/Command)
218
- - **Operation IR(dialect SQL + fragment tree + param slots + assembly + relation ops)**と
219
- その動的展開仕様(§4 の「残る難所」)
220
- - litedbmodel API → IR のコンパイラ(condition/values/relation 解析。SqlBuilder を方言バックエンド化)
221
- - 各言語 thin Runtime + codegen + conformance(graphddb 方式のクローン)
222
- - Transaction DAG 導出(後段スコープ、graphddb の mutation-derivation が参考)
223
-
224
- ---
225
-
226
- ## 6. リスク(訂正第2版)
227
-
228
- 1. **動的展開仕様の決定性**(§4)— 最難関だった「Dialect 非依存 SQL IR」の後継。範囲は大幅に狭い
229
- (断片の存在規則・構造木・番号振り直し・配列展開)が、多言語 byte 一致が要る。
230
- → 最初の conformance 対象はここに集中させる。
231
- 2. **意味的等価の限界** — SQL テキストが一致しても、駆動結果(NULL 順序・照合・timezone・浮動小数)は
232
- DB 側の性質。conformance は「同一 SQL + 同一 assemble」を保証し、DB 挙動差は方言コンパイル時の
233
- 規約(ORDER BY の NULLS 指定強制など)で潰せる範囲だけ潰す、と明確に線を引く。
234
- 3. **契約付き Raw SQL の境界** — 静的解析(Unknown Column 排除)の保証が Raw 部分では効かない。
235
- 「不透明・契約付き・方言別同梱」の3点セットを仕様として固定する。
236
- 4. **Transaction DAG 導出は依然研究的** — RDB は対話的・read-after-write・ロックを伴う。
237
- 初期は単文 Command + 明示 transaction 契約(宣言された固定列)に限定し、導出は後段。
238
-
239
- ---
240
-
241
- ## 7. 段階化
242
-
243
- 1. graphddb の Contract / planner / bundle / codegen / conformance 骨格を RDB 向けに fork。
244
- 2. **SQLite + TS だけで縦に1本**: litedbmodel API(find + relation select)→ IR(dialect SQL +
245
- fragment tree)→ thin Runtime 実行。golden = 「同一入力 → 同一 SQL テキスト + 同一結果」。
246
- 動的展開仕様(SKIP・断片木)をここで確定。
247
- 3. Postgres / MySQL 方言バックエンド追加(SqlBuilder 資産の移植。Runtime は不変のはず — それ自体が検証)。
248
- 4. Go / Rust / Python thin Runtime + codegen。litedbmodel.rs の `Relation<T>`/static-flatten 資産を
249
- Rust Runtime に接続。conformance を言語軸へ拡張。
250
- 5. 単文 Command → 明示 transaction 契約 → (後段)Transaction DAG 導出・Gate First。
251
-
252
- ---
253
-
254
- ## 8. エコシステム上の位置づけ
255
-
256
- SCP(Behavior/Component/Wire)がオペレーション間配線の宣言層、dsl-contracts が
257
- メタ契約(Metadata / Portable IR / Contract Service / Portability Guard)、graphddb が KVS 参照実装、
258
- 本件がその RDB プロファイル。litedbmodel(.ts/.rs) は Runtime ターゲット兼オーサリング表面として存続。
259
- 整合チェックは [dsl-contracts/scp-graphddb-consistency.md](../../../dsl-contracts/scp-graphddb-consistency.md)。
260
-
261
- ---
262
-
263
- ## 9. typed-object 化と LazyLoading(訂正・設計確定)
264
-
265
- ### 訂正
266
-
267
- 訂正第1版は「lazy loading(アクセス時の暗黙 I/O)はホスト言語に埋まった命令的実行であり
268
- IR に落とせない → 採用しない」とした。**これは誤り。**
269
-
270
- 守るべき不変条件は「**Runtime は SQL を生成しない**」であって、「Runtime は実行タイミングを
271
- 決めない」ではない。そして lazy relation の実行内容は完全に宣言的である:
272
-
273
- - モデル定義された relation グラフは**閉じた語彙**。全 relation のバッチクエリ
274
- (limit 変種 = LATERAL / ROW_NUMBER、複合キー = unnest / tuple-IN を含む)を
275
- **方言別に事前コンパイルして IR(relation ops)に同梱**できる。
276
- - lazy アクセス = **事前コンパイル済み relation op の、実行時タイミングでの起動**。
277
- batch context(結果セット内の兄弟から親キーを収集 → 1回のバッチ実行 → 各親へ分配)も
278
- Runtime の一般アルゴリズムであり、SQL 知識を要しない。
279
- - **litedbmodel.rs の `Relation<T>.load()` + 自動 batch が、他言語で同じ意味論を実装できることの
280
- 既存証明**になっている。
281
- - conformance: 「結果セット + relation load 要求 → 同一 SQL テキスト + 同一の行/assemble」で
282
- 言語横断に検証可能。
283
-
284
- これにより「アプリケーションによっては何をロードするか事前に確定できない」という現実の課題
285
- (一覧の条件付き描画、動的なグラフ探索など)にも答えが出る: **全エッジが事前コンパイル済み**
286
- なので、ad-hoc な traversal も常に IR + Runtime 経由で実行される。
287
-
288
- ### eager(宣言 select)と lazy の関係
289
-
290
- | | 宣言 select(推奨経路) | lazy アクセス(fallback) |
291
- |---|---|---|
292
- | ロード決定 | クエリ宣言時 | アクセス時(Runtime がタイミング決定) |
293
- | 実行 | planner が stage 化・兄弟 dedup(先読み最適化が効く) | batch context で N+1 回避(先読みはできない) |
294
- | SQL | 事前コンパイル済み relation op | **同じ** relation op |
295
- | 結果 | own プロパティ(データ) | アクセス時に解決 |
296
-
297
- planner の stage 最適化(兄弟をまとめて 1 stage で dedup 実行)は宣言 select でしか効かないため、
298
- **宣言できるものは宣言するのが最適経路、lazy はそれを強制しないための安全な fallback**、と位置づける。
299
-
300
- ### TS の実装機構: prototype で良い(設計確定)
301
-
302
- - **own プロパティ = 純データのみ**。`JSON.stringify` / `Object.keys` は汚れない。
303
- - **prototype に lazy getter**(`await user.posts` → `Promise<Post[]>`)と、
304
- **非列挙 Symbol の batch context**(graphddb の `GRAPHDDB_KEY` と同じ手法。spread/JSON に漏れない)。
305
- - **shadowing による統一**: select で宣言 hydrate された relation は own プロパティ(`Post[]` そのもの)
306
- として付与され、**prototype の lazy getter を自然に shadow** する。同じプロパティ名で
307
- 「宣言済み → データ / 未宣言 → lazy Promise」が両立し、型は select から推論
308
- (graphddb の `QueryResult<T,S>` 型代数と同型)。
309
- - spread / structuredClone は lazy と batch context を落とす(データは保持)。これは graphddb の
310
- hidden updatable key と同じ「設計された劣化」であり、ドキュメント化する。
311
- - 他言語のトリガーはエルゴノミクスに合わせる: Rust `user.posts.load().await`(既存)、
312
- Go `user.Posts(ctx)`、Python property/メソッド。**観測されるデータ挙動と SQL は全言語同一**。
313
-
314
- ### hydrate(graphddb と整合)
315
-
316
- 「後からホストオブジェクトに載せ替えたい」要求は、独自 API ではなく **graphddb の `options.hydrate`
317
- と同形**にする: read options bag の factory `(raw) => R`。relation 解決後に適用、`null` には適用しない、
318
- **IR には入らないホストランタイム専有**(graphddb docs/class-hydration.md と同じ位置づけ)。
319
- インスタンスメソッドが欲しいユーザは `hydrate: (raw) => new UserDomain(raw)` で従来の
320
- クラス的エルゴノミクスを回復できる。graphddb Phase 3(per-relation hydrate)が入る場合も同じ形に追随する。
321
-
322
- ### 現行からの移行の実態
323
-
324
- - `await user.posts` は**そのまま動く**(機構が getter→遅延バッチ から getter→relation op 起動 に変わるだけ)。
325
- - 変わるのは: 結果が DBModel インスタンスでなく typed-object になること(メソッドは hydrate で回復)、
326
- relation の select 宣言(推奨経路)が新設されること。
327
- - LazyRelation の中身(バッチ SQL)は relation ops のコンパイル内容として全量活きる。
328
- 消えるのは ActiveRecord クラス機構だけ。