litedbmodel 1.2.9 → 2.0.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 +1 -1
- package/dist/DBModel.d.ts.map +1 -1
- package/dist/DBModel.js +6 -0
- package/dist/DBModel.js.map +1 -1
- package/dist/scp/authoring-sql.d.ts +56 -0
- package/dist/scp/authoring-sql.d.ts.map +1 -0
- package/dist/scp/authoring-sql.js +83 -0
- package/dist/scp/authoring-sql.js.map +1 -0
- package/dist/scp/authoring.d.ts +155 -0
- package/dist/scp/authoring.d.ts.map +1 -0
- package/dist/scp/authoring.js +162 -0
- package/dist/scp/authoring.js.map +1 -0
- package/dist/scp/bridge.d.ts +64 -0
- package/dist/scp/bridge.d.ts.map +1 -0
- package/dist/scp/bridge.js +329 -0
- package/dist/scp/bridge.js.map +1 -0
- package/dist/scp/catalog.d.ts +91 -0
- package/dist/scp/catalog.d.ts.map +1 -0
- package/dist/scp/catalog.js +203 -0
- package/dist/scp/catalog.js.map +1 -0
- package/dist/scp/codegen.d.ts +131 -0
- package/dist/scp/codegen.d.ts.map +1 -0
- package/dist/scp/codegen.js +137 -0
- package/dist/scp/codegen.js.map +1 -0
- package/dist/scp/compile-dialect.d.ts +39 -0
- package/dist/scp/compile-dialect.d.ts.map +1 -0
- package/dist/scp/compile-dialect.js +62 -0
- package/dist/scp/compile-dialect.js.map +1 -0
- package/dist/scp/compile-sqlite.d.ts +114 -0
- package/dist/scp/compile-sqlite.d.ts.map +1 -0
- package/dist/scp/compile-sqlite.js +149 -0
- package/dist/scp/compile-sqlite.js.map +1 -0
- package/dist/scp/dialect.d.ts +141 -0
- package/dist/scp/dialect.d.ts.map +1 -0
- package/dist/scp/dialect.js +194 -0
- package/dist/scp/dialect.js.map +1 -0
- package/dist/scp/errors.d.ts +36 -0
- package/dist/scp/errors.d.ts.map +1 -0
- package/dist/scp/errors.js +72 -0
- package/dist/scp/errors.js.map +1 -0
- package/dist/scp/guard.d.ts +47 -0
- package/dist/scp/guard.d.ts.map +1 -0
- package/dist/scp/guard.js +137 -0
- package/dist/scp/guard.js.map +1 -0
- package/dist/scp/index.cjs +4744 -0
- package/dist/scp/index.d.ts +49 -0
- package/dist/scp/index.d.ts.map +1 -0
- package/dist/scp/index.js +164 -0
- package/dist/scp/index.js.map +1 -0
- package/dist/scp/index.mjs +2000 -0
- package/dist/scp/ir.d.ts +92 -0
- package/dist/scp/ir.d.ts.map +1 -0
- package/dist/scp/ir.js +28 -0
- package/dist/scp/ir.js.map +1 -0
- package/dist/scp/relation.d.ts +136 -0
- package/dist/scp/relation.d.ts.map +1 -0
- package/dist/scp/relation.js +191 -0
- package/dist/scp/relation.js.map +1 -0
- package/dist/scp/render.d.ts +40 -0
- package/dist/scp/render.d.ts.map +1 -0
- package/dist/scp/render.js +170 -0
- package/dist/scp/render.js.map +1 -0
- package/dist/scp/runtime.d.ts +295 -0
- package/dist/scp/runtime.d.ts.map +1 -0
- package/dist/scp/runtime.js +665 -0
- package/dist/scp/runtime.js.map +1 -0
- package/dist/scp/typed-object.d.ts +88 -0
- package/dist/scp/typed-object.d.ts.map +1 -0
- package/dist/scp/typed-object.js +163 -0
- package/dist/scp/typed-object.js.map +1 -0
- package/dist/scp/write-plan.d.ts +161 -0
- package/dist/scp/write-plan.d.ts.map +1 -0
- package/dist/scp/write-plan.js +528 -0
- package/dist/scp/write-plan.js.map +1 -0
- package/dist/scp/write-runtime.d.ts +80 -0
- package/dist/scp/write-runtime.d.ts.map +1 -0
- package/dist/scp/write-runtime.js +167 -0
- package/dist/scp/write-runtime.js.map +1 -0
- package/dist/scp/writes.d.ts +251 -0
- package/dist/scp/writes.d.ts.map +1 -0
- package/dist/scp/writes.js +176 -0
- package/dist/scp/writes.js.map +1 -0
- package/docs/proposal/contracts-architecture-feasibility.md +328 -0
- package/docs/proposal/contracts-architecture.md +579 -0
- package/docs/proposal/litedbmodel-v2-scp-architecture.md +382 -0
- package/docs/proposal/sql-dynamic-expansion-spec.md +175 -0
- package/package.json +27 -5
- package/docs/README_REVIEW.md +0 -23
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* litedbmodel v2 SCP — SQLite Backend Compile (WS1, #21).
|
|
4
|
+
*
|
|
5
|
+
* Lowers a structured CRUD operation description (a Component-graph Select/Insert/Update/
|
|
6
|
+
* Delete node with ports) into a {@link CompiledOperation}: SQLite dialect SQL text,
|
|
7
|
+
* a fragment tree (dynamic WHERE/SET with existence rules), and static param slots — the
|
|
8
|
+
* IR shape of spec §8. Placeholders are unified as `?` (the `?`→`$N` pass is PG-only and
|
|
9
|
+
* OUT OF SCOPE for WS1).
|
|
10
|
+
*
|
|
11
|
+
* The generated SQLite SQL is byte-identical to what litedbmodel v1's SqliteSqlBuilder /
|
|
12
|
+
* `DBModel._buildSelectSQL` produce for equivalent queries (the golden bar). In
|
|
13
|
+
* particular:
|
|
14
|
+
* - SELECT: `SELECT <cols> FROM <t>[ WHERE <c>][ GROUP BY <g>][ ORDER BY <o>][ LIMIT ?][ OFFSET ?]`
|
|
15
|
+
* - INSERT: `INSERT INTO <t> (<cols>) VALUES (<vals>)[ RETURNING <r>]`
|
|
16
|
+
* - UPDATE: `UPDATE <t> SET <a = ?, …> WHERE <c>[ RETURNING <r>]`
|
|
17
|
+
* - DELETE: `DELETE FROM <t> WHERE <c>[ RETURNING <r>]`
|
|
18
|
+
* - WHERE parts joined by ` AND ` (or ` OR ` for an OR group), equality `col = ?`,
|
|
19
|
+
* IN-list `col IN (?, …)`, empty array → `1 = 0`, NULL → `col IS NULL`.
|
|
20
|
+
*
|
|
21
|
+
* ## Hard rule: closed Expression IR only
|
|
22
|
+
*
|
|
23
|
+
* Every param slot this compiler emits is an Expression IR node from bc's closed set
|
|
24
|
+
* (`PORTABLE_EXPR_OPERATORS`). NO litedbmodel-local opcode is ever invented. An
|
|
25
|
+
* un-lowerable predicate is the Raw SQL escape hatch's concern (spec §13), not a fake
|
|
26
|
+
* opcode. {@link compileSelect} et al. only construct `ref` / `coalesce` / etc.
|
|
27
|
+
*/
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.compileSelect = compileSelect;
|
|
30
|
+
exports.compileInsert = compileInsert;
|
|
31
|
+
exports.compileUpdate = compileUpdate;
|
|
32
|
+
exports.compileDelete = compileDelete;
|
|
33
|
+
const ir_1 = require("./ir");
|
|
34
|
+
const dialect_1 = require("./dialect");
|
|
35
|
+
const compile_dialect_1 = require("./compile-dialect");
|
|
36
|
+
// ── WHERE fragment-tree lowering (spec §8) ────────────────────────────────────
|
|
37
|
+
/** Lower one condition to a fragment (leaf) or nested tree, without a leading connector. */
|
|
38
|
+
function lowerCondition(c) {
|
|
39
|
+
if (c.kind === 'group') {
|
|
40
|
+
const tree = {
|
|
41
|
+
connector: c.connector,
|
|
42
|
+
fragments: c.conditions.map(lowerCondition),
|
|
43
|
+
};
|
|
44
|
+
// A group's own SKIP guard is carried by wrapping it — but a FragmentTree has no
|
|
45
|
+
// `when`; represent a conditional group as a single-fragment tree is not expressible,
|
|
46
|
+
// so a guarded group is lowered as a leaf-less tree whose presence is the OR/AND of
|
|
47
|
+
// its members' presence (renderTree already drops it when empty). A group with its
|
|
48
|
+
// own skipWhen is not part of WS1's representative surface; reject loudly if used.
|
|
49
|
+
if (c.skipWhen !== undefined) {
|
|
50
|
+
throw new Error('a conditional (SKIP) group is not supported in WS1; guard the member conditions individually');
|
|
51
|
+
}
|
|
52
|
+
return tree;
|
|
53
|
+
}
|
|
54
|
+
let f;
|
|
55
|
+
switch (c.kind) {
|
|
56
|
+
case 'eq':
|
|
57
|
+
f = { always: true, sql: `${c.column} = ?`, params: [c.value] };
|
|
58
|
+
break;
|
|
59
|
+
case 'cmp':
|
|
60
|
+
f = { always: true, sql: `${c.column} ${c.op} ?`, params: [c.value] };
|
|
61
|
+
break;
|
|
62
|
+
case 'isNull':
|
|
63
|
+
f = { always: true, sql: `${c.column} IS NULL`, params: [] };
|
|
64
|
+
break;
|
|
65
|
+
case 'in':
|
|
66
|
+
// IN-list: single `(?)` slot expands at render time (spec §5). golden text:
|
|
67
|
+
// `col IN (?, ?, …)` with `, ` separators; empty array degenerates to `(NULL)`.
|
|
68
|
+
f = { always: true, sql: `${c.column} IN (?)`, params: [c.value], expand: 0 };
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
if (c.skipWhen !== undefined) {
|
|
72
|
+
delete f.always;
|
|
73
|
+
f.when = c.skipWhen;
|
|
74
|
+
}
|
|
75
|
+
return f;
|
|
76
|
+
}
|
|
77
|
+
/** Build a top-level AND fragment tree from a condition list (null when empty). */
|
|
78
|
+
function lowerWhere(conditions) {
|
|
79
|
+
if (conditions === undefined || conditions.length === 0)
|
|
80
|
+
return null;
|
|
81
|
+
return { connector: 'AND', fragments: conditions.map(lowerCondition) };
|
|
82
|
+
}
|
|
83
|
+
// ── CRUD compilers ────────────────────────────────────────────────────────────
|
|
84
|
+
const assembly = (shape) => ({ shape });
|
|
85
|
+
/**
|
|
86
|
+
* Compile a SELECT. Static params (LIMIT / OFFSET) sit AFTER the `{where}` splice, so
|
|
87
|
+
* they are emitted after the fragment params (dynamic-expansion spec §6).
|
|
88
|
+
*/
|
|
89
|
+
function compileSelect(desc) {
|
|
90
|
+
const cols = desc.select.length === 1 && desc.select[0] === '*' ? '*' : desc.select.join(', ');
|
|
91
|
+
let sql = `SELECT ${cols} FROM ${desc.table}`;
|
|
92
|
+
const where = lowerWhere(desc.where);
|
|
93
|
+
// The WHERE splice marker is emitted whenever a fragment tree exists (even if all
|
|
94
|
+
// fragments may skip — degeneration is a render-time decision, spec §3).
|
|
95
|
+
if (where !== null)
|
|
96
|
+
sql += ir_1.WHERE_SLOT;
|
|
97
|
+
if (desc.group !== undefined)
|
|
98
|
+
sql += ` GROUP BY ${desc.group}`;
|
|
99
|
+
if (desc.order !== undefined)
|
|
100
|
+
sql += ` ORDER BY ${desc.order}`;
|
|
101
|
+
const params = [];
|
|
102
|
+
if (desc.limit !== undefined) {
|
|
103
|
+
sql += ` LIMIT ?`;
|
|
104
|
+
params.push(desc.limit);
|
|
105
|
+
}
|
|
106
|
+
if (desc.offset !== undefined) {
|
|
107
|
+
sql += ` OFFSET ?`;
|
|
108
|
+
params.push(desc.offset);
|
|
109
|
+
}
|
|
110
|
+
return { component: 'Select', sql, where, params, assembly: assembly('items') };
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Compile an INSERT (SQLite). All params are static (no WHERE); order = column order. The
|
|
114
|
+
* dialect-specific conflict/verb rendering is delegated to the SQLite {@link SQLITE} strategy
|
|
115
|
+
* ({@link compileInsertFor}) — the SAME dialect-parameterized compile the PG/MySQL Backend
|
|
116
|
+
* Compile uses (WS6), so SQLite is byte-for-byte unchanged and the other dialects diverge only
|
|
117
|
+
* where the v1 SqlBuilders diverge.
|
|
118
|
+
*/
|
|
119
|
+
function compileInsert(desc) {
|
|
120
|
+
return (0, compile_dialect_1.compileInsertFor)(dialect_1.SQLITE, desc);
|
|
121
|
+
}
|
|
122
|
+
/** Compile an UPDATE. SET params (static) precede the `{where}` splice (spec §6). */
|
|
123
|
+
function compileUpdate(desc) {
|
|
124
|
+
const setCols = Object.keys(desc.set);
|
|
125
|
+
if (setCols.length === 0)
|
|
126
|
+
throw new Error('UPDATE requires at least one SET column');
|
|
127
|
+
const setClauses = setCols.map((c) => `${c} = ?`);
|
|
128
|
+
const params = setCols.map((c) => desc.set[c]);
|
|
129
|
+
const where = lowerWhere(desc.where);
|
|
130
|
+
if (where === null)
|
|
131
|
+
throw new Error('UPDATE requires conditions');
|
|
132
|
+
// The ` WHERE ` keyword is emitted by render() (it prepends ` WHERE ` when the fragment
|
|
133
|
+
// tree renders non-empty). Splice the marker directly after the SET clause.
|
|
134
|
+
let sql = `UPDATE ${desc.table} SET ${setClauses.join(', ')}${ir_1.WHERE_SLOT}`;
|
|
135
|
+
if (desc.returning !== undefined)
|
|
136
|
+
sql += ` RETURNING ${desc.returning.join(', ')}`;
|
|
137
|
+
return { component: 'Update', sql, where, params, assembly: assembly('items') };
|
|
138
|
+
}
|
|
139
|
+
/** Compile a DELETE. No static params before the WHERE (all params are conditions). */
|
|
140
|
+
function compileDelete(desc) {
|
|
141
|
+
const where = lowerWhere(desc.where);
|
|
142
|
+
if (where === null)
|
|
143
|
+
throw new Error('DELETE requires conditions');
|
|
144
|
+
let sql = `DELETE FROM ${desc.table}${ir_1.WHERE_SLOT}`;
|
|
145
|
+
if (desc.returning !== undefined)
|
|
146
|
+
sql += ` RETURNING ${desc.returning.join(', ')}`;
|
|
147
|
+
return { component: 'Delete', sql, where, params: [], assembly: assembly('items') };
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=compile-sqlite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile-sqlite.js","sourceRoot":"","sources":["../../src/scp/compile-sqlite.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* litedbmodel v2 SCP — dialect strategy table (WS6, #26; spec §4/§5/§8/§10).
|
|
3
|
+
*
|
|
4
|
+
* The SINGLE SOURCE OF TRUTH for every SQL-dialect difference the Backend Compile + render
|
|
5
|
+
* pipeline needs. The dialect axis is compiled ONCE, TS-side (spec §10: "方言軸はコンパイル時
|
|
6
|
+
* に TS 側で1回検証"). This module encodes the differences as a closed strategy record — NO
|
|
7
|
+
* scattered `?:` in the engine code (the hard rule). A backend compile / renderer asks the
|
|
8
|
+
* {@link Dialect} for the dialect-specific text and never branches on the dialect name inline.
|
|
9
|
+
*
|
|
10
|
+
* ## What actually differs (verified against the v1 SqlBuilders — the golden bar)
|
|
11
|
+
*
|
|
12
|
+
* For the CRUD + write-tx + relation SQL the SCP Backend Compile emits (single-row VALUES,
|
|
13
|
+
* `?` placeholders, `col = ?` WHERE, `col IN (?, …)`), the dialect surface is small and
|
|
14
|
+
* closed:
|
|
15
|
+
*
|
|
16
|
+
* - **INSERT conflict clause**: SQLite `INSERT OR IGNORE … ` / `… ON CONFLICT (cols) DO
|
|
17
|
+
* UPDATE SET c = excluded.c`; Postgres `… ON CONFLICT (cols) DO NOTHING` / `… DO UPDATE
|
|
18
|
+
* SET c = EXCLUDED.c`; MySQL `INSERT IGNORE …` / `… ON DUPLICATE KEY UPDATE c = VALUES(c)`.
|
|
19
|
+
* These are byte-identical to `SqliteSqlBuilder` / `PostgresSqlBuilder` / `MysqlSqlBuilder`
|
|
20
|
+
* `buildInsert` for the single-record case (see the WS6 dialect-golden test).
|
|
21
|
+
* - **Bare `ON CONFLICT DO NOTHING`** (no column list — the gate-first idempotency/unique
|
|
22
|
+
* guard INSERTs of the write-tx plan, spec §6): SQLite/Postgres emit `ON CONFLICT DO
|
|
23
|
+
* NOTHING`; MySQL emits `INSERT IGNORE`.
|
|
24
|
+
* - **Placeholder style**: all dialects author with `?`; Postgres converts `?`→`$1,$2,…` in a
|
|
25
|
+
* final left-to-right one-pass AFTER the SQL text is fully assembled (spec §8 — the
|
|
26
|
+
* number-reassignment problem is designed out because the pass runs once over the final
|
|
27
|
+
* flat text). SQLite/MySQL keep `?`.
|
|
28
|
+
*
|
|
29
|
+
* Everything else (SELECT/UPDATE/DELETE skeletons, `col = ?`, `col IN (?, …)` expansion, the
|
|
30
|
+
* fragment tree, RETURNING for SQLite/Postgres) is identical text across dialects, so it is
|
|
31
|
+
* NOT part of the strategy — only the genuine divergences live here.
|
|
32
|
+
*
|
|
33
|
+
* ## DB behavior differences beyond SQL text (spec §13) — closeable-by-convention line
|
|
34
|
+
*
|
|
35
|
+
* SQL-text identity does not guarantee identical DB behavior (NULL ordering, collation,
|
|
36
|
+
* timezone). Per spec §13, those are closed "by dialect-compile-time convention" only within
|
|
37
|
+
* the closeable line. WS6 encodes the ONE convention that is mechanically closeable in the
|
|
38
|
+
* compiled SQL text: deterministic NULL ordering for an `ORDER BY … NULLS` requirement
|
|
39
|
+
* ({@link Dialect.orderByNulls}). Collation / timezone / float semantics are OUT OF SCOPE
|
|
40
|
+
* (documented, not silently defaulted).
|
|
41
|
+
*/
|
|
42
|
+
/** The SQL dialects the Backend Compile targets (spec §4 breadth: PG/MySQL/SQLite). */
|
|
43
|
+
export type DialectName = 'sqlite' | 'postgres' | 'mysql';
|
|
44
|
+
/** An INSERT conflict action (dialect-neutral intent; the dialect renders the clause). */
|
|
45
|
+
export type ConflictAction = 'ignore' | {
|
|
46
|
+
readonly updateColumns: readonly string[];
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* A dialect strategy: the closed set of dialect-specific renderings the Backend Compile +
|
|
50
|
+
* render pipeline consumes. One frozen record per dialect (the SSoT). Every method is a pure
|
|
51
|
+
* text producer — no side effects, no hidden fallback.
|
|
52
|
+
*/
|
|
53
|
+
export interface Dialect {
|
|
54
|
+
readonly name: DialectName;
|
|
55
|
+
/**
|
|
56
|
+
* Render an INSERT's optional conflict clause, appended after `… VALUES (…)`.
|
|
57
|
+
*
|
|
58
|
+
* @param conflictColumns the conflict-target columns (`ON CONFLICT (a, b)`), or an empty
|
|
59
|
+
* array for a bare conflict target (the write-tx guard INSERTs — spec §6).
|
|
60
|
+
* @param action `'ignore'` (do-nothing) or an upsert with the update-column list.
|
|
61
|
+
* @param insertColumns the INSERT's column list (needed for the `VALUES(col)` / `EXCLUDED.col`
|
|
62
|
+
* SET-clause rendering when `updateColumns` is `'all'` at the call site — the caller passes
|
|
63
|
+
* the resolved list, so this only needs the resolved update columns).
|
|
64
|
+
*/
|
|
65
|
+
insertConflictClause(conflictColumns: readonly string[], action: ConflictAction): string;
|
|
66
|
+
/**
|
|
67
|
+
* For MySQL, an `ignore` conflict is expressed on the INSERT VERB (`INSERT IGNORE INTO`),
|
|
68
|
+
* not as a trailing clause; SQLite uses `INSERT OR IGNORE INTO`; Postgres uses a plain
|
|
69
|
+
* `INSERT INTO` + a trailing `ON CONFLICT … DO NOTHING`. This returns the INSERT verb+prefix
|
|
70
|
+
* up to and including `INTO` for the `ignore` case, and the plain `INSERT INTO` otherwise.
|
|
71
|
+
*/
|
|
72
|
+
insertVerb(action: ConflictAction | undefined): string;
|
|
73
|
+
/**
|
|
74
|
+
* Whether this dialect's conflict `ignore` is a trailing clause (Postgres) rather than an
|
|
75
|
+
* INSERT-verb modifier (SQLite `OR IGNORE`, MySQL `IGNORE`). Drives whether
|
|
76
|
+
* {@link insertConflictClause} emits text for the `ignore` case.
|
|
77
|
+
*/
|
|
78
|
+
readonly ignoreIsTrailingClause: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Render a bare do-nothing GUARD INSERT — the gate-first idempotency/unique guard of the
|
|
81
|
+
* write-tx plan (spec §6): `INSERT INTO <t> (<cols>) VALUES (<ph>)` + a do-nothing conflict
|
|
82
|
+
* on ANY unique constraint (no column target). SQLite/Postgres emit a trailing
|
|
83
|
+
* `… ON CONFLICT DO NOTHING`; MySQL emits `INSERT IGNORE INTO … VALUES (…)`.
|
|
84
|
+
*
|
|
85
|
+
* This is DISTINCT from the CRUD `ignore` path ({@link insertVerb} + {@link insertConflictClause}),
|
|
86
|
+
* which mirrors the v1 SqlBuilders (SQLite uses the `INSERT OR IGNORE` verb there). The guard
|
|
87
|
+
* form is SCP-internal and its SQLite golden is the trailing `ON CONFLICT DO NOTHING` (WS5),
|
|
88
|
+
* so the two contexts render differently ON SQLITE and are kept as separate strategy methods
|
|
89
|
+
* rather than one branch.
|
|
90
|
+
*
|
|
91
|
+
* @param table the guard table.
|
|
92
|
+
* @param columns the guard row's columns (in order).
|
|
93
|
+
* @param placeholders the pre-joined placeholder list (`"?, ?, ?"`).
|
|
94
|
+
*/
|
|
95
|
+
guardInsert(table: string, columns: readonly string[], placeholders: string): string;
|
|
96
|
+
/**
|
|
97
|
+
* Convert the fully-assembled, param-flattened SQL text's `?` placeholders to this dialect's
|
|
98
|
+
* final placeholder style. SQLite/MySQL: identity (keep `?`). Postgres: a single left-to-right
|
|
99
|
+
* pass replacing the Nth `?` with `$N` (spec §8 final one-pass). This runs ONCE over the final
|
|
100
|
+
* text, so there is no number-reassignment problem.
|
|
101
|
+
*/
|
|
102
|
+
finalizePlaceholders(sql: string): string;
|
|
103
|
+
/**
|
|
104
|
+
* Deterministic NULL ordering for an `ORDER BY <expr> <dir>` term when the model requires it
|
|
105
|
+
* (spec §13 "`ORDER BY … NULLS` 強制"). Postgres supports `NULLS FIRST/LAST` natively; SQLite
|
|
106
|
+
* (3.30+) also supports it; MySQL does NOT, so the convention is emulated with a leading
|
|
107
|
+
* `<expr> IS NULL` sort key. Returns the full ORDER BY term text.
|
|
108
|
+
*/
|
|
109
|
+
orderByNulls(expr: string, dir: 'ASC' | 'DESC', nulls: 'FIRST' | 'LAST'): string;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Replace each `?` placeholder in a fully-assembled SQL string with `$1, $2, …` left-to-right
|
|
113
|
+
* (Postgres). This is the spec §8 "最終1パス" conversion: it runs ONCE over the final flat SQL
|
|
114
|
+
* text, so placeholder numbering is a plain running counter — the number-reassignment problem
|
|
115
|
+
* cannot reappear (there is no per-fragment renumbering). Every `?` is a bound param position
|
|
116
|
+
* (the render pipeline never emits a literal `?` inside a string literal — values are always
|
|
117
|
+
* parameterized), so a naive scan is correct for the compiled surface.
|
|
118
|
+
*/
|
|
119
|
+
export declare function toDollarPlaceholders(sql: string): string;
|
|
120
|
+
/**
|
|
121
|
+
* SQLite. `ignore` is an INSERT-verb modifier (`INSERT OR IGNORE INTO`); upsert uses
|
|
122
|
+
* `ON CONFLICT (cols) DO UPDATE SET c = excluded.c`. Placeholders stay `?`. NULL ordering uses
|
|
123
|
+
* the native `NULLS FIRST/LAST` (SQLite 3.30+).
|
|
124
|
+
*/
|
|
125
|
+
export declare const SQLITE: Dialect;
|
|
126
|
+
/**
|
|
127
|
+
* Postgres. `ignore` is a TRAILING clause (`… ON CONFLICT (cols) DO NOTHING`); upsert uses
|
|
128
|
+
* `ON CONFLICT (cols) DO UPDATE SET c = EXCLUDED.c`. Placeholders are converted `?`→`$N` in the
|
|
129
|
+
* final one-pass. NULL ordering uses native `NULLS FIRST/LAST`.
|
|
130
|
+
*/
|
|
131
|
+
export declare const POSTGRES: Dialect;
|
|
132
|
+
/**
|
|
133
|
+
* MySQL. `ignore` is an INSERT-verb modifier (`INSERT IGNORE INTO`); upsert uses
|
|
134
|
+
* `… ON DUPLICATE KEY UPDATE c = VALUES(c)` (no conflict-column target — MySQL keys off any
|
|
135
|
+
* unique index). Placeholders stay `?`. NULL ordering is emulated with a leading
|
|
136
|
+
* `<expr> IS NULL` sort key (MySQL has no `NULLS FIRST/LAST`).
|
|
137
|
+
*/
|
|
138
|
+
export declare const MYSQL: Dialect;
|
|
139
|
+
/** Look up a dialect strategy by name (throws on an unknown dialect — no silent default). */
|
|
140
|
+
export declare function dialectFor(name: DialectName): Dialect;
|
|
141
|
+
//# sourceMappingURL=dialect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialect.d.ts","sourceRoot":"","sources":["../../src/scp/dialect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,uFAAuF;AACvF,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;AAE1D,0FAA0F;AAC1F,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG;IAAE,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAEtF;;;;GAIG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAE3B;;;;;;;;;OASG;IACH,oBAAoB,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,EAAE,MAAM,EAAE,cAAc,GAAG,MAAM,CAAC;IAEzF;;;;;OAKG;IACH,UAAU,CAAC,MAAM,EAAE,cAAc,GAAG,SAAS,GAAG,MAAM,CAAC;IAEvD;;;;OAIG;IACH,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAC;IAEzC;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC;IAErF;;;;;OAKG;IACH,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAE1C;;;;;OAKG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,GAAG,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;CAClF;AAID;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAYxD;AAwCD;;;;GAIG;AACH,eAAO,MAAM,MAAM,EAAE,OAoBnB,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,QAAQ,EAAE,OAkBrB,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,KAAK,EAAE,OA0BlB,CAAC;AASH,6FAA6F;AAC7F,wBAAgB,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAMrD"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* litedbmodel v2 SCP — dialect strategy table (WS6, #26; spec §4/§5/§8/§10).
|
|
4
|
+
*
|
|
5
|
+
* The SINGLE SOURCE OF TRUTH for every SQL-dialect difference the Backend Compile + render
|
|
6
|
+
* pipeline needs. The dialect axis is compiled ONCE, TS-side (spec §10: "方言軸はコンパイル時
|
|
7
|
+
* に TS 側で1回検証"). This module encodes the differences as a closed strategy record — NO
|
|
8
|
+
* scattered `?:` in the engine code (the hard rule). A backend compile / renderer asks the
|
|
9
|
+
* {@link Dialect} for the dialect-specific text and never branches on the dialect name inline.
|
|
10
|
+
*
|
|
11
|
+
* ## What actually differs (verified against the v1 SqlBuilders — the golden bar)
|
|
12
|
+
*
|
|
13
|
+
* For the CRUD + write-tx + relation SQL the SCP Backend Compile emits (single-row VALUES,
|
|
14
|
+
* `?` placeholders, `col = ?` WHERE, `col IN (?, …)`), the dialect surface is small and
|
|
15
|
+
* closed:
|
|
16
|
+
*
|
|
17
|
+
* - **INSERT conflict clause**: SQLite `INSERT OR IGNORE … ` / `… ON CONFLICT (cols) DO
|
|
18
|
+
* UPDATE SET c = excluded.c`; Postgres `… ON CONFLICT (cols) DO NOTHING` / `… DO UPDATE
|
|
19
|
+
* SET c = EXCLUDED.c`; MySQL `INSERT IGNORE …` / `… ON DUPLICATE KEY UPDATE c = VALUES(c)`.
|
|
20
|
+
* These are byte-identical to `SqliteSqlBuilder` / `PostgresSqlBuilder` / `MysqlSqlBuilder`
|
|
21
|
+
* `buildInsert` for the single-record case (see the WS6 dialect-golden test).
|
|
22
|
+
* - **Bare `ON CONFLICT DO NOTHING`** (no column list — the gate-first idempotency/unique
|
|
23
|
+
* guard INSERTs of the write-tx plan, spec §6): SQLite/Postgres emit `ON CONFLICT DO
|
|
24
|
+
* NOTHING`; MySQL emits `INSERT IGNORE`.
|
|
25
|
+
* - **Placeholder style**: all dialects author with `?`; Postgres converts `?`→`$1,$2,…` in a
|
|
26
|
+
* final left-to-right one-pass AFTER the SQL text is fully assembled (spec §8 — the
|
|
27
|
+
* number-reassignment problem is designed out because the pass runs once over the final
|
|
28
|
+
* flat text). SQLite/MySQL keep `?`.
|
|
29
|
+
*
|
|
30
|
+
* Everything else (SELECT/UPDATE/DELETE skeletons, `col = ?`, `col IN (?, …)` expansion, the
|
|
31
|
+
* fragment tree, RETURNING for SQLite/Postgres) is identical text across dialects, so it is
|
|
32
|
+
* NOT part of the strategy — only the genuine divergences live here.
|
|
33
|
+
*
|
|
34
|
+
* ## DB behavior differences beyond SQL text (spec §13) — closeable-by-convention line
|
|
35
|
+
*
|
|
36
|
+
* SQL-text identity does not guarantee identical DB behavior (NULL ordering, collation,
|
|
37
|
+
* timezone). Per spec §13, those are closed "by dialect-compile-time convention" only within
|
|
38
|
+
* the closeable line. WS6 encodes the ONE convention that is mechanically closeable in the
|
|
39
|
+
* compiled SQL text: deterministic NULL ordering for an `ORDER BY … NULLS` requirement
|
|
40
|
+
* ({@link Dialect.orderByNulls}). Collation / timezone / float semantics are OUT OF SCOPE
|
|
41
|
+
* (documented, not silently defaulted).
|
|
42
|
+
*/
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.MYSQL = exports.POSTGRES = exports.SQLITE = void 0;
|
|
45
|
+
exports.toDollarPlaceholders = toDollarPlaceholders;
|
|
46
|
+
exports.dialectFor = dialectFor;
|
|
47
|
+
// ── `?`→`$N` final one-pass (Postgres only) ───────────────────────────────────
|
|
48
|
+
/**
|
|
49
|
+
* Replace each `?` placeholder in a fully-assembled SQL string with `$1, $2, …` left-to-right
|
|
50
|
+
* (Postgres). This is the spec §8 "最終1パス" conversion: it runs ONCE over the final flat SQL
|
|
51
|
+
* text, so placeholder numbering is a plain running counter — the number-reassignment problem
|
|
52
|
+
* cannot reappear (there is no per-fragment renumbering). Every `?` is a bound param position
|
|
53
|
+
* (the render pipeline never emits a literal `?` inside a string literal — values are always
|
|
54
|
+
* parameterized), so a naive scan is correct for the compiled surface.
|
|
55
|
+
*/
|
|
56
|
+
function toDollarPlaceholders(sql) {
|
|
57
|
+
let n = 0;
|
|
58
|
+
let out = '';
|
|
59
|
+
for (const ch of sql) {
|
|
60
|
+
if (ch === '?') {
|
|
61
|
+
n += 1;
|
|
62
|
+
out += `$${n}`;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
out += ch;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
// ── Shared conflict-clause rendering (parameterized by the SET-assignment form) ─
|
|
71
|
+
/**
|
|
72
|
+
* Render the trailing conflict clause for the "has a column target" upsert/ignore forms shared
|
|
73
|
+
* by SQLite and Postgres (`ON CONFLICT (cols) DO NOTHING | DO UPDATE SET …`). MySQL overrides
|
|
74
|
+
* with its `ON DUPLICATE KEY UPDATE` form. `excludedRef` produces the per-column right-hand side
|
|
75
|
+
* (`excluded.c` for SQLite, `EXCLUDED.c` for Postgres).
|
|
76
|
+
*/
|
|
77
|
+
function onConflictClause(conflictColumns, action, excludedRef) {
|
|
78
|
+
const target = conflictColumns.length > 0 ? ` (${conflictColumns.join(', ')})` : '';
|
|
79
|
+
if (action === 'ignore') {
|
|
80
|
+
return ` ON CONFLICT${target} DO NOTHING`;
|
|
81
|
+
}
|
|
82
|
+
const sets = action.updateColumns.map((c) => `${c} = ${excludedRef(c)}`);
|
|
83
|
+
return ` ON CONFLICT${target} DO UPDATE SET ${sets.join(', ')}`;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Render a bare do-nothing guard INSERT. `trailingDoNothing` dialects (SQLite/Postgres) emit
|
|
87
|
+
* `INSERT INTO … VALUES (…) ON CONFLICT DO NOTHING`; MySQL emits `INSERT IGNORE INTO … VALUES (…)`.
|
|
88
|
+
*/
|
|
89
|
+
function guardInsertText(table, columns, placeholders, form) {
|
|
90
|
+
const head = form === 'insertIgnore' ? 'INSERT IGNORE INTO' : 'INSERT INTO';
|
|
91
|
+
const tail = form === 'trailingDoNothing' ? ' ON CONFLICT DO NOTHING' : '';
|
|
92
|
+
return `${head} ${table} (${columns.join(', ')}) VALUES (${placeholders})${tail}`;
|
|
93
|
+
}
|
|
94
|
+
// ── The three frozen dialect strategies (SSoT) ─────────────────────────────────
|
|
95
|
+
/**
|
|
96
|
+
* SQLite. `ignore` is an INSERT-verb modifier (`INSERT OR IGNORE INTO`); upsert uses
|
|
97
|
+
* `ON CONFLICT (cols) DO UPDATE SET c = excluded.c`. Placeholders stay `?`. NULL ordering uses
|
|
98
|
+
* the native `NULLS FIRST/LAST` (SQLite 3.30+).
|
|
99
|
+
*/
|
|
100
|
+
exports.SQLITE = Object.freeze({
|
|
101
|
+
name: 'sqlite',
|
|
102
|
+
ignoreIsTrailingClause: false,
|
|
103
|
+
insertVerb(action) {
|
|
104
|
+
return action === 'ignore' ? 'INSERT OR IGNORE INTO' : 'INSERT INTO';
|
|
105
|
+
},
|
|
106
|
+
insertConflictClause(conflictColumns, action) {
|
|
107
|
+
// `ignore` is handled by the verb (`INSERT OR IGNORE`), so no trailing clause for it.
|
|
108
|
+
if (action === 'ignore')
|
|
109
|
+
return '';
|
|
110
|
+
return onConflictClause(conflictColumns, action, (c) => `excluded.${c}`);
|
|
111
|
+
},
|
|
112
|
+
guardInsert(table, columns, placeholders) {
|
|
113
|
+
return guardInsertText(table, columns, placeholders, 'trailingDoNothing');
|
|
114
|
+
},
|
|
115
|
+
finalizePlaceholders(sql) {
|
|
116
|
+
return sql;
|
|
117
|
+
},
|
|
118
|
+
orderByNulls(expr, dir, nulls) {
|
|
119
|
+
return `${expr} ${dir} NULLS ${nulls}`;
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
/**
|
|
123
|
+
* Postgres. `ignore` is a TRAILING clause (`… ON CONFLICT (cols) DO NOTHING`); upsert uses
|
|
124
|
+
* `ON CONFLICT (cols) DO UPDATE SET c = EXCLUDED.c`. Placeholders are converted `?`→`$N` in the
|
|
125
|
+
* final one-pass. NULL ordering uses native `NULLS FIRST/LAST`.
|
|
126
|
+
*/
|
|
127
|
+
exports.POSTGRES = Object.freeze({
|
|
128
|
+
name: 'postgres',
|
|
129
|
+
ignoreIsTrailingClause: true,
|
|
130
|
+
insertVerb(_action) {
|
|
131
|
+
return 'INSERT INTO';
|
|
132
|
+
},
|
|
133
|
+
insertConflictClause(conflictColumns, action) {
|
|
134
|
+
return onConflictClause(conflictColumns, action, (c) => `EXCLUDED.${c}`);
|
|
135
|
+
},
|
|
136
|
+
guardInsert(table, columns, placeholders) {
|
|
137
|
+
return guardInsertText(table, columns, placeholders, 'trailingDoNothing');
|
|
138
|
+
},
|
|
139
|
+
finalizePlaceholders(sql) {
|
|
140
|
+
return toDollarPlaceholders(sql);
|
|
141
|
+
},
|
|
142
|
+
orderByNulls(expr, dir, nulls) {
|
|
143
|
+
return `${expr} ${dir} NULLS ${nulls}`;
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
/**
|
|
147
|
+
* MySQL. `ignore` is an INSERT-verb modifier (`INSERT IGNORE INTO`); upsert uses
|
|
148
|
+
* `… ON DUPLICATE KEY UPDATE c = VALUES(c)` (no conflict-column target — MySQL keys off any
|
|
149
|
+
* unique index). Placeholders stay `?`. NULL ordering is emulated with a leading
|
|
150
|
+
* `<expr> IS NULL` sort key (MySQL has no `NULLS FIRST/LAST`).
|
|
151
|
+
*/
|
|
152
|
+
exports.MYSQL = Object.freeze({
|
|
153
|
+
name: 'mysql',
|
|
154
|
+
ignoreIsTrailingClause: false,
|
|
155
|
+
insertVerb(action) {
|
|
156
|
+
return action === 'ignore' ? 'INSERT IGNORE INTO' : 'INSERT INTO';
|
|
157
|
+
},
|
|
158
|
+
insertConflictClause(_conflictColumns, action) {
|
|
159
|
+
if (action === 'ignore')
|
|
160
|
+
return ''; // handled by the `INSERT IGNORE` verb
|
|
161
|
+
const sets = action.updateColumns.map((c) => `${c} = VALUES(${c})`);
|
|
162
|
+
return ` ON DUPLICATE KEY UPDATE ${sets.join(', ')}`;
|
|
163
|
+
},
|
|
164
|
+
guardInsert(table, columns, placeholders) {
|
|
165
|
+
return guardInsertText(table, columns, placeholders, 'insertIgnore');
|
|
166
|
+
},
|
|
167
|
+
finalizePlaceholders(sql) {
|
|
168
|
+
return sql;
|
|
169
|
+
},
|
|
170
|
+
orderByNulls(expr, dir, nulls) {
|
|
171
|
+
// MySQL: emulate NULLS FIRST/LAST with a leading `IS NULL` key.
|
|
172
|
+
// NULLS FIRST → `expr IS NULL DESC, expr <dir>` (nulls sort as 1, before 0... wait)
|
|
173
|
+
// In MySQL, NULL sorts LOWEST by default. `expr IS NULL` is 1 for null, 0 otherwise.
|
|
174
|
+
// NULLS FIRST: nulls must come first → order the IS-NULL flag DESC (1 before 0).
|
|
175
|
+
// NULLS LAST: nulls must come last → order the IS-NULL flag ASC (0 before 1).
|
|
176
|
+
const flagDir = nulls === 'FIRST' ? 'DESC' : 'ASC';
|
|
177
|
+
return `${expr} IS NULL ${flagDir}, ${expr} ${dir}`;
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
/** Resolve a {@link DialectName} to its frozen {@link Dialect} strategy (fail-closed). */
|
|
181
|
+
const DIALECTS = Object.freeze({
|
|
182
|
+
sqlite: exports.SQLITE,
|
|
183
|
+
postgres: exports.POSTGRES,
|
|
184
|
+
mysql: exports.MYSQL,
|
|
185
|
+
});
|
|
186
|
+
/** Look up a dialect strategy by name (throws on an unknown dialect — no silent default). */
|
|
187
|
+
function dialectFor(name) {
|
|
188
|
+
const d = DIALECTS[name];
|
|
189
|
+
if (d === undefined) {
|
|
190
|
+
throw new Error(`scp dialect: unknown dialect '${String(name)}' (known: ${Object.keys(DIALECTS).join(', ')})`);
|
|
191
|
+
}
|
|
192
|
+
return d;
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=dialect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialect.js","sourceRoot":"","sources":["../../src/scp/dialect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* litedbmodel v2 SCP — Error Mapping (WS3, #23; spec §11 item 5).
|
|
3
|
+
*
|
|
4
|
+
* Maps a SQLite driver error (better-sqlite3 `SqliteError`, carrying a `SQLITE_*` `code`)
|
|
5
|
+
* to an SCP {@link SqlFailure}: a structured Failure with a stable `kind` and the bc
|
|
6
|
+
* Execution-Plan {@link PolicyKind} the runtime honors (fail / retry / continue). The
|
|
7
|
+
* handler returns `{ error }` to bc's `runBehavior`; a `fail`-policy node re-throws through
|
|
8
|
+
* `runPlan` (`OP_FAILED`), so the driver surfaces this structured failure at the boundary.
|
|
9
|
+
*
|
|
10
|
+
* The mapping is closed and explicit (no silent catch-all that hides a driver error): an
|
|
11
|
+
* unrecognized SQLite code maps to `kind: 'driver_error'` with `policy: 'fail'` — loud, and
|
|
12
|
+
* carrying the original code + message for diagnosis.
|
|
13
|
+
*/
|
|
14
|
+
import type { PolicyKind } from 'behavior-contracts';
|
|
15
|
+
/** The SCP failure kinds litedbmodel maps SQL driver errors to (spec §11 item 5). */
|
|
16
|
+
export type SqlFailureKind = 'constraint_violation' | 'foreign_key_violation' | 'retryable' | 'driver_error';
|
|
17
|
+
/**
|
|
18
|
+
* A mapped SCP failure: the SCP `kind`, the honored bc `PolicyKind`, the original SQLite
|
|
19
|
+
* `code`, and a human message. Thrown at the runtime boundary (or carried as `{error}`
|
|
20
|
+
* into `runBehavior` for Policy-Kind interpretation by `runPlan`).
|
|
21
|
+
*/
|
|
22
|
+
export declare class SqlFailure extends Error {
|
|
23
|
+
readonly kind: SqlFailureKind;
|
|
24
|
+
readonly policy: PolicyKind;
|
|
25
|
+
readonly sqliteCode: string | undefined;
|
|
26
|
+
constructor(kind: SqlFailureKind, policy: PolicyKind, sqliteCode: string | undefined, message: string);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Map a caught driver error to an {@link SqlFailure}. The `SQLITE_CONSTRAINT_*` family maps
|
|
30
|
+
* to constraint / FK kinds (Policy `fail` — a data conflict is not retryable); the
|
|
31
|
+
* `SQLITE_BUSY` / `SQLITE_LOCKED` family maps to `retryable` (Policy `retry`). Anything else
|
|
32
|
+
* (including a non-SQLite error) maps to `driver_error` (Policy `fail`), preserving the
|
|
33
|
+
* original message.
|
|
34
|
+
*/
|
|
35
|
+
export declare function mapSqliteError(e: unknown): SqlFailure;
|
|
36
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/scp/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,qFAAqF;AACrF,MAAM,MAAM,cAAc,GACtB,sBAAsB,GACtB,uBAAuB,GACvB,WAAW,GACX,cAAc,CAAC;AAEnB;;;;GAIG;AACH,qBAAa,UAAW,SAAQ,KAAK;IAEjC,QAAQ,CAAC,IAAI,EAAE,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,UAAU;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS;gBAF9B,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,MAAM,GAAG,SAAS,EACvC,OAAO,EAAE,MAAM;CAKlB;AAYD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,GAAG,UAAU,CAqBrD"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* litedbmodel v2 SCP — Error Mapping (WS3, #23; spec §11 item 5).
|
|
4
|
+
*
|
|
5
|
+
* Maps a SQLite driver error (better-sqlite3 `SqliteError`, carrying a `SQLITE_*` `code`)
|
|
6
|
+
* to an SCP {@link SqlFailure}: a structured Failure with a stable `kind` and the bc
|
|
7
|
+
* Execution-Plan {@link PolicyKind} the runtime honors (fail / retry / continue). The
|
|
8
|
+
* handler returns `{ error }` to bc's `runBehavior`; a `fail`-policy node re-throws through
|
|
9
|
+
* `runPlan` (`OP_FAILED`), so the driver surfaces this structured failure at the boundary.
|
|
10
|
+
*
|
|
11
|
+
* The mapping is closed and explicit (no silent catch-all that hides a driver error): an
|
|
12
|
+
* unrecognized SQLite code maps to `kind: 'driver_error'` with `policy: 'fail'` — loud, and
|
|
13
|
+
* carrying the original code + message for diagnosis.
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.SqlFailure = void 0;
|
|
17
|
+
exports.mapSqliteError = mapSqliteError;
|
|
18
|
+
/**
|
|
19
|
+
* A mapped SCP failure: the SCP `kind`, the honored bc `PolicyKind`, the original SQLite
|
|
20
|
+
* `code`, and a human message. Thrown at the runtime boundary (or carried as `{error}`
|
|
21
|
+
* into `runBehavior` for Policy-Kind interpretation by `runPlan`).
|
|
22
|
+
*/
|
|
23
|
+
class SqlFailure extends Error {
|
|
24
|
+
kind;
|
|
25
|
+
policy;
|
|
26
|
+
sqliteCode;
|
|
27
|
+
constructor(kind, policy, sqliteCode, message) {
|
|
28
|
+
super(message);
|
|
29
|
+
this.kind = kind;
|
|
30
|
+
this.policy = policy;
|
|
31
|
+
this.sqliteCode = sqliteCode;
|
|
32
|
+
this.name = 'SqlFailure';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.SqlFailure = SqlFailure;
|
|
36
|
+
/** True if `e` looks like a better-sqlite3 `SqliteError` (has a `SQLITE_*` string `code`). */
|
|
37
|
+
function isSqliteError(e) {
|
|
38
|
+
return (typeof e === 'object' &&
|
|
39
|
+
e !== null &&
|
|
40
|
+
typeof e.code === 'string' &&
|
|
41
|
+
e.code.startsWith('SQLITE_'));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Map a caught driver error to an {@link SqlFailure}. The `SQLITE_CONSTRAINT_*` family maps
|
|
45
|
+
* to constraint / FK kinds (Policy `fail` — a data conflict is not retryable); the
|
|
46
|
+
* `SQLITE_BUSY` / `SQLITE_LOCKED` family maps to `retryable` (Policy `retry`). Anything else
|
|
47
|
+
* (including a non-SQLite error) maps to `driver_error` (Policy `fail`), preserving the
|
|
48
|
+
* original message.
|
|
49
|
+
*/
|
|
50
|
+
function mapSqliteError(e) {
|
|
51
|
+
if (!isSqliteError(e)) {
|
|
52
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
53
|
+
return new SqlFailure('driver_error', 'fail', undefined, `non-SQLite driver error: ${message}`);
|
|
54
|
+
}
|
|
55
|
+
const { code, message } = e;
|
|
56
|
+
// The message embeds the `SQLITE_*` code so it survives being wrapped by bc's `runPlan`
|
|
57
|
+
// (`OP_FAILED: <handler message>`); the runtime re-maps from it to re-surface the
|
|
58
|
+
// structured SqlFailure (kind / policy / code) at the boundary.
|
|
59
|
+
const tagged = `[${code}] ${message}`;
|
|
60
|
+
if (code === 'SQLITE_CONSTRAINT_FOREIGNKEY') {
|
|
61
|
+
return new SqlFailure('foreign_key_violation', 'fail', code, tagged);
|
|
62
|
+
}
|
|
63
|
+
if (code.startsWith('SQLITE_CONSTRAINT')) {
|
|
64
|
+
// UNIQUE / PRIMARYKEY / CHECK / NOTNULL / … — a durable constraint conflict.
|
|
65
|
+
return new SqlFailure('constraint_violation', 'fail', code, tagged);
|
|
66
|
+
}
|
|
67
|
+
if (code === 'SQLITE_BUSY' || code === 'SQLITE_LOCKED') {
|
|
68
|
+
return new SqlFailure('retryable', 'retry', code, tagged);
|
|
69
|
+
}
|
|
70
|
+
return new SqlFailure('driver_error', 'fail', code, tagged);
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/scp/errors.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;;AA6CH,wCAqBC;AAvDD;;;;GAIG;AACH,MAAa,UAAW,SAAQ,KAAK;IAExB;IACA;IACA;IAHX,YACW,IAAoB,EACpB,MAAkB,EAClB,UAA8B,EACvC,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QALN,SAAI,GAAJ,IAAI,CAAgB;QACpB,WAAM,GAAN,MAAM,CAAY;QAClB,eAAU,GAAV,UAAU,CAAoB;QAIvC,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC3B,CAAC;CACF;AAVD,gCAUC;AAED,8FAA8F;AAC9F,SAAS,aAAa,CAAC,CAAU;IAC/B,OAAO,CACL,OAAO,CAAC,KAAK,QAAQ;QACrB,CAAC,KAAK,IAAI;QACV,OAAQ,CAAwB,CAAC,IAAI,KAAK,QAAQ;QACjD,CAAsB,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CACnD,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,cAAc,CAAC,CAAU;IACvC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC3D,OAAO,IAAI,UAAU,CAAC,cAAc,EAAE,MAAM,EAAE,SAAS,EAAE,4BAA4B,OAAO,EAAE,CAAC,CAAC;IAClG,CAAC;IACD,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IAC5B,wFAAwF;IACxF,kFAAkF;IAClF,gEAAgE;IAChE,MAAM,MAAM,GAAG,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;IACtC,IAAI,IAAI,KAAK,8BAA8B,EAAE,CAAC;QAC5C,OAAO,IAAI,UAAU,CAAC,uBAAuB,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACzC,6EAA6E;QAC7E,OAAO,IAAI,UAAU,CAAC,sBAAsB,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,eAAe,EAAE,CAAC;QACvD,OAAO,IAAI,UAAU,CAAC,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,IAAI,UAAU,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AAC9D,CAAC"}
|