litedbmodel 2.0.2 → 2.2.0
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/README.md +7 -0
- package/dist/DBConditions.d.ts.map +1 -1
- package/dist/DBConditions.js +16 -1
- package/dist/DBConditions.js.map +1 -1
- package/dist/DBHandler.d.ts.map +1 -1
- package/dist/DBHandler.js +6 -0
- package/dist/DBHandler.js.map +1 -1
- package/dist/DBModel.d.ts +84 -2
- package/dist/DBModel.d.ts.map +1 -1
- package/dist/DBModel.js +312 -29
- package/dist/DBModel.js.map +1 -1
- package/dist/decorators.d.ts +52 -0
- package/dist/decorators.d.ts.map +1 -1
- package/dist/decorators.js +127 -24
- package/dist/decorators.js.map +1 -1
- package/dist/drivers/mysql.d.ts.map +1 -1
- package/dist/drivers/mysql.js +12 -2
- package/dist/drivers/mysql.js.map +1 -1
- package/dist/drivers/postgres.d.ts.map +1 -1
- package/dist/drivers/postgres.js +13 -2
- package/dist/drivers/postgres.js.map +1 -1
- package/dist/drivers/sqlite.d.ts +2 -0
- package/dist/drivers/sqlite.d.ts.map +1 -1
- package/dist/drivers/sqlite.js +49 -4
- package/dist/drivers/sqlite.js.map +1 -1
- package/dist/index.cjs +10741 -0
- package/dist/index.d.cts +1 -0
- package/dist/scp/coltype.d.ts +108 -0
- package/dist/scp/coltype.d.ts.map +1 -1
- package/dist/scp/coltype.js +293 -6
- package/dist/scp/coltype.js.map +1 -1
- package/dist/scp/connection-routing.d.ts +312 -0
- package/dist/scp/connection-routing.d.ts.map +1 -0
- package/dist/scp/connection-routing.js +394 -0
- package/dist/scp/connection-routing.js.map +1 -0
- package/dist/scp/dbmodel-runtime.d.ts +101 -0
- package/dist/scp/dbmodel-runtime.d.ts.map +1 -0
- package/dist/scp/dbmodel-runtime.js +174 -0
- package/dist/scp/dbmodel-runtime.js.map +1 -0
- package/dist/scp/decorator-adapter.d.ts +196 -0
- package/dist/scp/decorator-adapter.d.ts.map +1 -0
- package/dist/scp/decorator-adapter.js +286 -0
- package/dist/scp/decorator-adapter.js.map +1 -0
- package/dist/scp/emit/emitter.d.ts +108 -0
- package/dist/scp/emit/emitter.d.ts.map +1 -0
- package/dist/scp/emit/emitter.js +782 -0
- package/dist/scp/emit/emitter.js.map +1 -0
- package/dist/scp/emit/endpoint.d.ts +248 -0
- package/dist/scp/emit/endpoint.d.ts.map +1 -0
- package/dist/scp/emit/endpoint.js +20 -0
- package/dist/scp/emit/endpoint.js.map +1 -0
- package/dist/scp/emit/index.d.ts +11 -0
- package/dist/scp/emit/index.d.ts.map +1 -0
- package/dist/scp/emit/index.js +13 -0
- package/dist/scp/emit/index.js.map +1 -0
- package/dist/scp/errors.d.ts +45 -1
- package/dist/scp/errors.d.ts.map +1 -1
- package/dist/scp/errors.js +47 -1
- package/dist/scp/errors.js.map +1 -1
- package/dist/scp/exec-context.d.ts +390 -0
- package/dist/scp/exec-context.d.ts.map +1 -0
- package/dist/scp/exec-context.js +540 -0
- package/dist/scp/exec-context.js.map +1 -0
- package/dist/scp/grouping.d.ts +32 -0
- package/dist/scp/grouping.d.ts.map +1 -0
- package/dist/scp/grouping.js +0 -0
- package/dist/scp/grouping.js.map +1 -0
- package/dist/scp/index.cjs +6432 -17579
- package/dist/scp/index.d.cts +1 -0
- package/dist/scp/index.d.mts +1 -0
- package/dist/scp/index.d.ts +51 -52
- package/dist/scp/index.d.ts.map +1 -1
- package/dist/scp/index.js +189 -152
- package/dist/scp/index.js.map +1 -1
- package/dist/scp/index.mjs +6067 -3659
- package/dist/scp/leaf-transport.d.ts +50 -0
- package/dist/scp/leaf-transport.d.ts.map +1 -0
- package/dist/scp/leaf-transport.js +92 -0
- package/dist/scp/leaf-transport.js.map +1 -0
- package/dist/scp/leaves.d.ts +174 -0
- package/dist/scp/leaves.d.ts.map +1 -0
- package/dist/scp/leaves.js +287 -0
- package/dist/scp/leaves.js.map +1 -0
- package/dist/scp/limit-config.d.ts +118 -0
- package/dist/scp/limit-config.d.ts.map +1 -0
- package/dist/scp/limit-config.js +126 -0
- package/dist/scp/limit-config.js.map +1 -0
- package/dist/scp/makesql/compile-relation.d.ts +49 -23
- package/dist/scp/makesql/compile-relation.d.ts.map +1 -1
- package/dist/scp/makesql/compile-relation.js +101 -76
- package/dist/scp/makesql/compile-relation.js.map +1 -1
- package/dist/scp/makesql/compile-select.d.ts +45 -10
- package/dist/scp/makesql/compile-select.d.ts.map +1 -1
- package/dist/scp/makesql/compile-select.js +50 -10
- package/dist/scp/makesql/compile-select.js.map +1 -1
- package/dist/scp/makesql/handler.d.ts +1 -1
- package/dist/scp/makesql/handler.d.ts.map +1 -1
- package/dist/scp/makesql/index.d.ts +7 -10
- package/dist/scp/makesql/index.d.ts.map +1 -1
- package/dist/scp/makesql/index.js +19 -30
- package/dist/scp/makesql/index.js.map +1 -1
- package/dist/scp/makesql/json-array.d.ts +65 -0
- package/dist/scp/makesql/json-array.d.ts.map +1 -1
- package/dist/scp/makesql/json-array.js +99 -10
- package/dist/scp/makesql/json-array.js.map +1 -1
- package/dist/scp/makesql/json-batch.d.ts.map +1 -1
- package/dist/scp/makesql/json-batch.js +21 -19
- package/dist/scp/makesql/json-batch.js.map +1 -1
- package/dist/scp/makesql/makesql.d.ts +1 -1
- package/dist/scp/makesql/makesql.d.ts.map +1 -1
- package/dist/scp/makesql/mysql-returning.d.ts +93 -0
- package/dist/scp/makesql/mysql-returning.d.ts.map +1 -0
- package/dist/scp/makesql/mysql-returning.js +215 -0
- package/dist/scp/makesql/mysql-returning.js.map +1 -0
- package/dist/scp/makesql/outtype.d.ts +75 -34
- package/dist/scp/makesql/outtype.d.ts.map +1 -1
- package/dist/scp/makesql/outtype.js +91 -118
- package/dist/scp/makesql/outtype.js.map +1 -1
- package/dist/scp/makesql/pool-executor.d.ts +135 -13
- package/dist/scp/makesql/pool-executor.d.ts.map +1 -1
- package/dist/scp/makesql/pool-executor.js +229 -21
- package/dist/scp/makesql/pool-executor.js.map +1 -1
- package/dist/scp/makesql/tx.d.ts +107 -22
- package/dist/scp/makesql/tx.d.ts.map +1 -1
- package/dist/scp/makesql/tx.js +451 -97
- package/dist/scp/makesql/tx.js.map +1 -1
- package/dist/scp/makesql/writeouttype.d.ts +7 -8
- package/dist/scp/makesql/writeouttype.d.ts.map +1 -1
- package/dist/scp/makesql/writeouttype.js +8 -7
- package/dist/scp/makesql/writeouttype.js.map +1 -1
- package/dist/scp/middleware.d.ts +287 -0
- package/dist/scp/middleware.d.ts.map +1 -0
- package/dist/scp/middleware.js +358 -0
- package/dist/scp/middleware.js.map +1 -0
- package/dist/scp/relation.d.ts +80 -9
- package/dist/scp/relation.d.ts.map +1 -1
- package/dist/scp/relation.js +198 -78
- package/dist/scp/relation.js.map +1 -1
- package/dist/scp/tx-options.d.ts +136 -0
- package/dist/scp/tx-options.d.ts.map +1 -0
- package/dist/scp/tx-options.js +184 -0
- package/dist/scp/tx-options.js.map +1 -0
- package/dist/scp/write-bundle.d.ts +131 -0
- package/dist/scp/write-bundle.d.ts.map +1 -0
- package/dist/scp/write-bundle.js +160 -0
- package/dist/scp/write-bundle.js.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/docs/BENCHMARK.md +58 -56
- package/docs/benchmark-chart.svg +166 -166
- package/docs/design/phase-a-execution-context.md +139 -0
- package/package.json +16 -9
- package/dist/scp/authoring-sql.d.ts +0 -134
- package/dist/scp/authoring-sql.d.ts.map +0 -1
- package/dist/scp/authoring-sql.js +0 -191
- package/dist/scp/authoring-sql.js.map +0 -1
- package/dist/scp/authoring.d.ts +0 -155
- package/dist/scp/authoring.d.ts.map +0 -1
- package/dist/scp/authoring.js +0 -162
- package/dist/scp/authoring.js.map +0 -1
- package/dist/scp/catalog.d.ts +0 -94
- package/dist/scp/catalog.d.ts.map +0 -1
- package/dist/scp/catalog.js +0 -234
- package/dist/scp/catalog.js.map +0 -1
- package/dist/scp/codegen.d.ts +0 -189
- package/dist/scp/codegen.d.ts.map +0 -1
- package/dist/scp/codegen.js +0 -421
- package/dist/scp/codegen.js.map +0 -1
- package/dist/scp/find-filter-guard.d.ts +0 -68
- package/dist/scp/find-filter-guard.d.ts.map +0 -1
- package/dist/scp/find-filter-guard.js +0 -88
- package/dist/scp/find-filter-guard.js.map +0 -1
- package/dist/scp/guard.d.ts +0 -43
- package/dist/scp/guard.d.ts.map +0 -1
- package/dist/scp/guard.js +0 -134
- package/dist/scp/guard.js.map +0 -1
- package/dist/scp/makesql/authoring-compile.d.ts +0 -90
- package/dist/scp/makesql/authoring-compile.d.ts.map +0 -1
- package/dist/scp/makesql/authoring-compile.js +0 -494
- package/dist/scp/makesql/authoring-compile.js.map +0 -1
- package/dist/scp/makesql/ir.d.ts +0 -42
- package/dist/scp/makesql/ir.d.ts.map +0 -1
- package/dist/scp/makesql/ir.js +0 -66
- package/dist/scp/makesql/ir.js.map +0 -1
- package/dist/scp/makesql/static-bundle.d.ts +0 -187
- package/dist/scp/makesql/static-bundle.d.ts.map +0 -1
- package/dist/scp/makesql/static-bundle.js +0 -1113
- package/dist/scp/makesql/static-bundle.js.map +0 -1
- package/dist/scp/runtime.d.ts +0 -242
- package/dist/scp/runtime.d.ts.map +0 -1
- package/dist/scp/runtime.js +0 -400
- package/dist/scp/runtime.js.map +0 -1
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Phase A 設計: ExecutionContext + 中央 execute/query seam + 接続コンテキスト + 並行 tx 修正
|
|
2
|
+
|
|
3
|
+
**対象**: litedbmodel v2 → beta(v1 parity)Epic #74 の基盤フェーズ。tx(#69)・middleware(#70)・reader/writer/複数DB(#72)・config(#72) の全てがこの上に載る。**5 native 言語(TS/rust/go/py/php)共通契約**。設計参照: v1 TS(`AsyncLocalStorage`)・v1 rust(`litedbmodel.rs` `PoolTransaction`)・graphddb。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. 現状(seam の素地と欠落)
|
|
8
|
+
|
|
9
|
+
全 5 runtime が共通形:
|
|
10
|
+
- `executeBundle(bundle, input, driver/db)` … read(TS `executeBundle`→`executeReadGraph`、go `ExecuteBundle`、py `execute_bundle`、php `Runtime::executeBundle`、rust `execute_bundle`)
|
|
11
|
+
- `executeTransactionBundle(bundle, input, driver/db)` … write/tx
|
|
12
|
+
- SQL 実行は `driver.prepare(sql).all()/run()`(go は `db.Query/Exec`、php は `PDO`)
|
|
13
|
+
|
|
14
|
+
**欠落**:
|
|
15
|
+
- 全 SQL が通る**中央 seam が無い**(各所で driver を直接叩く)→ middleware 挿入点が無い。
|
|
16
|
+
- **接続コンテキストが無い**(driver を生で渡すだけ)→ tx スコープ・reader/writer・複数DB ルーティングを表現できない。
|
|
17
|
+
- **tx が driver グローバル単一スロット**(rust `writer: Mutex<Option>`、py `driver.py:369` 等)→ **並行 tx 汚染バグ**。
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 2. 中核設計: `ExecutionContext` を driver の代わりに通す
|
|
22
|
+
|
|
23
|
+
`executeBundle`/`executeTransactionBundle`/relation walker が受け取るのを **生 driver → `ExecutionContext`(以下 ctx)** に変える。ctx が保持するもの:
|
|
24
|
+
|
|
25
|
+
1. **接続プロバイダ**(`connectionFor(intent)`): この文にどの接続を使うかを解決(tx所有 / reader / writer-sticky / named-DB)。
|
|
26
|
+
2. **middleware chain**: 全 SQL をラップするフック列。
|
|
27
|
+
3. **設定**(timeout/limits 等、Phase C/E で拡張)。
|
|
28
|
+
|
|
29
|
+
**中央 seam(5 言語共通の 2 関数)**:
|
|
30
|
+
```
|
|
31
|
+
execute(ctx, sql, params) -> Rows // read(SELECT)
|
|
32
|
+
run(ctx, sql, params) -> RunInfo // write(INSERT/UPDATE/DELETE, BEGIN/COMMIT)
|
|
33
|
+
```
|
|
34
|
+
両関数の中身(共通契約):
|
|
35
|
+
```
|
|
36
|
+
seam(ctx, sql, params, intent):
|
|
37
|
+
return ctx.middleware.wrap(sql, params, (sql, params) => # ① middleware chain
|
|
38
|
+
conn = ctx.connectionFor(intent) # ② 接続解決(tx/reader/writer/db)
|
|
39
|
+
return conn.exec(sql, params) # ③ 実行(唯一の driver 接点)
|
|
40
|
+
)
|
|
41
|
+
```
|
|
42
|
+
→ **全 SQL がこの 1 点を通る**。middleware も接続解決もここに集約。既存の `driver.prepare().all()` 直呼びを全て `execute/run(ctx, …)` に置換。
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 3. 接続コンテキストモデル(per-execution・言語別)
|
|
47
|
+
|
|
48
|
+
**原則: 接続は「実行スコープ」が所有する。driver グローバルスロットは廃止。並行実行(HTTP req/tx)は各自別接続。**
|
|
49
|
+
|
|
50
|
+
`connectionFor(intent)` の解決優先順位(v1 準拠、`DBModel.ts:313` の順):
|
|
51
|
+
1. **アクティブ tx の接続**(tx スコープ内なら必ずその接続)
|
|
52
|
+
2. **withWriter スコープ** / **writer-sticky**(直近 tx 後 `writerStickyDuration` 内の read は writer へ)
|
|
53
|
+
3. **read=reader pool / write=writer pool**(reader/writer 分離時)
|
|
54
|
+
4. **named-DB ルーティング**(model→connection、複数DB時)→ 対象 DB の pool
|
|
55
|
+
|
|
56
|
+
言語別の「実行スコープ所有」実装:
|
|
57
|
+
| 言語 | ctx 伝播 | tx 接続所有 |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| **TS** | `AsyncLocalStorage<Ctx>`(v1 と同じ、非同期境界を跨ぐ) | tx が接続を ALS に束ねる(v1 `txContext.run`) |
|
|
60
|
+
| **rust** | ctx を**引数で明示 thread**(or `tokio::task_local`)。current-thread runtime(v1rs 準拠、block_on 軽量化) | `PoolTransaction`(接続所有ハンドル、v1 rust `handler.rs`)を ctx が保持 |
|
|
61
|
+
| **go** | `context.Context` に ctx を載せる | `*sql.Tx`(接続所有)を ctx が保持 |
|
|
62
|
+
| **py** | `contextvars.ContextVar<Ctx>` | tx 接続を contextvar に束ねる |
|
|
63
|
+
| **php** | ctx を**明示引数**(PHP は 1 req 1 プロセスで並行 tx 無し、但し接続所有は同契約) | tx が PDO 接続を ctx 内で所有 |
|
|
64
|
+
|
|
65
|
+
**tx の per-execution 所有(並行 tx バグ根治)**:
|
|
66
|
+
```
|
|
67
|
+
withTransaction(ctx, opts, fn) -> R:
|
|
68
|
+
conn = pool(writer, targetDB).acquire() # tx 専用に 1 接続取得
|
|
69
|
+
txctx = ctx.withConnection(conn, tx=true) # スコープに束ねる(ALS/task-local/owned)
|
|
70
|
+
conn.exec(BEGIN [ISOLATION opts.isolation])
|
|
71
|
+
try: r = fn(txctx) # fn 内の全 SQL は connectionFor→この conn
|
|
72
|
+
conn.exec(COMMIT); return r
|
|
73
|
+
except: conn.exec(ROLLBACK); (retry? #69-B3); raise
|
|
74
|
+
finally: pool.release(conn) [or destroy if bad #69-B4]
|
|
75
|
+
```
|
|
76
|
+
→ **並行 tx は各々別 conn を所有**。driver グローバル `writer` スロット(rust:431 等)を**全言語で撤去**。
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 4. Middleware hook 機構(5言語共通・TS定義主・native登録可)
|
|
81
|
+
|
|
82
|
+
**ctx が middleware chain を保持**、中央 seam(§2 ①)が全 SQL をラップ。2 レベル:
|
|
83
|
+
- **SQL-level `execute` フック**(全 SQL 横取り)= 中央 seam に組込。**5言語全部**に hook 点あり。
|
|
84
|
+
- **method-level フック**(find?/create?/update?…)= ORM メソッド入口でラップ(decorator model は TS、native は該当メソッド境界)。
|
|
85
|
+
|
|
86
|
+
**登録**:
|
|
87
|
+
- **TS が主**(v1 `DBModel.use(MiddlewareClass)` 相当)。middleware chain を構築。
|
|
88
|
+
- **native 側でも登録可**: rust/go/py/php 各 runtime に `register_middleware(mw)` API を設け、その言語の ctx chain に append。
|
|
89
|
+
- chain の**契約(`execute(next, sql, params)`)と適用順は 5 言語共通**。
|
|
90
|
+
|
|
91
|
+
middleware は ctx(実行スコープ)に紐づく → per-request/context 分離(v1 ALS と同じ)。
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 5. seam 契約(共通シェイプ・言語別実装の型)
|
|
96
|
+
|
|
97
|
+
疑似型(各言語に写す):
|
|
98
|
+
```
|
|
99
|
+
interface ExecutionContext {
|
|
100
|
+
connectionFor(intent: { write: bool, db?: string }): Connection
|
|
101
|
+
readonly middleware: MiddlewareChain
|
|
102
|
+
withConnection(conn, tx: bool): ExecutionContext // tx スコープ派生
|
|
103
|
+
// config(timeout/limit)は Phase C/E で追加
|
|
104
|
+
}
|
|
105
|
+
interface Connection { exec(sql, params): Rows | RunInfo } // 唯一の driver 接点
|
|
106
|
+
interface MiddlewareChain { wrap(sql, params, next): result }
|
|
107
|
+
execute(ctx, sql, params): Rows
|
|
108
|
+
run(ctx, sql, params): RunInfo
|
|
109
|
+
withTransaction(ctx, opts, fn): R
|
|
110
|
+
```
|
|
111
|
+
- 既存 `executeBundle(bundle, input, driver)` は `executeBundle(bundle, input, ctx)` に。呼び出し側は `ctx = Context.forDriver(driver)`(単一DB・middleware無し時は薄いラッパ=後方互換)。
|
|
112
|
+
- relation walker / tx walker は `driver.prepare().all()` を `execute/run(ctx, …)` に置換。
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 6. 移行と後方互換
|
|
117
|
+
|
|
118
|
+
- **既存の単純パス**(bench/conformance が driver 直渡し)は `Context.forDriver(driver)`(reader=writer=同 pool・middleware 空・単一DB)で**挙動不変**。conformance/livedb は byte 不変で通す。
|
|
119
|
+
- Phase A は「seam + ctx + tx所有 + 並行tx修正」まで。reader/writer(§3-2/3)・複数DB(§3-4)・middleware 登録 API・config は **B/C/D で ctx を拡張**(本設計の ctx がその受け皿)。
|
|
120
|
+
- **並行 tx 隔離テスト**(#69 AC)を Phase A の完了条件に含める(現行 fail→修正で green、全言語・実 DB)。
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 7. Phase A の完了条件(AC)
|
|
125
|
+
|
|
126
|
+
- [ ] 中央 `execute/run(ctx, …)` seam を 5 言語に実装、全 SQL(read/write/tx/relation)がそこを通る(直 driver 呼び出しゼロを grep で担保)。
|
|
127
|
+
- [ ] `ExecutionContext` + per-execution 接続所有(tx が接続をスコープ所有)。driver グローバル tx スロット全言語撤去。
|
|
128
|
+
- [ ] **並行 tx 隔離テスト green**(同一プロセス・共有 runtime で N tx 同時、混入なし・原子性保持、実 PG/MySQL、全言語)。現行コードで fail することも実証。
|
|
129
|
+
- [ ] middleware chain 挿入点を seam に用意(空 chain で挙動不変。登録 API 実体は #70/Phase D)。
|
|
130
|
+
- [ ] conformance/livedb/unit/bench 全 green・byte 不変(後方互換ラッパ経由)、全ゲート native ARM。
|
|
131
|
+
- [ ] 独立監査(並行 tx の隔離を mutation で実証)。
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 8. 要判断(sign-off 前に確認したい)
|
|
136
|
+
|
|
137
|
+
1. **rust の ctx 伝播**: 明示引数 thread か `tokio::task_local` か(前者は型安全・後者は v1 TS の ALS に近い)。→ 提案: **明示引数**(rust らしく静的・所有明確)。
|
|
138
|
+
2. **current-thread runtime 化**(rust、block_on 軽量化・v1rs 準拠)を Phase A に含めるか(perf にも効く)。→ 提案: 含める。
|
|
139
|
+
3. **seam の粒度**: statement 単位(各 SQL)で middleware/接続解決。read-graph の serial 連鎖は同一 tx/接続スコープを共有(§3)。並列 read fan-out は別接続(既存 bc#23 維持)。→ 確認。
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "litedbmodel",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "A lightweight TypeScript ORM for PostgreSQL, MySQL, and SQLite with Active Record pattern",
|
|
5
|
-
"main": "dist/index.
|
|
5
|
+
"main": "dist/index.cjs",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
9
9
|
"types": "./dist/index.d.ts",
|
|
10
|
-
"default": "./dist/index.
|
|
10
|
+
"default": "./dist/index.cjs"
|
|
11
11
|
},
|
|
12
12
|
"./drivers": {
|
|
13
13
|
"types": "./dist/drivers/index.d.ts",
|
|
@@ -35,6 +35,8 @@
|
|
|
35
35
|
"test": "vitest run",
|
|
36
36
|
"test:unit": "vitest run test/unit",
|
|
37
37
|
"test:integration": "TEST_DB_HOST=localhost vitest run test/integration",
|
|
38
|
+
"parity:capture": "TEST_DB_HOST=localhost TEST_DB_PORT=5433 vitest run test/parity/v1-sql-golden.test.ts",
|
|
39
|
+
"parity:scp": "vitest run test/parity/v2-scp-parity.test.ts",
|
|
38
40
|
"test:watch": "vitest",
|
|
39
41
|
"test:coverage": "vitest run --coverage",
|
|
40
42
|
"lint": "eslint src",
|
|
@@ -49,17 +51,19 @@
|
|
|
49
51
|
"sync:versions": "node scripts/sync-versions.mjs",
|
|
50
52
|
"sync:versions:check": "node scripts/sync-versions.mjs --check",
|
|
51
53
|
"deps:check": "node scripts/check-no-local-deps.mjs",
|
|
54
|
+
"gates:check": "node scripts/check-reachable-test-gates.mjs",
|
|
55
|
+
"pkg:check": "node scripts/check-package-entrypoints.mjs",
|
|
52
56
|
"vendor:bc-php": "node scripts/vendor-behavior-contracts-php.mjs",
|
|
53
57
|
"vendor:bc-php:check": "node scripts/vendor-behavior-contracts-php.mjs --check",
|
|
54
58
|
"conformance:gen": "vitest run --config conformance/vitest.config.ts",
|
|
55
59
|
"conformance:gen:livedb": "vitest run --config conformance/vitest.livedb.config.ts",
|
|
56
|
-
"conformance:
|
|
57
|
-
"conformance:run": "npm run build:scp && tsx conformance/vectors-run.ts",
|
|
58
|
-
"conformance:codegen": "npm run build:scp && tsx conformance/codegen/codegen-runner.ts",
|
|
60
|
+
"conformance:check:livedb": "LIVEDB_GEN_MODE=check vitest run --config conformance/vitest.livedb.config.ts",
|
|
59
61
|
"conformance:livedb": "tsx conformance/livedb-run.ts",
|
|
60
62
|
"docker:livedb:up": "docker compose -f docker-compose.test.yml -f docker-compose.livedb.yml up -d postgres mysql",
|
|
61
63
|
"docker:livedb:down": "docker compose -f docker-compose.test.yml -f docker-compose.livedb.yml down -v",
|
|
62
|
-
"conformance:livedb:docker": "npm run docker:livedb:up && sleep 5 && npm run conformance:gen:livedb && npm run conformance:livedb; e=$?; npm run docker:livedb:down; exit $e"
|
|
64
|
+
"conformance:livedb:docker": "npm run docker:livedb:up && sleep 5 && npm run conformance:gen:livedb && npm run conformance:livedb; e=$?; npm run docker:livedb:down; exit $e",
|
|
65
|
+
"native:gen": "bash benchmark/crosslang/gen-native.sh generate",
|
|
66
|
+
"bench:codegen:drift": "bash benchmark/crosslang/gen-native.sh check"
|
|
63
67
|
},
|
|
64
68
|
"keywords": [
|
|
65
69
|
"orm",
|
|
@@ -80,7 +84,7 @@
|
|
|
80
84
|
"url": "git+https://github.com/foo-ogawa/litedbmodel.git"
|
|
81
85
|
},
|
|
82
86
|
"dependencies": {
|
|
83
|
-
"behavior-contracts": "^0.
|
|
87
|
+
"behavior-contracts": "^0.11.17",
|
|
84
88
|
"reflect-metadata": "^0.2.2"
|
|
85
89
|
},
|
|
86
90
|
"devDependencies": {
|
|
@@ -123,6 +127,9 @@
|
|
|
123
127
|
"node": ">=18.0.0"
|
|
124
128
|
},
|
|
125
129
|
"overrides": {
|
|
126
|
-
"js-yaml": "
|
|
130
|
+
"js-yaml": "4.3.0",
|
|
131
|
+
"linkify-it": "5.0.2",
|
|
132
|
+
"postcss": "8.5.24",
|
|
133
|
+
"brace-expansion": "5.0.8"
|
|
127
134
|
}
|
|
128
135
|
}
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* litedbmodel v2 SCP — SQL WHERE authoring helpers (WS3, #23).
|
|
3
|
-
*
|
|
4
|
-
* These are thin, closed-set wrappers over behavior-contracts' expression builders that
|
|
5
|
-
* make a WHERE fragment tree authorable in the `SemanticBehavior` / eager surface while
|
|
6
|
-
* emitting ONLY bc's closed-set Expression IR (no invented opcode — the hard rule). The
|
|
7
|
-
* {@link import('./bridge').compileNode} Backend-Compile bridge decodes exactly these
|
|
8
|
-
* closed-set encodings back into WS1's fragment `Condition[]`:
|
|
9
|
-
*
|
|
10
|
-
* - {@link whereEq} → `{eq:[<colRef>, <value>]}` → `col = ?`
|
|
11
|
-
* - {@link whereNe}/{@link whereLt}/… → `{ne|lt|le|gt|ge:[<colRef>, v]}` → `col <op> ?`
|
|
12
|
-
* - {@link whereIsNull} → `{eq:[<colRef>, null]}` → `col IS NULL`
|
|
13
|
-
* - {@link whereIn} → `{eq:[{ref:[IN_SENTINEL, col]}, <arr>]}` → `col IN (?, …)`
|
|
14
|
-
*
|
|
15
|
-
* A SKIP-optional condition is authored with bc's `when(cond, () => <whereX(...)>)`, which
|
|
16
|
-
* bc lowers to `{cond:[cond, <member>, null]}` — the bridge reads that as a `skipWhen`
|
|
17
|
-
* guard (dynamic-expansion spec §2). Nested AND/OR groups are authored with bc's `and` /
|
|
18
|
-
* `or` over these members.
|
|
19
|
-
*
|
|
20
|
-
* The column argument is a RECORDED reference (`$.author_id`, or a wire field `$p.foo`):
|
|
21
|
-
* its ref-path last segment is the physical column name (spec §7). The value argument is a
|
|
22
|
-
* recorded reference, a literal, or any closed-set builder expression (`coalesce`, `add`, …).
|
|
23
|
-
*/
|
|
24
|
-
import { type Recorded } from 'behavior-contracts';
|
|
25
|
-
/** A recorded `$`-reference (column or value) or a literal value usable in a builder. */
|
|
26
|
-
type Operand = Recorded | unknown;
|
|
27
|
-
/**
|
|
28
|
-
* The sentinel ref-path heads that mark the ADDITIVE where-primitives (V0 R2/R3) so the live
|
|
29
|
-
* compile (`static-bundle.lowerWhereMember`) can decode them into the EXACT v1 `ConditionObject`
|
|
30
|
-
* and drive the ORIGINAL `DBConditions.compile()` for byte-true text — never a hand-roll. Each is
|
|
31
|
-
* encoded with the closed-set `eq(<sentinel ref>, <value>)` shape (the SAME trick {@link whereIn}
|
|
32
|
-
* uses for IN-lists), so no opcode outside bc's closed set is invented. Structural metadata (the
|
|
33
|
-
* column name, the SQL cast type, the LIKE keyword, the tuple column list, the subquery text)
|
|
34
|
-
* rides as extra STRING segments in the sentinel ref path; the runtime value operands ride as the
|
|
35
|
-
* `eq` RHS and are deferred as value-specs 1:1 with the placeholders in the v1-produced text.
|
|
36
|
-
*/
|
|
37
|
-
export declare const BETWEEN_SENTINEL = "@between";
|
|
38
|
-
export declare const LIKE_SENTINEL = "@like";
|
|
39
|
-
export declare const CAST_SENTINEL = "@cast";
|
|
40
|
-
export declare const DYNAMIC_SENTINEL = "@dynamic";
|
|
41
|
-
export declare const IMMEDIATE_SENTINEL = "@immediate";
|
|
42
|
-
export declare const TUPLE_SENTINEL = "@tuple";
|
|
43
|
-
export declare const SUBQUERY_SENTINEL = "@subquery";
|
|
44
|
-
export declare const EXISTS_SENTINEL = "@exists";
|
|
45
|
-
/** `col = value` — equality fragment (`{eq:[colRef, value]}`). */
|
|
46
|
-
export declare function whereEq(col: Recorded, value: Operand): Recorded;
|
|
47
|
-
/** `col <> value` — inequality fragment. */
|
|
48
|
-
export declare function whereNe(col: Recorded, value: Operand): Recorded;
|
|
49
|
-
/** `col < value`. */
|
|
50
|
-
export declare function whereLt(col: Recorded, value: Operand): Recorded;
|
|
51
|
-
/** `col <= value`. */
|
|
52
|
-
export declare function whereLe(col: Recorded, value: Operand): Recorded;
|
|
53
|
-
/** `col > value`. */
|
|
54
|
-
export declare function whereGt(col: Recorded, value: Operand): Recorded;
|
|
55
|
-
/** `col >= value`. */
|
|
56
|
-
export declare function whereGe(col: Recorded, value: Operand): Recorded;
|
|
57
|
-
/** `col IS NULL` — encoded as `eq(col, null)` (v1 parity; bridge maps null-RHS → IS NULL). */
|
|
58
|
-
export declare function whereIsNull(col: Recorded): Recorded;
|
|
59
|
-
/**
|
|
60
|
-
* `col IN (?, …)` — encoded as `eq(<IN-sentinel col>, value)`. `col` MUST be the IN-sentinel
|
|
61
|
-
* reference built by {@link inColumn} (its ref-path head is {@link IN_SENTINEL}); `value` is
|
|
62
|
-
* the array-valued reference/expression whose `?` expands to `(?, ?, …)` at render time
|
|
63
|
-
* (dynamic-expansion spec §5). Using the sentinel keeps IN expressible with only the
|
|
64
|
-
* closed-set `eq` + `ref` operators.
|
|
65
|
-
*/
|
|
66
|
-
export declare function whereIn(col: Recorded, value: Operand): Recorded;
|
|
67
|
-
/**
|
|
68
|
-
* Build the IN-list column reference for {@link whereIn}: `$[IN_SENTINEL][name]` — a
|
|
69
|
-
* recorded ref whose path is `[IN_SENTINEL, name]`. The bridge strips the sentinel head and
|
|
70
|
-
* treats `name` as the physical column (a membership fragment, not an equality).
|
|
71
|
-
*/
|
|
72
|
-
export declare function inColumn($: Recorded, name: string): Recorded;
|
|
73
|
-
/**
|
|
74
|
-
* `col BETWEEN ? AND ?` (V0 R3). Encoded `eq($[@between][col], [lo, hi])`; the live compile builds
|
|
75
|
-
* the v1 custom-op `ConditionObject` `{'<col> BETWEEN ? AND ?': [lo, hi]}` and defers both bounds.
|
|
76
|
-
* `lo`/`hi` are recorded refs or literals.
|
|
77
|
-
*/
|
|
78
|
-
export declare function whereBetween($: Recorded, col: string, lo: Operand, hi: Operand): Recorded;
|
|
79
|
-
/**
|
|
80
|
-
* `col LIKE ?` (V0 R3). Encoded `eq($[@like][col], pattern)` → v1 `{'<col> LIKE ?': pattern}`.
|
|
81
|
-
* The pattern is a recorded ref or literal.
|
|
82
|
-
*/
|
|
83
|
-
export declare function whereLike($: Recorded, col: string, pattern: Operand): Recorded;
|
|
84
|
-
/**
|
|
85
|
-
* `col ILIKE ?` (V0 R3, PG case-insensitive; on MySQL/SQLite v1 emits the raw `ILIKE` keyword —
|
|
86
|
-
* this reproduces v1 verbatim, not a portability rewrite). Encoded `eq($[@like][col][ILIKE], p)`.
|
|
87
|
-
*/
|
|
88
|
-
export declare function whereILike($: Recorded, col: string, pattern: Operand): Recorded;
|
|
89
|
-
/**
|
|
90
|
-
* `col <op> ?::type` (V0 R3, dialect-gated cast — `dbCast`). Encoded
|
|
91
|
-
* `eq($[@cast][col][type][op], value)`; the live compile drives v1 `dbCast(value, type, op)` so the
|
|
92
|
-
* PG `::type` cast (and the MySQL/SQLite no-cast) is byte-true. `op` defaults to `=`.
|
|
93
|
-
*/
|
|
94
|
-
export declare function whereCast($: Recorded, col: string, sqlType: string, value: Operand, op?: string): Recorded;
|
|
95
|
-
/**
|
|
96
|
-
* `col = fn(?)` (V0 R3, `dbDynamic`) — a function-call template with `?` placeholders bound to the
|
|
97
|
-
* value list. Encoded `eq($[@dynamic][col][template], values)`; drives v1 `dbDynamic(template, vals)`.
|
|
98
|
-
* `template` is the raw function SQL (e.g. `to_tsvector('en', ?)`).
|
|
99
|
-
*/
|
|
100
|
-
export declare function whereDynamic($: Recorded, col: string, template: string, values: Operand): Recorded;
|
|
101
|
-
/**
|
|
102
|
-
* `col = <sql>` (V0 R3, `dbImmediate` — an inline SQL expression, NO bound param, e.g. `NOW()`).
|
|
103
|
-
* Encoded `eq($[@immediate][col][sql], null)`; drives v1 `dbImmediate(sql)`. No value-spec.
|
|
104
|
-
*/
|
|
105
|
-
export declare function whereImmediate($: Recorded, col: string, sql: string): Recorded;
|
|
106
|
-
/**
|
|
107
|
-
* `(a, b, …) IN ((?, ?), …)` (V0 R3, `dbTupleIn` composite membership). Encoded
|
|
108
|
-
* `eq($[@tuple][a][b]…, tuples)` where `tuples` is an array-of-tuples value; drives v1
|
|
109
|
-
* `dbTupleIn(columns, tuples)`. `columns` is the tuple column list.
|
|
110
|
-
*/
|
|
111
|
-
export declare function whereTupleIn($: Recorded, columns: readonly string[], tuples: Operand): Recorded;
|
|
112
|
-
/**
|
|
113
|
-
* `lhs IN (SELECT …)` / `lhs NOT IN (SELECT …)` (V0 R2). The subquery is authored as a NESTED
|
|
114
|
-
* makeSQL Fragment carried in the param slot (spec §2 補足): `sub` is a `{ sql, params? }` where
|
|
115
|
-
* `sql` is the inner SELECT text (already dialect-tuned, v1-sourced) and `params` its bound
|
|
116
|
-
* value-specs. Encoded `eq($[@subquery][lhsCol][kw], sub)`; the live compile splices the inner
|
|
117
|
-
* `sql` into the v1 `DBSubquery`-shaped predicate `<lhs> <kw> (<sub.sql>)` and appends `sub.params`.
|
|
118
|
-
*/
|
|
119
|
-
export declare function whereInSubquery($: Recorded, lhs: string, sub: {
|
|
120
|
-
sql: string;
|
|
121
|
-
params?: readonly Operand[];
|
|
122
|
-
}, not?: boolean): Recorded;
|
|
123
|
-
/**
|
|
124
|
-
* `EXISTS (SELECT 1 …)` / `NOT EXISTS (…)` (V0 R2). Like {@link whereInSubquery}, the correlated
|
|
125
|
-
* subquery rides as a nested makeSQL Fragment in the param slot: `sub.sql` is the inner
|
|
126
|
-
* `SELECT 1 FROM … WHERE …` (correlation refs already rendered as literal column paths, v1-sourced).
|
|
127
|
-
* Encoded `eq($[@exists][kw], sub)`; the live compile emits `<kw> (<sub.sql>)` + `sub.params`.
|
|
128
|
-
*/
|
|
129
|
-
export declare function whereExists($: Recorded, sub: {
|
|
130
|
-
sql: string;
|
|
131
|
-
params?: readonly Operand[];
|
|
132
|
-
}, not?: boolean): Recorded;
|
|
133
|
-
export {};
|
|
134
|
-
//# sourceMappingURL=authoring-sql.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"authoring-sql.d.ts","sourceRoot":"","sources":["../../src/scp/authoring-sql.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* litedbmodel v2 SCP — SQL WHERE authoring helpers (WS3, #23).
|
|
4
|
-
*
|
|
5
|
-
* These are thin, closed-set wrappers over behavior-contracts' expression builders that
|
|
6
|
-
* make a WHERE fragment tree authorable in the `SemanticBehavior` / eager surface while
|
|
7
|
-
* emitting ONLY bc's closed-set Expression IR (no invented opcode — the hard rule). The
|
|
8
|
-
* {@link import('./bridge').compileNode} Backend-Compile bridge decodes exactly these
|
|
9
|
-
* closed-set encodings back into WS1's fragment `Condition[]`:
|
|
10
|
-
*
|
|
11
|
-
* - {@link whereEq} → `{eq:[<colRef>, <value>]}` → `col = ?`
|
|
12
|
-
* - {@link whereNe}/{@link whereLt}/… → `{ne|lt|le|gt|ge:[<colRef>, v]}` → `col <op> ?`
|
|
13
|
-
* - {@link whereIsNull} → `{eq:[<colRef>, null]}` → `col IS NULL`
|
|
14
|
-
* - {@link whereIn} → `{eq:[{ref:[IN_SENTINEL, col]}, <arr>]}` → `col IN (?, …)`
|
|
15
|
-
*
|
|
16
|
-
* A SKIP-optional condition is authored with bc's `when(cond, () => <whereX(...)>)`, which
|
|
17
|
-
* bc lowers to `{cond:[cond, <member>, null]}` — the bridge reads that as a `skipWhen`
|
|
18
|
-
* guard (dynamic-expansion spec §2). Nested AND/OR groups are authored with bc's `and` /
|
|
19
|
-
* `or` over these members.
|
|
20
|
-
*
|
|
21
|
-
* The column argument is a RECORDED reference (`$.author_id`, or a wire field `$p.foo`):
|
|
22
|
-
* its ref-path last segment is the physical column name (spec §7). The value argument is a
|
|
23
|
-
* recorded reference, a literal, or any closed-set builder expression (`coalesce`, `add`, …).
|
|
24
|
-
*/
|
|
25
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.EXISTS_SENTINEL = exports.SUBQUERY_SENTINEL = exports.TUPLE_SENTINEL = exports.IMMEDIATE_SENTINEL = exports.DYNAMIC_SENTINEL = exports.CAST_SENTINEL = exports.LIKE_SENTINEL = exports.BETWEEN_SENTINEL = void 0;
|
|
27
|
-
exports.whereEq = whereEq;
|
|
28
|
-
exports.whereNe = whereNe;
|
|
29
|
-
exports.whereLt = whereLt;
|
|
30
|
-
exports.whereLe = whereLe;
|
|
31
|
-
exports.whereGt = whereGt;
|
|
32
|
-
exports.whereGe = whereGe;
|
|
33
|
-
exports.whereIsNull = whereIsNull;
|
|
34
|
-
exports.whereIn = whereIn;
|
|
35
|
-
exports.inColumn = inColumn;
|
|
36
|
-
exports.whereBetween = whereBetween;
|
|
37
|
-
exports.whereLike = whereLike;
|
|
38
|
-
exports.whereILike = whereILike;
|
|
39
|
-
exports.whereCast = whereCast;
|
|
40
|
-
exports.whereDynamic = whereDynamic;
|
|
41
|
-
exports.whereImmediate = whereImmediate;
|
|
42
|
-
exports.whereTupleIn = whereTupleIn;
|
|
43
|
-
exports.whereInSubquery = whereInSubquery;
|
|
44
|
-
exports.whereExists = whereExists;
|
|
45
|
-
const behavior_contracts_1 = require("behavior-contracts");
|
|
46
|
-
const makesql_1 = require("./makesql");
|
|
47
|
-
/**
|
|
48
|
-
* The sentinel ref-path heads that mark the ADDITIVE where-primitives (V0 R2/R3) so the live
|
|
49
|
-
* compile (`static-bundle.lowerWhereMember`) can decode them into the EXACT v1 `ConditionObject`
|
|
50
|
-
* and drive the ORIGINAL `DBConditions.compile()` for byte-true text — never a hand-roll. Each is
|
|
51
|
-
* encoded with the closed-set `eq(<sentinel ref>, <value>)` shape (the SAME trick {@link whereIn}
|
|
52
|
-
* uses for IN-lists), so no opcode outside bc's closed set is invented. Structural metadata (the
|
|
53
|
-
* column name, the SQL cast type, the LIKE keyword, the tuple column list, the subquery text)
|
|
54
|
-
* rides as extra STRING segments in the sentinel ref path; the runtime value operands ride as the
|
|
55
|
-
* `eq` RHS and are deferred as value-specs 1:1 with the placeholders in the v1-produced text.
|
|
56
|
-
*/
|
|
57
|
-
exports.BETWEEN_SENTINEL = '@between';
|
|
58
|
-
exports.LIKE_SENTINEL = '@like';
|
|
59
|
-
exports.CAST_SENTINEL = '@cast';
|
|
60
|
-
exports.DYNAMIC_SENTINEL = '@dynamic';
|
|
61
|
-
exports.IMMEDIATE_SENTINEL = '@immediate';
|
|
62
|
-
exports.TUPLE_SENTINEL = '@tuple';
|
|
63
|
-
exports.SUBQUERY_SENTINEL = '@subquery';
|
|
64
|
-
exports.EXISTS_SENTINEL = '@exists';
|
|
65
|
-
/** Build a sentinel column ref: `$[HEAD][seg0][seg1]…` → a recorded ref with that path. */
|
|
66
|
-
function sentinelRef($, head, segs) {
|
|
67
|
-
let node = $[head];
|
|
68
|
-
for (const s of segs)
|
|
69
|
-
node = node[s];
|
|
70
|
-
return node;
|
|
71
|
-
}
|
|
72
|
-
/** `col = value` — equality fragment (`{eq:[colRef, value]}`). */
|
|
73
|
-
function whereEq(col, value) {
|
|
74
|
-
return (0, behavior_contracts_1.eq)(col, value);
|
|
75
|
-
}
|
|
76
|
-
/** `col <> value` — inequality fragment. */
|
|
77
|
-
function whereNe(col, value) {
|
|
78
|
-
return (0, behavior_contracts_1.ne)(col, value);
|
|
79
|
-
}
|
|
80
|
-
/** `col < value`. */
|
|
81
|
-
function whereLt(col, value) {
|
|
82
|
-
return (0, behavior_contracts_1.lt)(col, value);
|
|
83
|
-
}
|
|
84
|
-
/** `col <= value`. */
|
|
85
|
-
function whereLe(col, value) {
|
|
86
|
-
return (0, behavior_contracts_1.le)(col, value);
|
|
87
|
-
}
|
|
88
|
-
/** `col > value`. */
|
|
89
|
-
function whereGt(col, value) {
|
|
90
|
-
return (0, behavior_contracts_1.gt)(col, value);
|
|
91
|
-
}
|
|
92
|
-
/** `col >= value`. */
|
|
93
|
-
function whereGe(col, value) {
|
|
94
|
-
return (0, behavior_contracts_1.ge)(col, value);
|
|
95
|
-
}
|
|
96
|
-
/** `col IS NULL` — encoded as `eq(col, null)` (v1 parity; bridge maps null-RHS → IS NULL). */
|
|
97
|
-
function whereIsNull(col) {
|
|
98
|
-
return (0, behavior_contracts_1.eq)(col, null);
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* `col IN (?, …)` — encoded as `eq(<IN-sentinel col>, value)`. `col` MUST be the IN-sentinel
|
|
102
|
-
* reference built by {@link inColumn} (its ref-path head is {@link IN_SENTINEL}); `value` is
|
|
103
|
-
* the array-valued reference/expression whose `?` expands to `(?, ?, …)` at render time
|
|
104
|
-
* (dynamic-expansion spec §5). Using the sentinel keeps IN expressible with only the
|
|
105
|
-
* closed-set `eq` + `ref` operators.
|
|
106
|
-
*/
|
|
107
|
-
function whereIn(col, value) {
|
|
108
|
-
return (0, behavior_contracts_1.eq)(col, value);
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Build the IN-list column reference for {@link whereIn}: `$[IN_SENTINEL][name]` — a
|
|
112
|
-
* recorded ref whose path is `[IN_SENTINEL, name]`. The bridge strips the sentinel head and
|
|
113
|
-
* treats `name` as the physical column (a membership fragment, not an equality).
|
|
114
|
-
*/
|
|
115
|
-
function inColumn($, name) {
|
|
116
|
-
return $[makesql_1.IN_SENTINEL][name];
|
|
117
|
-
}
|
|
118
|
-
// ── Additive where-primitives (V0 R2/R3) — all v1-sourced at compile, live-reachable ──────────
|
|
119
|
-
/**
|
|
120
|
-
* `col BETWEEN ? AND ?` (V0 R3). Encoded `eq($[@between][col], [lo, hi])`; the live compile builds
|
|
121
|
-
* the v1 custom-op `ConditionObject` `{'<col> BETWEEN ? AND ?': [lo, hi]}` and defers both bounds.
|
|
122
|
-
* `lo`/`hi` are recorded refs or literals.
|
|
123
|
-
*/
|
|
124
|
-
function whereBetween($, col, lo, hi) {
|
|
125
|
-
return (0, behavior_contracts_1.eq)(sentinelRef($, exports.BETWEEN_SENTINEL, [col]), [lo, hi]);
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* `col LIKE ?` (V0 R3). Encoded `eq($[@like][col], pattern)` → v1 `{'<col> LIKE ?': pattern}`.
|
|
129
|
-
* The pattern is a recorded ref or literal.
|
|
130
|
-
*/
|
|
131
|
-
function whereLike($, col, pattern) {
|
|
132
|
-
return (0, behavior_contracts_1.eq)(sentinelRef($, exports.LIKE_SENTINEL, [col, 'LIKE']), pattern);
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* `col ILIKE ?` (V0 R3, PG case-insensitive; on MySQL/SQLite v1 emits the raw `ILIKE` keyword —
|
|
136
|
-
* this reproduces v1 verbatim, not a portability rewrite). Encoded `eq($[@like][col][ILIKE], p)`.
|
|
137
|
-
*/
|
|
138
|
-
function whereILike($, col, pattern) {
|
|
139
|
-
return (0, behavior_contracts_1.eq)(sentinelRef($, exports.LIKE_SENTINEL, [col, 'ILIKE']), pattern);
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* `col <op> ?::type` (V0 R3, dialect-gated cast — `dbCast`). Encoded
|
|
143
|
-
* `eq($[@cast][col][type][op], value)`; the live compile drives v1 `dbCast(value, type, op)` so the
|
|
144
|
-
* PG `::type` cast (and the MySQL/SQLite no-cast) is byte-true. `op` defaults to `=`.
|
|
145
|
-
*/
|
|
146
|
-
function whereCast($, col, sqlType, value, op = '=') {
|
|
147
|
-
return (0, behavior_contracts_1.eq)(sentinelRef($, exports.CAST_SENTINEL, [col, sqlType, op]), value);
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* `col = fn(?)` (V0 R3, `dbDynamic`) — a function-call template with `?` placeholders bound to the
|
|
151
|
-
* value list. Encoded `eq($[@dynamic][col][template], values)`; drives v1 `dbDynamic(template, vals)`.
|
|
152
|
-
* `template` is the raw function SQL (e.g. `to_tsvector('en', ?)`).
|
|
153
|
-
*/
|
|
154
|
-
function whereDynamic($, col, template, values) {
|
|
155
|
-
return (0, behavior_contracts_1.eq)(sentinelRef($, exports.DYNAMIC_SENTINEL, [col, template]), values);
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* `col = <sql>` (V0 R3, `dbImmediate` — an inline SQL expression, NO bound param, e.g. `NOW()`).
|
|
159
|
-
* Encoded `eq($[@immediate][col][sql], null)`; drives v1 `dbImmediate(sql)`. No value-spec.
|
|
160
|
-
*/
|
|
161
|
-
function whereImmediate($, col, sql) {
|
|
162
|
-
return (0, behavior_contracts_1.eq)(sentinelRef($, exports.IMMEDIATE_SENTINEL, [col, sql]), null);
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* `(a, b, …) IN ((?, ?), …)` (V0 R3, `dbTupleIn` composite membership). Encoded
|
|
166
|
-
* `eq($[@tuple][a][b]…, tuples)` where `tuples` is an array-of-tuples value; drives v1
|
|
167
|
-
* `dbTupleIn(columns, tuples)`. `columns` is the tuple column list.
|
|
168
|
-
*/
|
|
169
|
-
function whereTupleIn($, columns, tuples) {
|
|
170
|
-
return (0, behavior_contracts_1.eq)(sentinelRef($, exports.TUPLE_SENTINEL, columns), tuples);
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* `lhs IN (SELECT …)` / `lhs NOT IN (SELECT …)` (V0 R2). The subquery is authored as a NESTED
|
|
174
|
-
* makeSQL Fragment carried in the param slot (spec §2 補足): `sub` is a `{ sql, params? }` where
|
|
175
|
-
* `sql` is the inner SELECT text (already dialect-tuned, v1-sourced) and `params` its bound
|
|
176
|
-
* value-specs. Encoded `eq($[@subquery][lhsCol][kw], sub)`; the live compile splices the inner
|
|
177
|
-
* `sql` into the v1 `DBSubquery`-shaped predicate `<lhs> <kw> (<sub.sql>)` and appends `sub.params`.
|
|
178
|
-
*/
|
|
179
|
-
function whereInSubquery($, lhs, sub, not = false) {
|
|
180
|
-
return (0, behavior_contracts_1.eq)(sentinelRef($, exports.SUBQUERY_SENTINEL, [lhs, not ? 'NOT IN' : 'IN']), sub);
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* `EXISTS (SELECT 1 …)` / `NOT EXISTS (…)` (V0 R2). Like {@link whereInSubquery}, the correlated
|
|
184
|
-
* subquery rides as a nested makeSQL Fragment in the param slot: `sub.sql` is the inner
|
|
185
|
-
* `SELECT 1 FROM … WHERE …` (correlation refs already rendered as literal column paths, v1-sourced).
|
|
186
|
-
* Encoded `eq($[@exists][kw], sub)`; the live compile emits `<kw> (<sub.sql>)` + `sub.params`.
|
|
187
|
-
*/
|
|
188
|
-
function whereExists($, sub, not = false) {
|
|
189
|
-
return (0, behavior_contracts_1.eq)(sentinelRef($, exports.EXISTS_SENTINEL, [not ? 'NOT EXISTS' : 'EXISTS']), sub);
|
|
190
|
-
}
|
|
191
|
-
//# sourceMappingURL=authoring-sql.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"authoring-sql.js","sourceRoot":"","sources":["../../src/scp/authoring-sql.ts"],"names":[],"mappings":"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"}
|