litedbmodel 2.0.0 → 2.0.2
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.
- package/dist/scp/authoring-sql.d.ts +78 -0
- package/dist/scp/authoring-sql.d.ts.map +1 -1
- package/dist/scp/authoring-sql.js +110 -2
- package/dist/scp/authoring-sql.js.map +1 -1
- package/dist/scp/catalog.d.ts +5 -2
- package/dist/scp/catalog.d.ts.map +1 -1
- package/dist/scp/catalog.js +32 -1
- package/dist/scp/catalog.js.map +1 -1
- package/dist/scp/codegen.d.ts +143 -85
- package/dist/scp/codegen.d.ts.map +1 -1
- package/dist/scp/codegen.js +374 -90
- package/dist/scp/codegen.js.map +1 -1
- package/dist/scp/coltype.d.ts +41 -0
- package/dist/scp/coltype.d.ts.map +1 -0
- package/dist/scp/coltype.js +188 -0
- package/dist/scp/coltype.js.map +1 -0
- package/dist/scp/dialect.d.ts +12 -3
- package/dist/scp/dialect.d.ts.map +1 -1
- package/dist/scp/dialect.js +12 -3
- package/dist/scp/dialect.js.map +1 -1
- package/dist/scp/find-filter-guard.d.ts +68 -0
- package/dist/scp/find-filter-guard.d.ts.map +1 -0
- package/dist/scp/find-filter-guard.js +88 -0
- package/dist/scp/find-filter-guard.js.map +1 -0
- package/dist/scp/fragment/assemble.d.ts +61 -0
- package/dist/scp/fragment/assemble.d.ts.map +1 -0
- package/dist/scp/fragment/assemble.js +156 -0
- package/dist/scp/fragment/assemble.js.map +1 -0
- package/dist/scp/fragment/compile-pg.d.ts +107 -0
- package/dist/scp/fragment/compile-pg.d.ts.map +1 -0
- package/dist/scp/fragment/compile-pg.js +142 -0
- package/dist/scp/fragment/compile-pg.js.map +1 -0
- package/dist/scp/fragment/index.d.ts +16 -0
- package/dist/scp/fragment/index.d.ts.map +1 -0
- package/dist/scp/fragment/index.js +34 -0
- package/dist/scp/fragment/index.js.map +1 -0
- package/dist/scp/fragment/model.d.ts +119 -0
- package/dist/scp/fragment/model.d.ts.map +1 -0
- package/dist/scp/fragment/model.js +66 -0
- package/dist/scp/fragment/model.js.map +1 -0
- package/dist/scp/fragment/pg-array-type.d.ts +13 -0
- package/dist/scp/fragment/pg-array-type.d.ts.map +1 -0
- package/dist/scp/fragment/pg-array-type.js +34 -0
- package/dist/scp/fragment/pg-array-type.js.map +1 -0
- package/dist/scp/guard.d.ts +2 -6
- package/dist/scp/guard.d.ts.map +1 -1
- package/dist/scp/guard.js +19 -22
- package/dist/scp/guard.js.map +1 -1
- package/dist/scp/index.cjs +18695 -3921
- package/dist/scp/index.d.ts +41 -24
- package/dist/scp/index.d.ts.map +1 -1
- package/dist/scp/index.js +134 -49
- package/dist/scp/index.js.map +1 -1
- package/dist/scp/index.mjs +4830 -1432
- package/dist/scp/makesql/authoring-compile.d.ts +90 -0
- package/dist/scp/makesql/authoring-compile.d.ts.map +1 -0
- package/dist/scp/makesql/authoring-compile.js +494 -0
- package/dist/scp/makesql/authoring-compile.js.map +1 -0
- package/dist/scp/makesql/compile-crud.d.ts +133 -0
- package/dist/scp/makesql/compile-crud.d.ts.map +1 -0
- package/dist/scp/makesql/compile-crud.js +288 -0
- package/dist/scp/makesql/compile-crud.js.map +1 -0
- package/dist/scp/makesql/compile-relation.d.ts +157 -0
- package/dist/scp/makesql/compile-relation.d.ts.map +1 -0
- package/dist/scp/makesql/compile-relation.js +425 -0
- package/dist/scp/makesql/compile-relation.js.map +1 -0
- package/dist/scp/makesql/compile-select.d.ts +52 -0
- package/dist/scp/makesql/compile-select.d.ts.map +1 -0
- package/dist/scp/makesql/compile-select.js +58 -0
- package/dist/scp/makesql/compile-select.js.map +1 -0
- package/dist/scp/makesql/compile.d.ts +63 -0
- package/dist/scp/makesql/compile.d.ts.map +1 -0
- package/dist/scp/makesql/compile.js +99 -0
- package/dist/scp/makesql/compile.js.map +1 -0
- package/dist/scp/makesql/handler.d.ts +58 -0
- package/dist/scp/makesql/handler.d.ts.map +1 -0
- package/dist/scp/makesql/handler.js +113 -0
- package/dist/scp/makesql/handler.js.map +1 -0
- package/dist/scp/makesql/index.d.ts +33 -0
- package/dist/scp/makesql/index.d.ts.map +1 -0
- package/dist/scp/makesql/index.js +114 -0
- package/dist/scp/makesql/index.js.map +1 -0
- package/dist/scp/makesql/ir.d.ts +42 -0
- package/dist/scp/makesql/ir.d.ts.map +1 -0
- package/dist/scp/makesql/ir.js +66 -0
- package/dist/scp/makesql/ir.js.map +1 -0
- package/dist/scp/makesql/json-array.d.ts +84 -0
- package/dist/scp/makesql/json-array.d.ts.map +1 -0
- package/dist/scp/makesql/json-array.js +118 -0
- package/dist/scp/makesql/json-array.js.map +1 -0
- package/dist/scp/makesql/json-batch.d.ts +102 -0
- package/dist/scp/makesql/json-batch.d.ts.map +1 -0
- package/dist/scp/makesql/json-batch.js +269 -0
- package/dist/scp/makesql/json-batch.js.map +1 -0
- package/dist/scp/makesql/makesql.d.ts +99 -0
- package/dist/scp/makesql/makesql.d.ts.map +1 -0
- package/dist/scp/makesql/makesql.js +122 -0
- package/dist/scp/makesql/makesql.js.map +1 -0
- package/dist/scp/makesql/outtype.d.ts +44 -0
- package/dist/scp/makesql/outtype.d.ts.map +1 -0
- package/dist/scp/makesql/outtype.js +197 -0
- package/dist/scp/makesql/outtype.js.map +1 -0
- package/dist/scp/makesql/pool-executor.d.ts +47 -0
- package/dist/scp/makesql/pool-executor.d.ts.map +1 -0
- package/dist/scp/makesql/pool-executor.js +50 -0
- package/dist/scp/makesql/pool-executor.js.map +1 -0
- package/dist/scp/makesql/static-bundle.d.ts +187 -0
- package/dist/scp/makesql/static-bundle.d.ts.map +1 -0
- package/dist/scp/makesql/static-bundle.js +1113 -0
- package/dist/scp/makesql/static-bundle.js.map +1 -0
- package/dist/scp/makesql/tx.d.ts +216 -0
- package/dist/scp/makesql/tx.d.ts.map +1 -0
- package/dist/scp/makesql/tx.js +788 -0
- package/dist/scp/makesql/tx.js.map +1 -0
- package/dist/scp/makesql/writeouttype.d.ts +66 -0
- package/dist/scp/makesql/writeouttype.d.ts.map +1 -0
- package/dist/scp/makesql/writeouttype.js +195 -0
- package/dist/scp/makesql/writeouttype.js.map +1 -0
- package/dist/scp/relation.d.ts +86 -74
- package/dist/scp/relation.d.ts.map +1 -1
- package/dist/scp/relation.js +186 -120
- package/dist/scp/relation.js.map +1 -1
- package/dist/scp/runtime.d.ts +158 -211
- package/dist/scp/runtime.d.ts.map +1 -1
- package/dist/scp/runtime.js +250 -515
- package/dist/scp/runtime.js.map +1 -1
- package/dist/scp/typed-object.d.ts +12 -1
- package/dist/scp/typed-object.d.ts.map +1 -1
- package/dist/scp/typed-object.js +25 -4
- package/dist/scp/typed-object.js.map +1 -1
- package/docs/proposal/litedbmodel-v2-scp-architecture.md +51 -0
- package/docs/proposal/v0-coverage-matrix.md +157 -0
- package/docs/proposal/v2-completeness-plan.md +90 -0
- package/docs/proposal/v2-sql-parity-checklist.md +162 -0
- package/package.json +3 -3
- package/dist/scp/bridge.d.ts +0 -64
- package/dist/scp/bridge.d.ts.map +0 -1
- package/dist/scp/bridge.js +0 -329
- package/dist/scp/bridge.js.map +0 -1
- package/dist/scp/compile-dialect.d.ts +0 -39
- package/dist/scp/compile-dialect.d.ts.map +0 -1
- package/dist/scp/compile-dialect.js +0 -62
- package/dist/scp/compile-dialect.js.map +0 -1
- package/dist/scp/compile-sqlite.d.ts +0 -114
- package/dist/scp/compile-sqlite.d.ts.map +0 -1
- package/dist/scp/compile-sqlite.js +0 -149
- package/dist/scp/compile-sqlite.js.map +0 -1
- package/dist/scp/ir.d.ts +0 -92
- package/dist/scp/ir.d.ts.map +0 -1
- package/dist/scp/ir.js +0 -28
- package/dist/scp/ir.js.map +0 -1
- package/dist/scp/render.d.ts +0 -40
- package/dist/scp/render.d.ts.map +0 -1
- package/dist/scp/render.js +0 -170
- package/dist/scp/render.js.map +0 -1
- package/dist/scp/write-plan.d.ts +0 -161
- package/dist/scp/write-plan.d.ts.map +0 -1
- package/dist/scp/write-plan.js +0 -528
- package/dist/scp/write-plan.js.map +0 -1
- package/dist/scp/write-runtime.d.ts +0 -80
- package/dist/scp/write-runtime.d.ts.map +0 -1
- package/dist/scp/write-runtime.js +0 -167
- package/dist/scp/write-runtime.js.map +0 -1
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# v2 SQL パリティ チェックリスト(epic #43 — PostgreSQL アンカー)
|
|
2
|
+
|
|
3
|
+
> 目的: v2 SCP の生成 SQL を、旧 `litedbmodel`(.ts v1) と旧 `litedbmodel.rs` の **tuned SQL** と一致させる。v2 の conformance を縮小基準(.ts v1 SqlBuilder の単一行 CRUD / SQLite-first 形)にアンカーしたため、このライブラリの核心である tuned SQL を取りこぼし、**旧 .ts・.rs の両方より SQL が退行**した(超デグレ)。本書はその全差分の作業チェックリスト。
|
|
4
|
+
|
|
5
|
+
## 原則
|
|
6
|
+
- **アンカー = PostgreSQL。** PG の最も tuned な SQL を正とし、MySQL/SQLite は PG 意味論に各 DB の能力範囲で導出する(PG を lowest-common-denominator に落とさない)。
|
|
7
|
+
- **conformance golden を旧 tuned 実装の PG SQL に対して作り直す**(縮小基準は破棄)。
|
|
8
|
+
- **原実装のバグは踏襲しない**(後述の「原実装バグ」参照)。3実装で挙動が割れる箇所は PG アンカーを選ぶ。
|
|
9
|
+
- 凡例 `差分`: ✅同一 / ⚠️差あり / ❌v2欠落。`優先度`: 高(correctness) / 中(perf/parity) / 低(cosmetic/edge)。
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 0. 構造的所見(最重要 — 単なる runtime 修正でなく §8 IR の破壊的変更が要る)
|
|
14
|
+
|
|
15
|
+
1. **§8 可搬 bundle が batch write を表現できない。** `compileInsertFor`/UPDATE 経路は単一行のみ。batch INSERT(UNNEST)/UPDATE(UNNEST/JOIN-VALUES/CASE-WHEN)/SKIP-column が bundle に無い → **Python/Go/Rust/PHP の thin runtime は batch write を実行不可**。多言語の約束の穴。
|
|
16
|
+
2. **§8 IR が複合キー relation を表現できない。** `RelationOp` が `parentKey`/`targetKey` を単一 `string` でハードコード(`src/scp/relation.ts:64-69,90-92`)。複合 FK の relation が構造的に不可能。
|
|
17
|
+
3. **relation IN に dialect 別 fragment 種が無い。** `= ANY(?::type[])` / UNNEST / `::type` cast / `CROSS JOIN LATERAL` を表す fragment kind が無く、`Dialect` strategy(`dialect.ts`) は INSERT-conflict/placeholder/NULLS しか扱わない(relation に未関与)。
|
|
18
|
+
4. **WHERE 語彙が閉集合に縮小。** v2 は eq/ne/lt/le/gt/ge/isNull/in/and/or/cond のみ(`bridge.ts:208` が他を loud-reject)。subquery/EXISTS/cast/LIKE/raw/BETWEEN 等が全欠落。
|
|
19
|
+
5. **hardLimit / relation where-filter / FOR UPDATE / HAVING / APPEND** が §8/runtime から欠落。
|
|
20
|
+
|
|
21
|
+
→ #43 は「IR 契約の作り直し(relation 複合キー・dialect relation fragment・batch write・条件語彙拡張)+ 全言語 render + conformance 再構築」を含む。**リリース済み 2.0.0 はこの点で超デグレ。**
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 1. 原実装バグ(PG アンカー統一時に *踏襲しない*)
|
|
26
|
+
- **.rs cast が dialect 非対応**: `condition.rs:97-116` が `?::type` をハードコードし SQLite/MySQL にも `::uuid` を漏らす。v1 は `SqlCastFormatter` で dialect gate。→ **v1 の dialect-aware を採用**。
|
|
27
|
+
- **.rs `Immediate`(`NOW()`) が条件で inline されず文字列を param bind**(`condition.rs` catch-all、test :613-622)。v1 は inline。→ **v1 の inline を採用**。
|
|
28
|
+
- **.rs 空 `IntArray/TextArray/FloatArray/BoolArray` → 不正な `IN ()`**(空ガードが `ValueArray` のみ)。v1/v2 は `1 = 0`。→ **`1 = 0` を採用**。
|
|
29
|
+
- **.rs per-parent-limit が PG でも `ROW_NUMBER()`**(LATERAL でない)。v1 は `CROSS JOIN LATERAL`。→ **v1 LATERAL を PG アンカーに採用**。
|
|
30
|
+
- **.rs PG 型推論が粗い**(uuid/timestamp/date/json を text に畳む、`model.rs:730`)。v1 は sqlCast 駆動で精緻。→ **v1 の sqlCast 駆動を採用**。
|
|
31
|
+
|
|
32
|
+
## 2. 3実装割れ(PG アンカーで確定すべき判断)
|
|
33
|
+
- **OR / 空OR / 単一要素の括弧規則**が v1/`.rs`/v2 で不一致(.rs は top-level OR を `(…)` 包む・単一要素 unwrap、v2 は top-level OR を包まず nested 単一 fragment を `(x)` 包む、v1 `__or__` は二重包み)。空OR は .rs=`1=0` / v1・v2=空文字(AND 合流時に TRUE 相当=意味が違う)。→ **PG アンカー形を1つ決めて pin**。
|
|
34
|
+
- **boolean を WHERE で literal(`= TRUE`) か bound(`= ?`) か**(v1=literal / .rs・v2=bound)。→ 要決定(tuned PG は literal `TRUE`)。
|
|
35
|
+
- **LIMIT/OFFSET を parameterize(`LIMIT ?`) か inline(`LIMIT 10`) か**(v2=param / v1・.rs=inline)。→ **byte-golden が v1 と不一致になる**ため要決定。
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## A. WHERE / 条件 / 値
|
|
40
|
+
|
|
41
|
+
| 構文 | dialect | .ts v1 | .rs | v2現状 | PGアンカー目標 | 差分 | 優先度 | ☐ |
|
|
42
|
+
|---|---|---|---|---|---|---|---|---|
|
|
43
|
+
| equality `col = ?` | all | `col = ?`/`$1` | `col = ?` | `col = ?` | `col = $1` | ✅同一 | — | |
|
|
44
|
+
| `!= / <>` | PG | custom-op key のみ | `Raw` のみ | `col <> ?`(first-class) | `col <> $1` | ⚠️差あり | 中 | [ ] |
|
|
45
|
+
| `< <= > >=` | PG | custom-op key のみ | `Raw` のみ | first-class `cmp` | `col > $1` | ⚠️差あり(出力は一致) | 中 | [ ] |
|
|
46
|
+
| IN-list `col IN (?,?)` | all | array→IN | array→IN | `IN (?)`→展開 | `col IN ($1,$2)` | ✅同一 | — | |
|
|
47
|
+
| empty-IN | all | `1 = 0` no param | ⚠️IntArray等は `IN ()`(不正) / ValueArrayのみ`1=0` | `1 = 0` | `1 = 0` | ⚠️.rsバグ | 高 | [ ] |
|
|
48
|
+
| NOT IN (list) | PG | custom-op のみ | 無し | ❌欠落 | `col NOT IN ($1,$2)` | ❌ | 中 | [ ] |
|
|
49
|
+
| IS NULL | all | `col IS NULL` | `col IS NULL` | `isNull` | `col IS NULL` | ✅同一 | — | |
|
|
50
|
+
| **IS NOT NULL** | all | `dbNotNull` | `Value::NotNull` | ❌欠落(isNullのみ) | `col IS NOT NULL` | ❌ | 高 | [ ] |
|
|
51
|
+
| boolean | PG | `= TRUE`literal | `= ?`bound | `= ?`bound | 要決定(PG tuned=`= TRUE`) | ⚠️差あり | 中 | [ ] |
|
|
52
|
+
| LIKE/NOT LIKE | PG | custom-op/raw | `Raw` | ❌欠落 | `col LIKE $1` | ❌ | 中 | [ ] |
|
|
53
|
+
| ILIKE | PG | custom-op/raw | `Raw` | ❌欠落 | `col ILIKE $1`(MySQL/SQLiteは`LIKE`・blindに落とさない) | ❌ | 中 | [ ] |
|
|
54
|
+
| BETWEEN | PG | custom-op | `Raw` | ❌欠落 | `col BETWEEN $1 AND $2` | ❌ | 中 | [ ] |
|
|
55
|
+
| **IN(subquery)** | PG | `DBSubquery` | `InSubquery` | ❌欠落 | `col IN (SELECT …)`(複合`(a,b) IN (…)`) | ❌ | 高 | [ ] |
|
|
56
|
+
| **NOT IN(subquery)** | PG | `DBSubquery` | `NotInSubquery` | ❌欠落 | `col NOT IN (SELECT …)` | ❌ | 高 | [ ] |
|
|
57
|
+
| **EXISTS** | PG | `DBExists` | `Exists` | ❌欠落 | `EXISTS (SELECT 1 …)` | ❌ | 高 | [ ] |
|
|
58
|
+
| **NOT EXISTS** | PG | `DBExists` | `NotExists` | ❌欠落 | `NOT EXISTS (…)` | ❌ | 高 | [ ] |
|
|
59
|
+
| 相関 parentRef | PG | `DBParentRef`→`t.col`inline | `parent_ref`inline | ❌欠落 | inlined `outer.col` | ❌ | 高 | [ ] |
|
|
60
|
+
| **raw / `__raw__`** | PG | verbatim/tuple | `Condition::Raw` | ❌欠落(WHERE未配線) | raw predicate + params(§13) | ❌ | 高 | [ ] |
|
|
61
|
+
| custom-op (key-with-?) | PG | verbatim | 無し(Raw) | ❌欠落 | author operator | ❌ | 中 | [ ] |
|
|
62
|
+
| AND grouping | all | `join(' AND ')`,nested`(…)` | 同 | tree AND,nested`(inner)` | `a=$1 AND b=$2` | ✅同一 | — | |
|
|
63
|
+
| **OR / 括弧** | PG | `__or__`二重包み | top-OR`(…)`,単一unwrap | top-OR包まず/nested単一`(x)` | 要確定(§2) | ⚠️差あり | 高 | [ ] |
|
|
64
|
+
| **空AND** | all | `''`(節ドロップ) | `1=1` | `''`(節ドロップ) | 節ドロップ | ⚠️.rs差 | 中 | [ ] |
|
|
65
|
+
| **空OR** | all | `''` | `1=0` | `''` | 要確定(意味差) | ⚠️差あり | 高 | [ ] |
|
|
66
|
+
| SKIP/optional | all | 暗黙(key無) | caller filter | `when`/`skipWhen`明示 | 不在fragment→SQL/param無 | ✅同一 | — | |
|
|
67
|
+
| SKIP on GROUP | all | 暗黙可 | 可 | ❌loud-reject(`compile-sqlite.ts:103`) | group条件droppable | ⚠️差あり | 中 | [ ] |
|
|
68
|
+
| **cast `::type`単体** | PG | `dbCast`→`?::uuid`(formatter, dialect-gate) | ⚠️`?::uuid`hardcode(dialect非対応) | ❌欠落 | `$1::uuid`(MySQL/SQLite=`?`) | ❌+.rsバグ | 高 | [ ] |
|
|
69
|
+
| **cast array `IN(?::t,…)`** | PG | `dbCastIn`(formatter) | ⚠️hardcode | ❌欠落 | `IN ($1::uuid,…)`(他=`IN(?,…)`) | ❌ | 高 | [ ] |
|
|
70
|
+
| cast array empty | PG | `1 = 0` | `1 = 0` | ❌欠落 | `1 = 0` | ❌ | 中 | [ ] |
|
|
71
|
+
| dynamic `col = fn(?)` | PG | `DBDynamicValue` | `Value::Dynamic` | ❌欠落 | `col = fn($1)` | ❌ | 中 | [ ] |
|
|
72
|
+
| **immediate `col = NOW()`** | PG | inline no-param | ⚠️`?`にstring bind(バグ) | ❌欠落 | `col = NOW()`inline | ❌+.rsバグ | 高 | [ ] |
|
|
73
|
+
| **tuple/composite IN** | PG | `dbTupleIn`→`(a,b) IN ((?,?),…)` | `db_tuple_in_pg`→UNNEST | ❌欠落 | `(a,b) IN (SELECT * FROM UNNEST($1::t[],…))`(他=value-list) | ❌ | 高 | [ ] |
|
|
74
|
+
| `= ANY($1::t[])`(条件) | PG | PK-helperのみ | UNNEST-helperのみ | ❌欠落 | `col = ANY($1::t[])`(他=IN展開) | ❌ | 中 | [ ] |
|
|
75
|
+
| value: date/json | PG | driver formatter/`::jsonb` | typed(chrono/serde) | ⚠️bc Value untyped | typed bind | ⚠️差あり | 中 | [ ] |
|
|
76
|
+
|
|
77
|
+
## B. INSERT / UPDATE / DELETE / placeholder / tail
|
|
78
|
+
|
|
79
|
+
| 構文 | dialect | .ts v1 | .rs | v2現状 | PGアンカー目標 | 差分 | 優先度 | ☐ |
|
|
80
|
+
|---|---|---|---|---|---|---|---|---|
|
|
81
|
+
| single INSERT | PG | `VALUES(?::cast…)` | `VALUES($1…)`(cast無) | `VALUES(?…)`(cast無) | 単一行+per-col`?::sqlCast`保持 | ⚠️差あり | 中 | [ ] |
|
|
82
|
+
| column order | all | caller順(明示list) | caller順 | JS object挿入順(`compile-dialect.ts:46`) | caller宣言順 | ⚠️差あり | 中 | [ ] |
|
|
83
|
+
| **batch INSERT** | PG | `UNNEST($i::type[])`+型推論(array/json/DBToken) | `UNNEST`(型粗い) | ❌欠落(単一行のみ) | PG UNNEST batch(型推論)+SQLite/MySQL=multi VALUES | ❌(bundle欠落→多言語batch不可) | 高 | [ ] |
|
|
84
|
+
| ON CONFLICT DO NOTHING/UPDATE | all | `EXCLUDED`/`excluded`/`VALUES(c)` | 同 | 同(`dialect.ts`) | 各方言verb | ✅同一 | — | |
|
|
85
|
+
| empty DO UPDATE cols→all | all | (暗黙) | 明示fallback(`model.rs:524`) | ❌fallback無→`DO UPDATE SET `破損 | empty→全列 | ⚠️差あり | 中 | [ ] |
|
|
86
|
+
| RETURNING bare | PG | `RETURNING id` | 同 | `RETURNING cols` | bare | ✅同一 | — | |
|
|
87
|
+
| RETURNING `table.col`(SQLite/batch) | SQLite/PG | `table.col`/`t.col` | 同 | ❌bare のみ | SQLite=`table.col`/PG batch=`t.col`alias | ⚠️差あり | 中 | [ ] |
|
|
88
|
+
| RETURNING MySQL simulate | MySQL | append+driver sim | 同 | ❌無条件`RETURNING`(sim戦略無) | append+sim | ⚠️差あり | 中 | [ ] |
|
|
89
|
+
| single UPDATE | PG | `SET c=?::cast` | `SET c=?` | `SET c=?`(cast無) | per-col`?::sqlCast`保持 | ⚠️差あり | 中 | [ ] |
|
|
90
|
+
| **batch UPDATE** | PG | `SET c=v.c FROM UNNEST(?::t[],…) AS v(cols) WHERE t.k=v.k` | 同(型粗い) | ❌欠落 | PG UNNEST batch+MySQL JOIN-VALUES+SQLite CASE-WHEN | ❌(bundle欠落) | 高 | [ ] |
|
|
91
|
+
| **SKIP-column batch** | PG | `CASE WHEN v._skip_c…`+`?::bool[]` | 同 | ❌欠落 | PG CASE/MySQL IF/SQLite WHEN | ❌ | 高 | [ ] |
|
|
92
|
+
| batch RETURNING alias | PG | `RETURNING t.col` | 同 | ❌欠落 | `RETURNING t.col` | ❌ | 中 | [ ] |
|
|
93
|
+
| single DELETE | all | WHERE必須(throw) | WHERE任意(全消し可) | WHERE必須(throw) | WHERE必須(v1=PGアンカー) | ⚠️.rs外れ値 | 低 | [ ] |
|
|
94
|
+
| IN-list DELETE / empty | all | `IN(?,…)`,空`1=0` | 同 | 同 | 同 | ✅同一 | — | |
|
|
95
|
+
| `?`→`$N` | PG | naive replace | quote-aware(literalスキップ) | naive(`dialect.ts:129`) | quote-aware(#42) | ⚠️差あり(.rsが安全) | 中 | [ ] |
|
|
96
|
+
| **LIMIT/OFFSET** | all | inline literal `LIMIT 10` | inline | **param `LIMIT ?`**(`compile-sqlite.ts:158`) | 要確定(v1 goldenと text不一致) | ⚠️差あり | 高 | [ ] |
|
|
97
|
+
| NULLS FIRST/LAST | PG | 無(raw order) | 無 | `orderByNulls`定義済だが**未呼出(dormant)** | PG native/MySQL emulation | ⚠️差あり | 低 | [ ] |
|
|
98
|
+
| **FOR UPDATE** | all | `FOR UPDATE` | `FOR UPDATE` | ❌欠落 | `FOR UPDATE` | ❌ | 中 | [ ] |
|
|
99
|
+
| FOR SHARE | PG | 無 | `FOR SHARE`(.rsのみ) | ❌欠落 | `FOR SHARE` | ❌(.rsのみ) | 低 | [ ] |
|
|
100
|
+
| GROUP BY | all | 有 | 有 | 有 | 有 | ✅同一 | — | |
|
|
101
|
+
| HAVING | all | 無(v1core) | `HAVING`(.rsのみ) | ❌欠落 | `HAVING` | ⚠️差あり | 低 | [ ] |
|
|
102
|
+
| APPEND raw tail | all | 有 | 有 | ❌欠落 | raw append | ⚠️差あり | 低 | [ ] |
|
|
103
|
+
| identifier quoting | all | 無 | 無 | 無 | 無 | ✅同一 | — | |
|
|
104
|
+
|
|
105
|
+
## C. Relation batch-load / 型 binding
|
|
106
|
+
|
|
107
|
+
| 構文 | dialect | .ts v1 | .rs | v2現状 | PGアンカー目標 | 差分 | 優先度 | ☐ |
|
|
108
|
+
|---|---|---|---|---|---|---|---|---|
|
|
109
|
+
| single-key batch | PG | `= ANY(?::type[])`(1配列param) | `= ANY(?::t[])` | `IN (?,?,…)`(N param,cast無) | `= ANY($1::type[])` | ❌欠落 | 高 | [ ] |
|
|
110
|
+
| single-key batch | MySQL/SQLite | `IN (?,…)` | `IN (?,…)` | `IN (?,…)` | `IN (?,…)` | ✅同一 | — | |
|
|
111
|
+
| PG配列型推論 | PG | sqlCast駆動(uuid/ts/date/json) | ⚠️text畳み(粗) | 無(cast無) | sqlCast駆動 | ❌+.rsバグ | 高 | [ ] |
|
|
112
|
+
| per-parent-limit | PG | `CROSS JOIN LATERAL(…LIMIT n)` | ⚠️`ROW_NUMBER()`(LATERAL非) | `ROW_NUMBER()` | `CROSS JOIN LATERAL`(v1アンカー) | ❌+.rs退行 | 高 | [ ] |
|
|
113
|
+
| per-parent-limit | MySQL/SQLite | `ROW_NUMBER()` | 同 | 同 | `ROW_NUMBER()` | ✅同一 | — | |
|
|
114
|
+
| **複合キー(無limit)** | PG | `JOIN unnest(?::t[],…)`/`(cols) IN (SELECT * FROM UNNEST)` | `(cols) IN (SELECT * FROM UNNEST)` | ❌**表現不可**(単一key IR) | UNNEST tuple-IN | ❌(IR破壊的変更要) | 高 | [ ] |
|
|
115
|
+
| 複合キー(無limit) | MySQL/SQLite | `(a,b) IN ((?,?),…)` | 同 | ❌ | tuple-IN | ❌ | 高 | [ ] |
|
|
116
|
+
| 複合キー+limit | PG | LATERAL composite | ⚠️ROW_NUMBER composite | ❌ | LATERAL composite | ❌ | 高 | [ ] |
|
|
117
|
+
| 複合キー+limit | MySQL/SQLite | ROW_NUMBER composite | 同 | ❌ | ROW_NUMBER composite | ❌ | 高 | [ ] |
|
|
118
|
+
| 複合キー dedup | all | NUL-join tuple | 同 | ❌(複合経路無) | tuple dedup | ❌ | 中 | [ ] |
|
|
119
|
+
| 単一key dedup | all | Set/JSON | caller upstream | `dedupeKeys`Set | dedup | ✅同一 | — | |
|
|
120
|
+
| empty key set | all | query無 | query無 | query無(assert用`1=0`) | query無 | ✅同一 | — | |
|
|
121
|
+
| group by target key | hasMany | Map/NUL複合 | 同 | 単一keyのみ | 複合対応 | ⚠️差あり | 中 | [ ] |
|
|
122
|
+
| **hardLimit強制** | hasMany | 有(`DBModel.ts:1703`) | 有(`LIMIT n+1`+count) | ❌欠落 | hardLimit probe+throw | ❌ | 中 | [ ] |
|
|
123
|
+
| relation `where`filter | all | `config.conditions`merge | ⚠️decl有るが未配線 | ❌field無 | batch SELECTにmerge | ❌ | 中 | [ ] |
|
|
124
|
+
| ORDER BY(unlimited) | all | append | append | append | append | ✅同一 | — | |
|
|
125
|
+
| typed bind bool | PG | typed array | typed | plain`?` | typed | ⚠️差あり | 中 | [ ] |
|
|
126
|
+
| typed bind uuid | PG | `?::uuid`/`uuid[]` | `PgParam::Uuid` | text`?` | `?::uuid`/`=ANY(?::uuid[])` | ❌ | 高 | [ ] |
|
|
127
|
+
| typed bind timestamp/date | PG | typed | typed(chrono) | ISO string | typed | ⚠️差あり | 中 | [ ] |
|
|
128
|
+
| typed bind json | PG | `::jsonb` | `PgParam::Json` | 無 | `::jsonb` | ❌(PG) | 低 | [ ] |
|
|
129
|
+
| array param `::type[]` | PG | `= ANY`/unnest核 | `?::type[]` | 無(IN展開) | 1配列param`::type[]` | ❌ | 高 | [ ] |
|
|
130
|
+
| typed-IN helper `db_cast_in`/`db_uuid_in` | PG | (sqlCast) | `CastArray`→`?::type` | 無 | typed-cast IN | ❌ | 中 | [ ] |
|
|
131
|
+
| composite-IN helper `db_tuple_in_pg`(UNNEST) | PG | inline | `values.rs:439` | 無 | UNNEST composite-IN | ❌ | 高 | [ ] |
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 3. 高優先度 マスターロールアップ(実装の起点)
|
|
136
|
+
|
|
137
|
+
**IR 破壊的変更を伴う(§8 bundle + Dialect strategy + 全言語 render + conformance 再構築):**
|
|
138
|
+
1. 複合キー relation(`RelationOp` を複数キー化 + PG UNNEST tuple-IN / 他 tuple-IN)— C
|
|
139
|
+
2. PG 単一キー relation `= ANY(?::type[])`(dialect 別 relation-IN fragment + 配列 param slot)— C
|
|
140
|
+
3. PG per-parent-limit `CROSS JOIN LATERAL`(v1 アンカー、.rs の ROW_NUMBER は非採用)— C
|
|
141
|
+
4. batch INSERT(PG UNNEST+型推論 / SQLite・MySQL multi-VALUES)を bundle で表現 — B
|
|
142
|
+
5. batch UPDATE(PG UNNEST / MySQL JOIN-VALUES / SQLite CASE-WHEN)+ SKIP-column を bundle で表現 — B
|
|
143
|
+
6. WHERE 条件語彙拡張: subquery(IN/NOT IN/EXISTS/NOT EXISTS/相関)、IS NOT NULL、cast(`::uuid`/array/empty)、raw/§13 escape、tuple/composite IN、immediate inline — A
|
|
144
|
+
7. typed binding(uuid/timestamp/date/json/array/bool)を PG で型付き — A/C
|
|
145
|
+
|
|
146
|
+
**text-breaking(v1 golden と不一致・要確定):**
|
|
147
|
+
8. LIMIT/OFFSET を inline(v1) か param(v2) か — B
|
|
148
|
+
9. OR/空OR/単一要素の括弧規則、boolean literal vs bound を PG アンカーで pin — A
|
|
149
|
+
|
|
150
|
+
**中: per-col `?::sqlCast`、RETURNING `table.col`/MySQL sim、empty-DO-UPDATE→all fallback、`?`→`$N` quote-aware(#42)、FOR UPDATE、relation where-filter、hardLimit、NOT IN(list)/LIKE/BETWEEN/dynamic/custom-op、grouping 複合対応。**
|
|
151
|
+
|
|
152
|
+
**原実装バグは踏襲しない**(§1)。**3実装割れは PG アンカーで確定**(§2)。
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## 進め方
|
|
157
|
+
1. 本チェックリストの各 ❌/⚠️ を issue のサブタスクに(#43 配下)。IR 破壊的変更(1-5)を先に設計確定。
|
|
158
|
+
2. **conformance golden を旧 tuned 実装(.ts LazyRelation/SqlBuilder + .rs、PG SQL)に対して再生成**(縮小基準を捨てる)。
|
|
159
|
+
3. PG から実装→MySQL/SQLite 導出→5言語 render→byte 一致・実 DB(docker) 検証。
|
|
160
|
+
4. #44 の 1.x 最終版 vs v2 ベンチで定量回帰確認。
|
|
161
|
+
|
|
162
|
+
*出所: 旧 `litedbmodel.rs/litedbmodel/src/{condition,values,model,relation,handler,driver/*}.rs`、旧 `litedbmodel/src/{DBConditions,DBValues,DBModel,LazyRelation,drivers/*}.ts`、v2 `litedbmodel/src/scp/{render,dialect,compile-sqlite,compile-dialect,bridge,relation,write-plan,runtime,ir}.ts`。file:line は各 issue に詳細。*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "litedbmodel",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "A lightweight TypeScript ORM for PostgreSQL, MySQL, and SQLite with Active Record pattern",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"url": "git+https://github.com/foo-ogawa/litedbmodel.git"
|
|
81
81
|
},
|
|
82
82
|
"dependencies": {
|
|
83
|
-
"behavior-contracts": "^0.
|
|
83
|
+
"behavior-contracts": "^0.5.0",
|
|
84
84
|
"reflect-metadata": "^0.2.2"
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
@@ -96,9 +96,9 @@
|
|
|
96
96
|
"mysql2": "^3.16.0",
|
|
97
97
|
"pg": "^8.11.3",
|
|
98
98
|
"terser": "^5.44.1",
|
|
99
|
+
"tsx": "^4.22.3",
|
|
99
100
|
"typedoc": "^0.28.15",
|
|
100
101
|
"typedoc-plugin-markdown": "^4.9.0",
|
|
101
|
-
"tsx": "^4.22.3",
|
|
102
102
|
"typescript": "^5.3.0",
|
|
103
103
|
"typescript-eslint": "^8.60.0",
|
|
104
104
|
"vitest": "^4.1.7"
|
package/dist/scp/bridge.d.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* litedbmodel v2 SCP — the WS1↔WS3 Backend-Compile bridge (WS3, #23).
|
|
3
|
-
*
|
|
4
|
-
* WS2 (`authoring.ts`) produces the REAL behavior-contracts `ComponentGraphIR`: a
|
|
5
|
-
* Component's body carries `componentRef` / `map` nodes whose `ports` are Expression IR.
|
|
6
|
-
* The SQL-structural ports (`where`, `select`, `values.<field>`, `set.<field>`, `limit`,
|
|
7
|
-
* `order`, …) are NOT plain scalars — the `where` port is `{arr:[ <cond-expr>, … ]}` where
|
|
8
|
-
* a SKIP-optional condition is a pure `{cond:[c, <frag-expr>, null]}` node (WS2), and a
|
|
9
|
-
* comparison condition is a closed-set Expression `{eq:[<colRef>, <valueExpr>]}` (spec §7).
|
|
10
|
-
*
|
|
11
|
-
* WS1's Backend-Compile (`compile-sqlite.ts`) consumes a structured `SelectDesc` /
|
|
12
|
-
* `Condition[]`. NOTHING produced that shape from the real IR — this module closes that
|
|
13
|
-
* gap. It reads a raw `componentRef`/`map` node's ports directly and lowers them to WS1's
|
|
14
|
-
* `CompiledOperation` (SQL text + fragment tree + static param slots), performing the
|
|
15
|
-
* **SKIP → fragment-existence collapse**: a `{cond:[c, frag, null]}` where-member becomes a
|
|
16
|
-
* fragment guarded by `when: c` (present iff `c` is present), exactly the existence rule
|
|
17
|
-
* `render.ts` implements (dynamic-expansion spec §2). This is the single place that maps
|
|
18
|
-
* the real bc port shape → WS1 compile input; WS1's compiler is unchanged (its golden
|
|
19
|
-
* SQL text is the pinned bar) and now has a producer for its `SelectDesc`/`Condition`.
|
|
20
|
-
*
|
|
21
|
-
* ## WHERE condition interpretation (spec §7) — closed-set ONLY
|
|
22
|
-
*
|
|
23
|
-
* SKIP existence, IN-list membership and IS NULL are **fragment structure, NOT Expression
|
|
24
|
-
* IR opcodes** (catalog `where` port type is `fragment`; bc `expression-ir.md` §4: SKIP is
|
|
25
|
-
* OUTSIDE Expression IR). But bc's authoring lowering (`compileBehaviors`) only emits
|
|
26
|
-
* closed-set Expression IR into a port, so every where-member arrives as a closed-set node.
|
|
27
|
-
* This bridge therefore reads them STRUCTURALLY into fragment kinds WITHOUT inventing any
|
|
28
|
-
* opcode (the hard rule): every member is one of bc's closed operators, decoded here.
|
|
29
|
-
*
|
|
30
|
-
* - `{eq:[<colRef>, null]}` → `{ kind:'isNull', column }` (SQL `col IS NULL`)
|
|
31
|
-
* - `{eq:[<colRef>, <valueExpr>]}` → `{ kind:'eq', column, value:<valueExpr> }`
|
|
32
|
-
* - `{eq:[{ref:[IN_SENTINEL, col]}, <arrExpr>]}` → `{ kind:'in', column, value:<arrExpr> }`
|
|
33
|
-
* - `{lt|le|gt|ge|ne:[<colRef>, v]}` → `{ kind:'cmp', column, op, value:v }`
|
|
34
|
-
* - `{and|or:[m1, m2, …]}` → a nested `{ kind:'group', connector, conditions }`
|
|
35
|
-
* - `{cond:[c, <member>, null]}` → the lowered `<member>` with `skipWhen: c` (SKIP)
|
|
36
|
-
*
|
|
37
|
-
* The LEFT operand of a comparison names the column (spec §7 `{ref:["author_id"]}`): its
|
|
38
|
-
* `ref` path's LAST segment is the column name. The RIGHT operand is the value slot — a
|
|
39
|
-
* closed-set Expression IR node bound at render time. The litedbmodel authoring helpers
|
|
40
|
-
* ({@link import('./authoring-sql')}) produce exactly these closed-set encodings, so the
|
|
41
|
-
* WS2 portability guard passes and this decoder round-trips them to the WS1 fragment tree.
|
|
42
|
-
*/
|
|
43
|
-
/** The reserved column-ref path head that marks an IN-list membership (see module doc). */
|
|
44
|
-
export declare const IN_SENTINEL = "@in";
|
|
45
|
-
import type { Component, ComponentRefNode, MapNode } from './authoring';
|
|
46
|
-
import { type Dialect } from './dialect';
|
|
47
|
-
import type { CompiledOperation } from './ir';
|
|
48
|
-
/** A bc body node that references a catalog component (not a `cond` node). */
|
|
49
|
-
type RefLike = ComponentRefNode | MapNode;
|
|
50
|
-
/**
|
|
51
|
-
* Backend-Compile ONE catalog `componentRef`/`map` body node into a WS1
|
|
52
|
-
* {@link CompiledOperation}. This is the real IR → WS1 compile-input bridge for the
|
|
53
|
-
* SQL CRUD primitives.
|
|
54
|
-
*/
|
|
55
|
-
export declare function compileNode(node: RefLike, dialect?: Dialect): CompiledOperation;
|
|
56
|
-
/**
|
|
57
|
-
* Backend-Compile every catalog node of a component into a `nodeId → CompiledOperation`
|
|
58
|
-
* map. `cond` nodes carry no catalog reference and are skipped (they are pure Expression,
|
|
59
|
-
* evaluated by bc's `runBehavior`). The thin runtime looks up a node's `CompiledOperation`
|
|
60
|
-
* by `ctx.nodeId` when its handler fires.
|
|
61
|
-
*/
|
|
62
|
-
export declare function compileComponentNodes(component: Component, dialect?: Dialect): Map<string, CompiledOperation>;
|
|
63
|
-
export {};
|
|
64
|
-
//# sourceMappingURL=bridge.d.ts.map
|
package/dist/scp/bridge.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/scp/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,2FAA2F;AAC3F,eAAO,MAAM,WAAW,QAAQ,CAAC;AAEjC,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAYxE,OAAO,EAAU,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,iBAAiB,EAAY,MAAM,MAAM,CAAC;AAExD,8EAA8E;AAC9E,KAAK,OAAO,GAAG,gBAAgB,GAAG,OAAO,CAAC;AAiN1C;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,GAAE,OAAgB,GAAG,iBAAiB,CAkDvF;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,GAAE,OAAgB,GAAG,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAOrH"}
|
package/dist/scp/bridge.js
DELETED
|
@@ -1,329 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* litedbmodel v2 SCP — the WS1↔WS3 Backend-Compile bridge (WS3, #23).
|
|
4
|
-
*
|
|
5
|
-
* WS2 (`authoring.ts`) produces the REAL behavior-contracts `ComponentGraphIR`: a
|
|
6
|
-
* Component's body carries `componentRef` / `map` nodes whose `ports` are Expression IR.
|
|
7
|
-
* The SQL-structural ports (`where`, `select`, `values.<field>`, `set.<field>`, `limit`,
|
|
8
|
-
* `order`, …) are NOT plain scalars — the `where` port is `{arr:[ <cond-expr>, … ]}` where
|
|
9
|
-
* a SKIP-optional condition is a pure `{cond:[c, <frag-expr>, null]}` node (WS2), and a
|
|
10
|
-
* comparison condition is a closed-set Expression `{eq:[<colRef>, <valueExpr>]}` (spec §7).
|
|
11
|
-
*
|
|
12
|
-
* WS1's Backend-Compile (`compile-sqlite.ts`) consumes a structured `SelectDesc` /
|
|
13
|
-
* `Condition[]`. NOTHING produced that shape from the real IR — this module closes that
|
|
14
|
-
* gap. It reads a raw `componentRef`/`map` node's ports directly and lowers them to WS1's
|
|
15
|
-
* `CompiledOperation` (SQL text + fragment tree + static param slots), performing the
|
|
16
|
-
* **SKIP → fragment-existence collapse**: a `{cond:[c, frag, null]}` where-member becomes a
|
|
17
|
-
* fragment guarded by `when: c` (present iff `c` is present), exactly the existence rule
|
|
18
|
-
* `render.ts` implements (dynamic-expansion spec §2). This is the single place that maps
|
|
19
|
-
* the real bc port shape → WS1 compile input; WS1's compiler is unchanged (its golden
|
|
20
|
-
* SQL text is the pinned bar) and now has a producer for its `SelectDesc`/`Condition`.
|
|
21
|
-
*
|
|
22
|
-
* ## WHERE condition interpretation (spec §7) — closed-set ONLY
|
|
23
|
-
*
|
|
24
|
-
* SKIP existence, IN-list membership and IS NULL are **fragment structure, NOT Expression
|
|
25
|
-
* IR opcodes** (catalog `where` port type is `fragment`; bc `expression-ir.md` §4: SKIP is
|
|
26
|
-
* OUTSIDE Expression IR). But bc's authoring lowering (`compileBehaviors`) only emits
|
|
27
|
-
* closed-set Expression IR into a port, so every where-member arrives as a closed-set node.
|
|
28
|
-
* This bridge therefore reads them STRUCTURALLY into fragment kinds WITHOUT inventing any
|
|
29
|
-
* opcode (the hard rule): every member is one of bc's closed operators, decoded here.
|
|
30
|
-
*
|
|
31
|
-
* - `{eq:[<colRef>, null]}` → `{ kind:'isNull', column }` (SQL `col IS NULL`)
|
|
32
|
-
* - `{eq:[<colRef>, <valueExpr>]}` → `{ kind:'eq', column, value:<valueExpr> }`
|
|
33
|
-
* - `{eq:[{ref:[IN_SENTINEL, col]}, <arrExpr>]}` → `{ kind:'in', column, value:<arrExpr> }`
|
|
34
|
-
* - `{lt|le|gt|ge|ne:[<colRef>, v]}` → `{ kind:'cmp', column, op, value:v }`
|
|
35
|
-
* - `{and|or:[m1, m2, …]}` → a nested `{ kind:'group', connector, conditions }`
|
|
36
|
-
* - `{cond:[c, <member>, null]}` → the lowered `<member>` with `skipWhen: c` (SKIP)
|
|
37
|
-
*
|
|
38
|
-
* The LEFT operand of a comparison names the column (spec §7 `{ref:["author_id"]}`): its
|
|
39
|
-
* `ref` path's LAST segment is the column name. The RIGHT operand is the value slot — a
|
|
40
|
-
* closed-set Expression IR node bound at render time. The litedbmodel authoring helpers
|
|
41
|
-
* ({@link import('./authoring-sql')}) produce exactly these closed-set encodings, so the
|
|
42
|
-
* WS2 portability guard passes and this decoder round-trips them to the WS1 fragment tree.
|
|
43
|
-
*/
|
|
44
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
-
exports.IN_SENTINEL = void 0;
|
|
46
|
-
exports.compileNode = compileNode;
|
|
47
|
-
exports.compileComponentNodes = compileComponentNodes;
|
|
48
|
-
/** The reserved column-ref path head that marks an IN-list membership (see module doc). */
|
|
49
|
-
exports.IN_SENTINEL = '@in';
|
|
50
|
-
const compile_sqlite_1 = require("./compile-sqlite");
|
|
51
|
-
const compile_dialect_1 = require("./compile-dialect");
|
|
52
|
-
const dialect_1 = require("./dialect");
|
|
53
|
-
function isMap(n) {
|
|
54
|
-
return 'map' in n;
|
|
55
|
-
}
|
|
56
|
-
/** The catalog-name + ports of a `componentRef`/`map` body node (uniform view). */
|
|
57
|
-
function nodeRef(n) {
|
|
58
|
-
return isMap(n) ? { component: n.map.component, ports: n.map.ports } : { component: n.component, ports: n.ports };
|
|
59
|
-
}
|
|
60
|
-
// ── Port readers (structural — no evaluation) ─────────────────────────────────
|
|
61
|
-
/** A port that must be a literal string (`table`, `order`, `group`, `returning`). */
|
|
62
|
-
function stringPort(ports, name) {
|
|
63
|
-
const v = ports[name];
|
|
64
|
-
if (v === undefined)
|
|
65
|
-
return undefined;
|
|
66
|
-
if (typeof v !== 'string') {
|
|
67
|
-
throw new Error(`bridge: port '${name}' must be a literal string in the IR (got ${JSON.stringify(v)})`);
|
|
68
|
-
}
|
|
69
|
-
return v;
|
|
70
|
-
}
|
|
71
|
-
/** A `{arr:[...]}` port → its element array (a bc-lowered literal array). */
|
|
72
|
-
function arrPort(ports, name) {
|
|
73
|
-
const v = ports[name];
|
|
74
|
-
if (v === undefined)
|
|
75
|
-
return undefined;
|
|
76
|
-
if (typeof v === 'object' && v !== null && 'arr' in v && Array.isArray(v.arr)) {
|
|
77
|
-
return v.arr;
|
|
78
|
-
}
|
|
79
|
-
throw new Error(`bridge: port '${name}' must be an {arr:[...]} literal in the IR (got ${JSON.stringify(v)})`);
|
|
80
|
-
}
|
|
81
|
-
/** `select` / `returning` string-array port → `string[]` (elements must be literals). */
|
|
82
|
-
function stringArrayPort(ports, name) {
|
|
83
|
-
const arr = arrPort(ports, name);
|
|
84
|
-
if (arr === undefined)
|
|
85
|
-
return undefined;
|
|
86
|
-
return arr.map((e) => {
|
|
87
|
-
if (typeof e !== 'string')
|
|
88
|
-
throw new Error(`bridge: '${name}' entries must be literal strings (got ${JSON.stringify(e)})`);
|
|
89
|
-
return e;
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
/** The single-key operator name of an Expression node, or undefined if not a 1-key object. */
|
|
93
|
-
function opKey(node) {
|
|
94
|
-
if (node === null || typeof node !== 'object' || Array.isArray(node))
|
|
95
|
-
return undefined;
|
|
96
|
-
const keys = Object.keys(node);
|
|
97
|
-
return keys.length === 1 ? keys[0] : undefined;
|
|
98
|
-
}
|
|
99
|
-
/** The column name carried by a `ref`/`refOpt` path (its LAST segment — spec §7). */
|
|
100
|
-
function columnOf(node, ctx) {
|
|
101
|
-
const op = opKey(node);
|
|
102
|
-
if (op !== 'ref' && op !== 'refOpt') {
|
|
103
|
-
throw new Error(`bridge: ${ctx}: the column operand must be a {ref:[...]} / {refOpt:[...]} path, got ${JSON.stringify(node)}`);
|
|
104
|
-
}
|
|
105
|
-
const path = node[op];
|
|
106
|
-
if (!Array.isArray(path) || path.length === 0 || typeof path[path.length - 1] !== 'string') {
|
|
107
|
-
throw new Error(`bridge: ${ctx}: column ref path must be a non-empty string path`);
|
|
108
|
-
}
|
|
109
|
-
return path[path.length - 1];
|
|
110
|
-
}
|
|
111
|
-
const CMP_OPS = {
|
|
112
|
-
lt: '<',
|
|
113
|
-
le: '<=',
|
|
114
|
-
gt: '>',
|
|
115
|
-
ge: '>=',
|
|
116
|
-
ne: '<>',
|
|
117
|
-
};
|
|
118
|
-
/**
|
|
119
|
-
* If a column operand is an IN-list membership marker (its `ref`/`refOpt` path head is
|
|
120
|
-
* {@link IN_SENTINEL}), return the real column name (the segment AFTER the sentinel);
|
|
121
|
-
* otherwise undefined. The sentinel keeps IN-list expressible with only the closed-set
|
|
122
|
-
* `eq` + `ref` operators (no invented `in` opcode).
|
|
123
|
-
*/
|
|
124
|
-
function inSentinelColumn(node) {
|
|
125
|
-
const op = opKey(node);
|
|
126
|
-
if (op !== 'ref' && op !== 'refOpt')
|
|
127
|
-
return undefined;
|
|
128
|
-
const path = node[op];
|
|
129
|
-
if (Array.isArray(path) && path.length >= 2 && path[0] === exports.IN_SENTINEL && typeof path[path.length - 1] === 'string') {
|
|
130
|
-
return path[path.length - 1];
|
|
131
|
-
}
|
|
132
|
-
return undefined;
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Lower ONE where-member Expression node to a WS1 {@link Condition} (structural read).
|
|
136
|
-
* A `{cond:[c, member, null]}` node is the SKIP-optional collapse: the inner `member` is
|
|
137
|
-
* lowered and its `skipWhen` set to `c` (present iff `c` is present — dynamic-expansion §2).
|
|
138
|
-
*/
|
|
139
|
-
function lowerWhereMember(node, at) {
|
|
140
|
-
const op = opKey(node);
|
|
141
|
-
if (op === undefined) {
|
|
142
|
-
throw new Error(`bridge: ${at}: a where member must be a single-operator Expression node, got ${JSON.stringify(node)}`);
|
|
143
|
-
}
|
|
144
|
-
if (op === 'cond') {
|
|
145
|
-
// SKIP-optional: {cond:[c, <member>, null]}. The else branch MUST be null (absence).
|
|
146
|
-
const args = node.cond;
|
|
147
|
-
if (!Array.isArray(args) || args.length !== 3 || args[2] !== null) {
|
|
148
|
-
throw new Error(`bridge: ${at}: a SKIP-optional condition must be {cond:[c, <member>, null]} (else = null)`);
|
|
149
|
-
}
|
|
150
|
-
const inner = lowerWhereMember(args[1], `${at}.cond.then`);
|
|
151
|
-
if (inner.skipWhen !== undefined) {
|
|
152
|
-
throw new Error(`bridge: ${at}: nested SKIP guards are not supported (one cond per member)`);
|
|
153
|
-
}
|
|
154
|
-
return { ...inner, skipWhen: args[0] };
|
|
155
|
-
}
|
|
156
|
-
if (op === 'and' || op === 'or') {
|
|
157
|
-
// A nested group: {and|or:[m1, m2, ...]} → a Condition group.
|
|
158
|
-
const args = node[op];
|
|
159
|
-
if (!Array.isArray(args) || args.length < 2) {
|
|
160
|
-
throw new Error(`bridge: ${at}: '${op}' group expects >= 2 members`);
|
|
161
|
-
}
|
|
162
|
-
return {
|
|
163
|
-
kind: 'group',
|
|
164
|
-
connector: op === 'and' ? 'AND' : 'OR',
|
|
165
|
-
conditions: args.map((m, i) => lowerWhereMember(m, `${at}.${op}[${i}]`)),
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
if (op === 'eq') {
|
|
169
|
-
const [col, val] = binOperands(node, op, at);
|
|
170
|
-
// IN-list membership: the column ref path head is the reserved IN_SENTINEL.
|
|
171
|
-
const inCol = inSentinelColumn(col);
|
|
172
|
-
if (inCol !== undefined) {
|
|
173
|
-
return { kind: 'in', column: inCol, value: val };
|
|
174
|
-
}
|
|
175
|
-
// IS NULL: `eq(col, null)` (a null literal RHS) → SQL `col IS NULL` (v1 parity).
|
|
176
|
-
if (val === null) {
|
|
177
|
-
return { kind: 'isNull', column: columnOf(col, at) };
|
|
178
|
-
}
|
|
179
|
-
return { kind: 'eq', column: columnOf(col, at), value: val };
|
|
180
|
-
}
|
|
181
|
-
if (op in CMP_OPS) {
|
|
182
|
-
const [col, val] = binOperands(node, op, at);
|
|
183
|
-
return { kind: 'cmp', column: columnOf(col, at), op: CMP_OPS[op], value: val };
|
|
184
|
-
}
|
|
185
|
-
throw new Error(`bridge: ${at}: unsupported where operator '${op}' (supported: eq/ne/lt/le/gt/ge/and/or/cond; IN via ${exports.IN_SENTINEL} column head; IS NULL via eq(col,null))`);
|
|
186
|
-
}
|
|
187
|
-
/** Read the two operands of a binary comparison node, fail-closed on arity. */
|
|
188
|
-
function binOperands(node, op, at) {
|
|
189
|
-
const args = node[op];
|
|
190
|
-
if (!Array.isArray(args) || args.length !== 2) {
|
|
191
|
-
throw new Error(`bridge: ${at}: '${op}' expects exactly 2 operands`);
|
|
192
|
-
}
|
|
193
|
-
return [args[0], args[1]];
|
|
194
|
-
}
|
|
195
|
-
/** Lower the `where` port (`{arr:[...]}` of member nodes) to a WS1 `Condition[]`. */
|
|
196
|
-
function lowerWherePort(ports, at) {
|
|
197
|
-
const arr = arrPort(ports, 'where');
|
|
198
|
-
if (arr === undefined)
|
|
199
|
-
return undefined;
|
|
200
|
-
return arr.map((m, i) => lowerWhereMember(m, `${at}.where[${i}]`));
|
|
201
|
-
}
|
|
202
|
-
// ── The write value/set record families (`values.<field>` / `set.<field>`) ────
|
|
203
|
-
/**
|
|
204
|
-
* Collect a flattened write record family (`<prefix>.<field>` ports) → an ordered
|
|
205
|
-
* `Record<field, ExprNode>`. Field order = declaration (insertion) order of the ports,
|
|
206
|
-
* which is the SQL column order the golden pins.
|
|
207
|
-
*/
|
|
208
|
-
function collectFamily(ports, prefix) {
|
|
209
|
-
const out = {};
|
|
210
|
-
for (const k of Object.keys(ports)) {
|
|
211
|
-
if (k.startsWith(`${prefix}.`))
|
|
212
|
-
out[k.slice(prefix.length + 1)] = ports[k];
|
|
213
|
-
}
|
|
214
|
-
return out;
|
|
215
|
-
}
|
|
216
|
-
/** Parse the Insert conflict ports into WS1's `onConflict` / `onConflictAction`. */
|
|
217
|
-
function conflictOf(ports) {
|
|
218
|
-
const onConflict = stringPort(ports, 'onConflict');
|
|
219
|
-
const action = stringPort(ports, 'onConflictAction');
|
|
220
|
-
if (onConflict === undefined)
|
|
221
|
-
return {};
|
|
222
|
-
const keys = onConflict.split(',').map((s) => s.trim()).filter((s) => s.length > 0);
|
|
223
|
-
if (action === undefined || action === 'ignore') {
|
|
224
|
-
return { onConflict: keys, onConflictAction: 'ignore' };
|
|
225
|
-
}
|
|
226
|
-
if (action === 'update') {
|
|
227
|
-
// Update all inserted columns except the conflict keys (SQLite `excluded.*` upsert).
|
|
228
|
-
return { onConflict: keys, onConflictAction: { updateColumns: 'all' } };
|
|
229
|
-
}
|
|
230
|
-
// `update:col1,col2` — explicit update column list.
|
|
231
|
-
const m = /^update:(.+)$/.exec(action);
|
|
232
|
-
if (m) {
|
|
233
|
-
return { onConflict: keys, onConflictAction: { updateColumns: m[1].split(',').map((s) => s.trim()) } };
|
|
234
|
-
}
|
|
235
|
-
throw new Error(`bridge: unsupported onConflictAction '${action}' (expected 'ignore' / 'update' / 'update:col,col')`);
|
|
236
|
-
}
|
|
237
|
-
/** RETURNING port (`"id, title"` literal) → `string[]`. */
|
|
238
|
-
function returningOf(ports) {
|
|
239
|
-
const r = stringPort(ports, 'returning');
|
|
240
|
-
if (r === undefined)
|
|
241
|
-
return undefined;
|
|
242
|
-
return r.split(',').map((s) => s.trim()).filter((s) => s.length > 0);
|
|
243
|
-
}
|
|
244
|
-
// ── Node → CompiledOperation ──────────────────────────────────────────────────
|
|
245
|
-
/**
|
|
246
|
-
* Backend-Compile ONE catalog `componentRef`/`map` body node into a WS1
|
|
247
|
-
* {@link CompiledOperation}. This is the real IR → WS1 compile-input bridge for the
|
|
248
|
-
* SQL CRUD primitives.
|
|
249
|
-
*/
|
|
250
|
-
function compileNode(node, dialect = dialect_1.SQLITE) {
|
|
251
|
-
const { component, ports } = nodeRef(node);
|
|
252
|
-
const table = stringPort(ports, 'table');
|
|
253
|
-
if (table === undefined)
|
|
254
|
-
throw new Error(`bridge: ${component} node requires a literal 'table' port`);
|
|
255
|
-
const at = `${component}`;
|
|
256
|
-
switch (component) {
|
|
257
|
-
case 'Select': {
|
|
258
|
-
const select = stringArrayPort(ports, 'select');
|
|
259
|
-
if (select === undefined)
|
|
260
|
-
throw new Error(`bridge: Select requires a 'select' {arr:[...]} port`);
|
|
261
|
-
const desc = { table, select };
|
|
262
|
-
const where = lowerWherePort(ports, at);
|
|
263
|
-
if (where !== undefined)
|
|
264
|
-
desc.where = where;
|
|
265
|
-
const order = stringPort(ports, 'order');
|
|
266
|
-
if (order !== undefined)
|
|
267
|
-
desc.order = order;
|
|
268
|
-
const group = stringPort(ports, 'group');
|
|
269
|
-
if (group !== undefined)
|
|
270
|
-
desc.group = group;
|
|
271
|
-
if (ports.limit !== undefined)
|
|
272
|
-
desc.limit = ports.limit;
|
|
273
|
-
if (ports.offset !== undefined)
|
|
274
|
-
desc.offset = ports.offset;
|
|
275
|
-
return (0, compile_sqlite_1.compileSelect)(desc);
|
|
276
|
-
}
|
|
277
|
-
case 'Insert': {
|
|
278
|
-
const values = collectFamily(ports, 'values');
|
|
279
|
-
if (Object.keys(values).length === 0)
|
|
280
|
-
throw new Error(`bridge: Insert requires at least one 'values.<field>' port`);
|
|
281
|
-
const desc = { table, values, ...conflictOf(ports) };
|
|
282
|
-
const returning = returningOf(ports);
|
|
283
|
-
if (returning !== undefined)
|
|
284
|
-
desc.returning = returning;
|
|
285
|
-
return (0, compile_dialect_1.compileInsertFor)(dialect, desc);
|
|
286
|
-
}
|
|
287
|
-
case 'Update': {
|
|
288
|
-
const set = collectFamily(ports, 'set');
|
|
289
|
-
if (Object.keys(set).length === 0)
|
|
290
|
-
throw new Error(`bridge: Update requires at least one 'set.<field>' port`);
|
|
291
|
-
const where = lowerWherePort(ports, at);
|
|
292
|
-
if (where === undefined)
|
|
293
|
-
throw new Error(`bridge: Update requires a 'where' port`);
|
|
294
|
-
const desc = { table, set, where };
|
|
295
|
-
const returning = returningOf(ports);
|
|
296
|
-
if (returning !== undefined)
|
|
297
|
-
desc.returning = returning;
|
|
298
|
-
return (0, compile_sqlite_1.compileUpdate)(desc);
|
|
299
|
-
}
|
|
300
|
-
case 'Delete': {
|
|
301
|
-
const where = lowerWherePort(ports, at);
|
|
302
|
-
if (where === undefined)
|
|
303
|
-
throw new Error(`bridge: Delete requires a 'where' port`);
|
|
304
|
-
const desc = { table, where };
|
|
305
|
-
const returning = returningOf(ports);
|
|
306
|
-
if (returning !== undefined)
|
|
307
|
-
desc.returning = returning;
|
|
308
|
-
return (0, compile_sqlite_1.compileDelete)(desc);
|
|
309
|
-
}
|
|
310
|
-
default:
|
|
311
|
-
throw new Error(`bridge: catalog component '${component}' has no Backend-Compile (SQL CRUD only: Select/Insert/Update/Delete)`);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
/**
|
|
315
|
-
* Backend-Compile every catalog node of a component into a `nodeId → CompiledOperation`
|
|
316
|
-
* map. `cond` nodes carry no catalog reference and are skipped (they are pure Expression,
|
|
317
|
-
* evaluated by bc's `runBehavior`). The thin runtime looks up a node's `CompiledOperation`
|
|
318
|
-
* by `ctx.nodeId` when its handler fires.
|
|
319
|
-
*/
|
|
320
|
-
function compileComponentNodes(component, dialect = dialect_1.SQLITE) {
|
|
321
|
-
const out = new Map();
|
|
322
|
-
for (const n of component.body) {
|
|
323
|
-
if ('cond' in n)
|
|
324
|
-
continue;
|
|
325
|
-
out.set(n.id, compileNode(n, dialect));
|
|
326
|
-
}
|
|
327
|
-
return out;
|
|
328
|
-
}
|
|
329
|
-
//# sourceMappingURL=bridge.js.map
|
package/dist/scp/bridge.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/scp/bridge.ts"],"names":[],"mappings":"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"}
|