@rudderjs/database 1.1.0 → 1.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 +70 -0
- package/dist/db.d.ts +21 -3
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +27 -5
- package/dist/db.js.map +1 -1
- package/dist/index.d.ts +14 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -4
- package/dist/index.js.map +1 -1
- package/dist/native/adapter.d.ts +202 -0
- package/dist/native/adapter.d.ts.map +1 -0
- package/dist/native/adapter.js +440 -0
- package/dist/native/adapter.js.map +1 -0
- package/dist/native/compiler.d.ts +371 -0
- package/dist/native/compiler.d.ts.map +1 -0
- package/dist/native/compiler.js +978 -0
- package/dist/native/compiler.js.map +1 -0
- package/dist/native/dialect-mysql.d.ts +26 -0
- package/dist/native/dialect-mysql.d.ts.map +1 -0
- package/dist/native/dialect-mysql.js +188 -0
- package/dist/native/dialect-mysql.js.map +1 -0
- package/dist/native/dialect-pg.d.ts +26 -0
- package/dist/native/dialect-pg.d.ts.map +1 -0
- package/dist/native/dialect-pg.js +192 -0
- package/dist/native/dialect-pg.js.map +1 -0
- package/dist/native/dialect.d.ts +255 -0
- package/dist/native/dialect.d.ts.map +1 -0
- package/dist/native/dialect.js +237 -0
- package/dist/native/dialect.js.map +1 -0
- package/dist/native/driver.d.ts +37 -0
- package/dist/native/driver.d.ts.map +1 -0
- package/dist/native/driver.js +19 -0
- package/dist/native/driver.js.map +1 -0
- package/dist/native/drivers/better-sqlite3.d.ts +56 -0
- package/dist/native/drivers/better-sqlite3.d.ts.map +1 -0
- package/dist/native/drivers/better-sqlite3.js +171 -0
- package/dist/native/drivers/better-sqlite3.js.map +1 -0
- package/dist/native/drivers/mysql.d.ts +30 -0
- package/dist/native/drivers/mysql.d.ts.map +1 -0
- package/dist/native/drivers/mysql.js +176 -0
- package/dist/native/drivers/mysql.js.map +1 -0
- package/dist/native/drivers/postgres.d.ts +57 -0
- package/dist/native/drivers/postgres.d.ts.map +1 -0
- package/dist/native/drivers/postgres.js +155 -0
- package/dist/native/drivers/postgres.js.map +1 -0
- package/dist/native/errors.d.ts +43 -0
- package/dist/native/errors.d.ts.map +1 -0
- package/dist/native/errors.js +64 -0
- package/dist/native/errors.js.map +1 -0
- package/dist/native/index.d.ts +27 -0
- package/dist/native/index.d.ts.map +1 -0
- package/dist/native/index.js +55 -0
- package/dist/native/index.js.map +1 -0
- package/dist/native/isolation.d.ts +14 -0
- package/dist/native/isolation.d.ts.map +1 -0
- package/dist/native/isolation.js +37 -0
- package/dist/native/isolation.js.map +1 -0
- package/dist/native/query-builder.d.ts +303 -0
- package/dist/native/query-builder.d.ts.map +1 -0
- package/dist/native/query-builder.js +984 -0
- package/dist/native/query-builder.js.map +1 -0
- package/dist/native/replica-picker.d.ts +22 -0
- package/dist/native/replica-picker.d.ts.map +1 -0
- package/dist/native/replica-picker.js +65 -0
- package/dist/native/replica-picker.js.map +1 -0
- package/dist/native/schema/alter-blueprint.d.ts +37 -0
- package/dist/native/schema/alter-blueprint.d.ts.map +1 -0
- package/dist/native/schema/alter-blueprint.js +56 -0
- package/dist/native/schema/alter-blueprint.js.map +1 -0
- package/dist/native/schema/blueprint.d.ts +151 -0
- package/dist/native/schema/blueprint.d.ts.map +1 -0
- package/dist/native/schema/blueprint.js +286 -0
- package/dist/native/schema/blueprint.js.map +1 -0
- package/dist/native/schema/column.d.ts +168 -0
- package/dist/native/schema/column.d.ts.map +1 -0
- package/dist/native/schema/column.js +190 -0
- package/dist/native/schema/column.js.map +1 -0
- package/dist/native/schema/ddl-compiler.d.ts +34 -0
- package/dist/native/schema/ddl-compiler.d.ts.map +1 -0
- package/dist/native/schema/ddl-compiler.js +352 -0
- package/dist/native/schema/ddl-compiler.js.map +1 -0
- package/dist/native/schema/inspect.d.ts +67 -0
- package/dist/native/schema/inspect.d.ts.map +1 -0
- package/dist/native/schema/inspect.js +312 -0
- package/dist/native/schema/inspect.js.map +1 -0
- package/dist/native/schema/introspect.d.ts +34 -0
- package/dist/native/schema/introspect.d.ts.map +1 -0
- package/dist/native/schema/introspect.js +101 -0
- package/dist/native/schema/introspect.js.map +1 -0
- package/dist/native/schema/migration.d.ts +8 -0
- package/dist/native/schema/migration.d.ts.map +1 -0
- package/dist/native/schema/migration.js +19 -0
- package/dist/native/schema/migration.js.map +1 -0
- package/dist/native/schema/migrator.d.ts +144 -0
- package/dist/native/schema/migrator.d.ts.map +1 -0
- package/dist/native/schema/migrator.js +239 -0
- package/dist/native/schema/migrator.js.map +1 -0
- package/dist/native/schema/rebuild.d.ts +11 -0
- package/dist/native/schema/rebuild.d.ts.map +1 -0
- package/dist/native/schema/rebuild.js +92 -0
- package/dist/native/schema/rebuild.js.map +1 -0
- package/dist/native/schema/schema-builder.d.ts +46 -0
- package/dist/native/schema/schema-builder.d.ts.map +1 -0
- package/dist/native/schema/schema-builder.js +153 -0
- package/dist/native/schema/schema-builder.js.map +1 -0
- package/dist/native/schema/schema-facade.d.ts +63 -0
- package/dist/native/schema/schema-facade.d.ts.map +1 -0
- package/dist/native/schema/schema-facade.js +124 -0
- package/dist/native/schema/schema-facade.js.map +1 -0
- package/dist/native/schema/schema-types.d.ts +27 -0
- package/dist/native/schema/schema-types.d.ts.map +1 -0
- package/dist/native/schema/schema-types.js +52 -0
- package/dist/native/schema/schema-types.js.map +1 -0
- package/dist/native/schema/types-generator.d.ts +73 -0
- package/dist/native/schema/types-generator.d.ts.map +1 -0
- package/dist/native/schema/types-generator.js +181 -0
- package/dist/native/schema/types-generator.js.map +1 -0
- package/dist/registry-bridge.d.ts +24 -4
- package/dist/registry-bridge.d.ts.map +1 -1
- package/dist/registry-bridge.js +20 -0
- package/dist/registry-bridge.js.map +1 -1
- package/dist/sticky.d.ts +22 -0
- package/dist/sticky.d.ts.map +1 -0
- package/dist/sticky.js +61 -0
- package/dist/sticky.js.map +1 -0
- package/package.json +32 -2
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import type { ColumnDefinition } from './schema/column.js';
|
|
2
|
+
import type { LockOptions } from '@rudderjs/contracts';
|
|
3
|
+
/**
|
|
4
|
+
* The date/time component a `whereDate`/`whereTime`/`whereDay`/`whereMonth`/
|
|
5
|
+
* `whereYear` predicate extracts from a column before comparing. `date` and
|
|
6
|
+
* `time` compare as strings (`'YYYY-MM-DD'` / `'HH:MM:SS'`); `day`/`month`/
|
|
7
|
+
* `year` compare as integers.
|
|
8
|
+
*/
|
|
9
|
+
export type DatePart = 'date' | 'time' | 'day' | 'month' | 'year';
|
|
10
|
+
/**
|
|
11
|
+
* One step of a JSON arrow path (`meta->prefs->lang`, `meta->items->0`): a
|
|
12
|
+
* validated object key, or a number for an array index (`$[0]` / pg `->0`).
|
|
13
|
+
*/
|
|
14
|
+
export type JsonPathSegment = string | number;
|
|
15
|
+
/**
|
|
16
|
+
* The JS type of a JSON comparison value, hinting the dialect's extraction
|
|
17
|
+
* shape: pg casts its text extraction (`::numeric` / `::boolean`) so operators
|
|
18
|
+
* compare typed values; mysql compares booleans against the raw
|
|
19
|
+
* `JSON_EXTRACT` (no `JSON_UNQUOTE`); sqlite ignores the hint (`json_extract`
|
|
20
|
+
* already returns typed values).
|
|
21
|
+
*/
|
|
22
|
+
export type JsonValueKind = 'text' | 'number' | 'boolean';
|
|
23
|
+
/**
|
|
24
|
+
* One JSON path write inside an UPDATE payload (`'meta->prefs->lang': 'en'`
|
|
25
|
+
* → `{ segments: ['prefs', 'lang'], value: 'en' }`), consumed by
|
|
26
|
+
* {@link Dialect.jsonSet}. Segments are validated by {@link parseJsonPath}.
|
|
27
|
+
*/
|
|
28
|
+
export interface JsonPathWrite {
|
|
29
|
+
segments: readonly JsonPathSegment[];
|
|
30
|
+
value: unknown;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A SQL dialect: the knobs that change the emitted SQL text between databases.
|
|
34
|
+
* `SqliteDialect` is the first concrete impl; `PgDialect` / `MysqlDialect`
|
|
35
|
+
* plug in here later.
|
|
36
|
+
*/
|
|
37
|
+
export interface Dialect {
|
|
38
|
+
/** Short dialect tag — drives any capability branching in the compiler. */
|
|
39
|
+
readonly name: 'sqlite' | 'pg' | 'mysql';
|
|
40
|
+
/**
|
|
41
|
+
* Quote a single identifier (table or column). The identifier is validated
|
|
42
|
+
* first (letters/digits/underscores only, not starting with a digit) and
|
|
43
|
+
* then wrapped in the dialect's quote character so reserved words and casing
|
|
44
|
+
* survive. Dotted identifiers (`table.column`) are quoted segment-by-segment.
|
|
45
|
+
*
|
|
46
|
+
* Identifiers can't be bound as parameters, so this is the security boundary
|
|
47
|
+
* for the only user-influenced text that reaches the SQL string.
|
|
48
|
+
*/
|
|
49
|
+
quoteId(identifier: string): string;
|
|
50
|
+
/**
|
|
51
|
+
* Positional placeholder for the value at zero-based `index`. SQLite/MySQL
|
|
52
|
+
* use a literal `?` (index ignored); Postgres uses `$1`, `$2`, … (1-based).
|
|
53
|
+
*/
|
|
54
|
+
placeholder(index: number): string;
|
|
55
|
+
/** Whether the dialect supports `INSERT/UPDATE/DELETE ... RETURNING`.
|
|
56
|
+
* Unused on the read path; defined now so Phase 2 branches on the seam. */
|
|
57
|
+
readonly supportsReturning: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* DDL: the SQL fragment that follows a quoted column name in `CREATE TABLE` —
|
|
60
|
+
* the dialect's storage type plus any type-bundled clause. For an
|
|
61
|
+
* auto-incrementing column the dialect returns the *complete* spec
|
|
62
|
+
* (SQLite: `INTEGER PRIMARY KEY AUTOINCREMENT`; pg: `bigserial PRIMARY KEY`),
|
|
63
|
+
* and the DDL compiler appends no further modifiers to it. For every other
|
|
64
|
+
* column it returns just the type keyword and the compiler appends the shared
|
|
65
|
+
* `NOT NULL` / `DEFAULT` / `PRIMARY KEY` modifiers.
|
|
66
|
+
*
|
|
67
|
+
* This is the per-dialect half of the schema builder (parent plan Part 2's
|
|
68
|
+
* column-type table); pg/mysql implement the same method.
|
|
69
|
+
*/
|
|
70
|
+
columnTypeSql(column: ColumnDefinition): string;
|
|
71
|
+
/**
|
|
72
|
+
* Render a `boolean` column DEFAULT as a SQL literal. DDL can't bind values,
|
|
73
|
+
* so the DDL compiler asks the dialect how to spell a boolean default: SQLite
|
|
74
|
+
* and MySQL store booleans as `0`/`1` integers, but Postgres has a real
|
|
75
|
+
* `boolean` type that rejects `DEFAULT 1` and wants `DEFAULT true`/`false`.
|
|
76
|
+
* This is the only spot in `defaultLiteral` that diverges per dialect.
|
|
77
|
+
*/
|
|
78
|
+
booleanLiteral(value: boolean): string;
|
|
79
|
+
/**
|
|
80
|
+
* The conflict-resolution suffix appended to an `INSERT … VALUES …` for an
|
|
81
|
+
* upsert (before any `RETURNING`). Diverges sharply per dialect:
|
|
82
|
+
*
|
|
83
|
+
* - SQLite / Postgres: `ON CONFLICT (<uniqueBy>) DO UPDATE SET col = excluded.col, …`
|
|
84
|
+
* (or `… DO NOTHING` when `update` is empty). The conflict target is the
|
|
85
|
+
* `uniqueBy` columns; a matching unique index/constraint must exist.
|
|
86
|
+
* - MySQL: `ON DUPLICATE KEY UPDATE col = VALUES(col), …`. MySQL keys off any
|
|
87
|
+
* existing unique index, so `uniqueBy` is ignored here (the caller still
|
|
88
|
+
* needs the unique constraint to exist). An empty `update` degrades to a
|
|
89
|
+
* no-op assignment on the first `uniqueBy` column so the row is left intact.
|
|
90
|
+
*
|
|
91
|
+
* `uniqueBy` and `update` are already-resolved, validated column-name arrays
|
|
92
|
+
* (the Model layer computes the default `update` set). Values are never
|
|
93
|
+
* interpolated here — only identifiers, quoted via {@link quoteId}.
|
|
94
|
+
*/
|
|
95
|
+
upsertClause(uniqueBy: readonly string[], update: readonly string[]): string;
|
|
96
|
+
/**
|
|
97
|
+
* The SQL expression extracting a date/time component from a column — the
|
|
98
|
+
* per-dialect half of `whereDate`/`whereTime`/`whereDay`/`whereMonth`/
|
|
99
|
+
* `whereYear`. `column` arrives ALREADY QUOTED (the compiler runs it through
|
|
100
|
+
* {@link quoteId} first), so the dialect only splices it into its extraction
|
|
101
|
+
* function. The result must compare cleanly against a bound value:
|
|
102
|
+
* `'YYYY-MM-DD'` text for `date`, `'HH:MM:SS'` text for `time`, and an
|
|
103
|
+
* INTEGER for `day`/`month`/`year` (so a bound `5` matches May — dialects
|
|
104
|
+
* whose extractor yields text, like SQLite's `strftime`, must CAST).
|
|
105
|
+
*/
|
|
106
|
+
dateExtract(part: DatePart, column: string): string;
|
|
107
|
+
/**
|
|
108
|
+
* The SQL expression extracting a JSON path from a column for a scalar
|
|
109
|
+
* comparison — the per-dialect half of `where('meta->prefs->lang', …)`.
|
|
110
|
+
* `column` arrives ALREADY QUOTED (the compiler runs it through
|
|
111
|
+
* {@link quoteId} first); `segments` are validated by {@link parseJsonPath}
|
|
112
|
+
* (quote/backslash/control characters rejected), so the dialect only splices
|
|
113
|
+
* them into its path syntax. `valueKind` hints the comparison value's JS
|
|
114
|
+
* type — see {@link JsonValueKind} for what each dialect does with it.
|
|
115
|
+
*/
|
|
116
|
+
jsonExtract(column: string, segments: readonly JsonPathSegment[], valueKind: JsonValueKind): string;
|
|
117
|
+
/**
|
|
118
|
+
* The `IS [NOT] NULL` predicate for a JSON path — `whereNull('meta->x')` /
|
|
119
|
+
* `where('meta->x', null)`. Laravel semantics: a MISSING key and an explicit
|
|
120
|
+
* json `null` BOTH count as null (`whereNotNull` matches only an actual
|
|
121
|
+
* value). sqlite and pg get this for free — their extractions surface both
|
|
122
|
+
* as SQL NULL — but mysql's `JSON_EXTRACT` returns a JSON `null` LITERAL
|
|
123
|
+
* (not SQL NULL) for an explicit null, and `JSON_UNQUOTE` turns it into the
|
|
124
|
+
* STRING `'null'`, so a plain `extract IS NULL` matched missing keys only.
|
|
125
|
+
* mysql emits Laravel's grammar shape instead:
|
|
126
|
+
* `(extract IS NULL OR JSON_TYPE(extract) = 'NULL')`.
|
|
127
|
+
*/
|
|
128
|
+
jsonNullComparison(column: string, segments: readonly JsonPathSegment[], negated: boolean): string;
|
|
129
|
+
/**
|
|
130
|
+
* Normalize a boolean JSON comparison value for binding, paired with
|
|
131
|
+
* {@link jsonExtract}'s `'boolean'` shape: sqlite `1`/`0` (json_extract
|
|
132
|
+
* yields integers for json booleans), mysql `'true'`/`'false'` (compared
|
|
133
|
+
* against the raw JSON_EXTRACT — MySQL coerces the string via
|
|
134
|
+
* `CAST(… AS JSON)`), pg the boolean itself (the extraction is `::boolean`-cast).
|
|
135
|
+
*/
|
|
136
|
+
jsonBoolean(value: boolean): unknown;
|
|
137
|
+
/**
|
|
138
|
+
* The containment predicate for `whereJsonContains(column, value)`. `column`
|
|
139
|
+
* arrives quoted; `segments` (possibly empty — a whole-column check)
|
|
140
|
+
* validated. `value` may be a scalar or an array (array = every element
|
|
141
|
+
* contained, matching pg `@>` / mysql `JSON_CONTAINS`). Values are never
|
|
142
|
+
* interpolated — the dialect binds through the `bind` callback (which
|
|
143
|
+
* returns the placeholder for the value it's handed), keeping positional
|
|
144
|
+
* order correct across the statement.
|
|
145
|
+
*
|
|
146
|
+
* - pg: `(col->'a')::jsonb @> $n::jsonb` (value bound as JSON text).
|
|
147
|
+
* - mysql: `JSON_CONTAINS(col, ?, '$."a"')` (value bound as JSON text).
|
|
148
|
+
* - sqlite: emulated via `EXISTS (SELECT 1 FROM json_each(col, '$."a"')
|
|
149
|
+
* WHERE json_each.value = ?)` per element (AND-joined for arrays) —
|
|
150
|
+
* scalar elements only; object values throw.
|
|
151
|
+
*
|
|
152
|
+
* The compiler wraps the returned expression in `NOT (…)` for
|
|
153
|
+
* `whereJsonDoesntContain`, so multi-part emulations must self-parenthesize.
|
|
154
|
+
*/
|
|
155
|
+
jsonContains(column: string, segments: readonly JsonPathSegment[], value: unknown, bind: (v: unknown) => string): string;
|
|
156
|
+
/**
|
|
157
|
+
* The array-length expression for `whereJsonLength(column, op, n)` — the
|
|
158
|
+
* comparison value binds in the compiler. sqlite `json_array_length(col,
|
|
159
|
+
* '$."a"')`, pg `jsonb_array_length((col->'a')::jsonb)`, mysql
|
|
160
|
+
* `JSON_LENGTH(col, '$."a"')`. `segments` may be empty (whole column).
|
|
161
|
+
*/
|
|
162
|
+
jsonLength(column: string, segments: readonly JsonPathSegment[]): string;
|
|
163
|
+
/**
|
|
164
|
+
* The SET right-hand side writing one or more JSON paths into a single
|
|
165
|
+
* column — the per-dialect half of `update(id, { 'meta->prefs->lang': … })`.
|
|
166
|
+
* `column` arrives ALREADY QUOTED; `writes` carry segments validated by
|
|
167
|
+
* {@link parseJsonPath}. Values are never interpolated — each binds as JSON
|
|
168
|
+
* text (`JSON.stringify`) through the `bind` callback in write order, so
|
|
169
|
+
* positional bindings stay in SQL-text order, and the JSON-text shape keeps
|
|
170
|
+
* every value type (string/number/boolean/null/array/object) round-tripping
|
|
171
|
+
* identically across dialects:
|
|
172
|
+
*
|
|
173
|
+
* - sqlite: `json_set(col, '$."a"', json(?), '$."b"', json(?))`
|
|
174
|
+
* - mysql: `JSON_SET(col, '$."a"', CAST(? AS JSON), …)`
|
|
175
|
+
* - pg: nested `jsonb_set((col)::jsonb, ARRAY['a'], $n::jsonb)` (one
|
|
176
|
+
* wrap per write — jsonb_set takes a single path).
|
|
177
|
+
*
|
|
178
|
+
* Like Laravel's grammars, missing INTERMEDIATE keys are not created (only
|
|
179
|
+
* the leaf key is); a NULL column stays NULL on pg (`jsonb_set(NULL, …)` is
|
|
180
|
+
* NULL) — write the whole column to initialize it.
|
|
181
|
+
*/
|
|
182
|
+
jsonSet(column: string, writes: readonly JsonPathWrite[], bind: (v: unknown) => string): string;
|
|
183
|
+
/**
|
|
184
|
+
* The pessimistic-locking suffix appended to a `SELECT` (after ORDER BY /
|
|
185
|
+
* LIMIT), or `''` when the dialect has no row-level locking. Powers
|
|
186
|
+
* `QueryBuilder.lockForUpdate()` / `sharedLock()`:
|
|
187
|
+
*
|
|
188
|
+
* - Postgres / MySQL 8: `' FOR UPDATE'` / `' FOR SHARE'`, with `opts`
|
|
189
|
+
* appending the wait behavior — `' SKIP LOCKED'` (skip already-locked
|
|
190
|
+
* rows) or `' NOWAIT'` (error instead of blocking). The QueryBuilder
|
|
191
|
+
* validates mutual exclusivity before the options reach here.
|
|
192
|
+
* - SQLite: `''` — there is no per-row lock; a write transaction already
|
|
193
|
+
* serializes writers, so the reservation is safe without a suffix. The
|
|
194
|
+
* options are ignored along with the lock itself.
|
|
195
|
+
*
|
|
196
|
+
* Always prefixed with a leading space so the compiler can concatenate it
|
|
197
|
+
* unconditionally.
|
|
198
|
+
*/
|
|
199
|
+
lockSql(mode: 'update' | 'shared', opts?: LockOptions): string;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Quote a string as a SQL literal (single-quoted, embedded `'` doubled). Used
|
|
203
|
+
* for DDL value lists that can't be bound — `enum`/`set` allowed-value lists and
|
|
204
|
+
* the `CHECK (… IN (…))` constraint on pg/sqlite. Migration-author supplied, so
|
|
205
|
+
* escaping (not an allowlist) is the right boundary, matching the column-DEFAULT
|
|
206
|
+
* literal path in the DDL compiler.
|
|
207
|
+
*/
|
|
208
|
+
export declare function quoteSqlString(value: string): string;
|
|
209
|
+
/** Render an `enum`/`set` value list as a `(quoted, list)` for inline use. */
|
|
210
|
+
export declare function quoteValueList(values: readonly string[]): string;
|
|
211
|
+
/**
|
|
212
|
+
* Validate a (possibly dotted) identifier and return its segments. Throws
|
|
213
|
+
* {@link NativeIdentifierError} on anything that isn't a plain
|
|
214
|
+
* `[letter|_][letter|digit|_]*` per dot-separated segment.
|
|
215
|
+
*/
|
|
216
|
+
export declare function validateIdentifier(identifier: string): string[];
|
|
217
|
+
/**
|
|
218
|
+
* Split a `column->path->to->key` arrow column into the base column and its
|
|
219
|
+
* validated JSON path segments. The column half goes through the normal
|
|
220
|
+
* {@link validateIdentifier} gate at quote time; each path segment is checked
|
|
221
|
+
* against {@link JSON_SEGMENT_REJECT} here. All-digit segments become numeric
|
|
222
|
+
* array indexes (`meta->items->0` → `$[0]` / pg `->0`).
|
|
223
|
+
*/
|
|
224
|
+
export declare function parseJsonPath(path: string): {
|
|
225
|
+
column: string;
|
|
226
|
+
segments: JsonPathSegment[];
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* Render validated segments as a single-quoted SQL JSON-path literal —
|
|
230
|
+
* `'$."a"."b"[0]'`. Keys are double-quoted inside the path so spaces/dots
|
|
231
|
+
* survive; safe to inline because {@link parseJsonPath} rejected every
|
|
232
|
+
* character that could escape either quoting layer. Shared by the sqlite and
|
|
233
|
+
* mysql dialects (pg uses `->` operator chains instead).
|
|
234
|
+
*/
|
|
235
|
+
export declare function jsonPathLiteral(segments: readonly JsonPathSegment[]): string;
|
|
236
|
+
/** SQLite dialect — `"`-quoted identifiers, `?` placeholders, RETURNING since
|
|
237
|
+
* 3.35. Also the dialect used by libsql/Turso (Phase 6). */
|
|
238
|
+
export declare class SqliteDialect implements Dialect {
|
|
239
|
+
readonly name: "sqlite";
|
|
240
|
+
readonly supportsReturning = true;
|
|
241
|
+
quoteId(identifier: string): string;
|
|
242
|
+
placeholder(_index: number): string;
|
|
243
|
+
booleanLiteral(value: boolean): string;
|
|
244
|
+
dateExtract(part: DatePart, column: string): string;
|
|
245
|
+
jsonExtract(column: string, segments: readonly JsonPathSegment[], _valueKind: JsonValueKind): string;
|
|
246
|
+
jsonNullComparison(column: string, segments: readonly JsonPathSegment[], negated: boolean): string;
|
|
247
|
+
jsonBoolean(value: boolean): unknown;
|
|
248
|
+
jsonContains(column: string, segments: readonly JsonPathSegment[], value: unknown, bind: (v: unknown) => string): string;
|
|
249
|
+
jsonLength(column: string, segments: readonly JsonPathSegment[]): string;
|
|
250
|
+
jsonSet(column: string, writes: readonly JsonPathWrite[], bind: (v: unknown) => string): string;
|
|
251
|
+
lockSql(_mode: 'update' | 'shared', _opts?: LockOptions): string;
|
|
252
|
+
upsertClause(uniqueBy: readonly string[], update: readonly string[]): string;
|
|
253
|
+
columnTypeSql(column: ColumnDefinition): string;
|
|
254
|
+
}
|
|
255
|
+
//# sourceMappingURL=dialect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialect.d.ts","sourceRoot":"","sources":["../../src/native/dialect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
// ─── Dialect seam (per-SQL-flavor) ─────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// The `Dialect` captures every place the SQL TEXT differs between databases:
|
|
4
|
+
// identifier quoting, placeholder syntax, RETURNING support, etc. The compiler
|
|
5
|
+
// builds SQL strings through this interface only, so adding Postgres / MySQL
|
|
6
|
+
// later (Phases 5–6) is a new `Dialect` — not a compiler rewrite.
|
|
7
|
+
//
|
|
8
|
+
// This module is PURE — string building only. No `node:`, no driver, no I/O.
|
|
9
|
+
import { NativeIdentifierError, NativeOrmError } from './errors.js';
|
|
10
|
+
// Strict identifier allowlist. Anything outside it is rejected rather than
|
|
11
|
+
// escaped — the ORM only ever feeds column/table names here, so a value with
|
|
12
|
+
// quotes, spaces, or SQL meta-characters means a bug or an injection attempt.
|
|
13
|
+
const SEGMENT = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
14
|
+
/**
|
|
15
|
+
* Quote a string as a SQL literal (single-quoted, embedded `'` doubled). Used
|
|
16
|
+
* for DDL value lists that can't be bound — `enum`/`set` allowed-value lists and
|
|
17
|
+
* the `CHECK (… IN (…))` constraint on pg/sqlite. Migration-author supplied, so
|
|
18
|
+
* escaping (not an allowlist) is the right boundary, matching the column-DEFAULT
|
|
19
|
+
* literal path in the DDL compiler.
|
|
20
|
+
*/
|
|
21
|
+
export function quoteSqlString(value) {
|
|
22
|
+
return `'${String(value).replace(/'/g, "''")}'`;
|
|
23
|
+
}
|
|
24
|
+
/** Render an `enum`/`set` value list as a `(quoted, list)` for inline use. */
|
|
25
|
+
export function quoteValueList(values) {
|
|
26
|
+
return values.map(quoteSqlString).join(', ');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Validate a (possibly dotted) identifier and return its segments. Throws
|
|
30
|
+
* {@link NativeIdentifierError} on anything that isn't a plain
|
|
31
|
+
* `[letter|_][letter|digit|_]*` per dot-separated segment.
|
|
32
|
+
*/
|
|
33
|
+
export function validateIdentifier(identifier) {
|
|
34
|
+
if (typeof identifier !== 'string' || identifier.length === 0) {
|
|
35
|
+
throw new NativeIdentifierError(String(identifier));
|
|
36
|
+
}
|
|
37
|
+
const segments = identifier.split('.');
|
|
38
|
+
for (const seg of segments) {
|
|
39
|
+
if (!SEGMENT.test(seg))
|
|
40
|
+
throw new NativeIdentifierError(identifier);
|
|
41
|
+
}
|
|
42
|
+
return segments;
|
|
43
|
+
}
|
|
44
|
+
// JSON path segments are user-supplied strings spliced into the SQL text (as
|
|
45
|
+
// quoted keys inside a path literal or pg `->'key'` operands), so they're the
|
|
46
|
+
// second identifier-like security boundary after `validateIdentifier`. Unlike
|
|
47
|
+
// column names they may legitimately contain spaces/dots (`$."a b"` quoting
|
|
48
|
+
// handles those), so instead of an allowlist we REJECT the characters that
|
|
49
|
+
// could escape the quoting: quotes, backticks, backslashes, and control chars.
|
|
50
|
+
// eslint-disable-next-line no-control-regex -- control characters are exactly what we reject
|
|
51
|
+
const JSON_SEGMENT_REJECT = /['"`\\\x00-\x1f]/;
|
|
52
|
+
/**
|
|
53
|
+
* Split a `column->path->to->key` arrow column into the base column and its
|
|
54
|
+
* validated JSON path segments. The column half goes through the normal
|
|
55
|
+
* {@link validateIdentifier} gate at quote time; each path segment is checked
|
|
56
|
+
* against {@link JSON_SEGMENT_REJECT} here. All-digit segments become numeric
|
|
57
|
+
* array indexes (`meta->items->0` → `$[0]` / pg `->0`).
|
|
58
|
+
*/
|
|
59
|
+
export function parseJsonPath(path) {
|
|
60
|
+
const [column, ...rawSegments] = path.split('->');
|
|
61
|
+
if (!column || rawSegments.length === 0 || rawSegments.some(s => s.length === 0)) {
|
|
62
|
+
throw new NativeOrmError('NATIVE_JSON_PATH_INVALID', `[RudderJS ORM native] Malformed JSON path "${path}" — expected column->key[->key…] with non-empty segments.`);
|
|
63
|
+
}
|
|
64
|
+
const segments = rawSegments.map((seg) => {
|
|
65
|
+
if (JSON_SEGMENT_REJECT.test(seg)) {
|
|
66
|
+
throw new NativeOrmError('NATIVE_JSON_PATH_SEGMENT', `[RudderJS ORM native] JSON path segment ${JSON.stringify(seg)} in "${path}" contains a quote, backslash, backtick, or control character — not allowed (path segments are spliced into SQL text).`);
|
|
67
|
+
}
|
|
68
|
+
return /^\d+$/.test(seg) ? Number(seg) : seg;
|
|
69
|
+
});
|
|
70
|
+
return { column, segments };
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Render validated segments as a single-quoted SQL JSON-path literal —
|
|
74
|
+
* `'$."a"."b"[0]'`. Keys are double-quoted inside the path so spaces/dots
|
|
75
|
+
* survive; safe to inline because {@link parseJsonPath} rejected every
|
|
76
|
+
* character that could escape either quoting layer. Shared by the sqlite and
|
|
77
|
+
* mysql dialects (pg uses `->` operator chains instead).
|
|
78
|
+
*/
|
|
79
|
+
export function jsonPathLiteral(segments) {
|
|
80
|
+
return `'$${segments.map(s => (typeof s === 'number' ? `[${s}]` : `."${s}"`)).join('')}'`;
|
|
81
|
+
}
|
|
82
|
+
/** SQLite dialect — `"`-quoted identifiers, `?` placeholders, RETURNING since
|
|
83
|
+
* 3.35. Also the dialect used by libsql/Turso (Phase 6). */
|
|
84
|
+
export class SqliteDialect {
|
|
85
|
+
name = 'sqlite';
|
|
86
|
+
supportsReturning = true;
|
|
87
|
+
quoteId(identifier) {
|
|
88
|
+
const segments = validateIdentifier(identifier);
|
|
89
|
+
// Double any embedded `"` defensively; the allowlist already forbids them,
|
|
90
|
+
// so this is belt-and-suspenders for the quoting itself.
|
|
91
|
+
return segments.map(s => `"${s.replace(/"/g, '""')}"`).join('.');
|
|
92
|
+
}
|
|
93
|
+
placeholder(_index) {
|
|
94
|
+
return '?';
|
|
95
|
+
}
|
|
96
|
+
// SQLite has no boolean type; booleans round-trip as 0/1 integers, so a
|
|
97
|
+
// boolean default renders as the matching integer literal.
|
|
98
|
+
booleanLiteral(value) {
|
|
99
|
+
return value ? '1' : '0';
|
|
100
|
+
}
|
|
101
|
+
// SQLite stores dates as ISO-8601 text — `strftime` extracts components.
|
|
102
|
+
// `date`/`time` stay text ('YYYY-MM-DD' / 'HH:MM:SS'); `day`/`month`/`year`
|
|
103
|
+
// CAST to INTEGER so a bound number compares (strftime returns zero-padded
|
|
104
|
+
// text like '05', and SQLite never equates TEXT with INTEGER).
|
|
105
|
+
dateExtract(part, column) {
|
|
106
|
+
switch (part) {
|
|
107
|
+
case 'date': return `strftime('%Y-%m-%d', ${column})`;
|
|
108
|
+
case 'time': return `strftime('%H:%M:%S', ${column})`;
|
|
109
|
+
case 'day': return `CAST(strftime('%d', ${column}) AS INTEGER)`;
|
|
110
|
+
case 'month': return `CAST(strftime('%m', ${column}) AS INTEGER)`;
|
|
111
|
+
case 'year': return `CAST(strftime('%Y', ${column}) AS INTEGER)`;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// `json_extract` returns typed values (TEXT for strings, INTEGER/REAL for
|
|
115
|
+
// numbers, 1/0 for json booleans, NULL for json null AND missing keys), so
|
|
116
|
+
// the bound value compares directly — no cast, the valueKind hint is unused.
|
|
117
|
+
jsonExtract(column, segments, _valueKind) {
|
|
118
|
+
return `json_extract(${column}, ${jsonPathLiteral(segments)})`;
|
|
119
|
+
}
|
|
120
|
+
// json_extract already surfaces BOTH a missing key and an explicit json
|
|
121
|
+
// null as SQL NULL — the plain IS [NOT] NULL on the extraction is correct.
|
|
122
|
+
jsonNullComparison(column, segments, negated) {
|
|
123
|
+
return `${this.jsonExtract(column, segments, 'text')} IS ${negated ? 'NOT ' : ''}NULL`;
|
|
124
|
+
}
|
|
125
|
+
// json_extract yields INTEGER 1/0 for json true/false — bind the matching int.
|
|
126
|
+
jsonBoolean(value) {
|
|
127
|
+
return value ? 1 : 0;
|
|
128
|
+
}
|
|
129
|
+
// SQLite has no containment operator — emulate per element via json_each:
|
|
130
|
+
// EXISTS (SELECT 1 FROM json_each(col, path) WHERE json_each.value = ?).
|
|
131
|
+
// Array values AND one EXISTS per element (matching pg @> / mysql
|
|
132
|
+
// JSON_CONTAINS "every element contained" semantics). Scalars only — a
|
|
133
|
+
// nested object/array element has no reliable text-equality form here.
|
|
134
|
+
jsonContains(column, segments, value, bind) {
|
|
135
|
+
const target = segments.length === 0 ? column : `${column}, ${jsonPathLiteral(segments)}`;
|
|
136
|
+
const elements = Array.isArray(value) ? value : [value];
|
|
137
|
+
const parts = elements.map(v => {
|
|
138
|
+
if (v !== null && typeof v === 'object') {
|
|
139
|
+
throw new NativeOrmError('NATIVE_JSON_CONTAINS_UNSUPPORTED', '[RudderJS ORM native] whereJsonContains on SQLite supports scalar values (and arrays of scalars) only — object containment has no json_each equality form. Use whereRaw(...) for structural checks.');
|
|
140
|
+
}
|
|
141
|
+
// json null elements surface as SQL NULL in json_each.value — match on
|
|
142
|
+
// the row's declared type instead (`= NULL` never matches in SQL).
|
|
143
|
+
if (v === null)
|
|
144
|
+
return `EXISTS (SELECT 1 FROM json_each(${target}) WHERE "json_each"."type" = 'null')`;
|
|
145
|
+
const bound = typeof v === 'boolean' ? (v ? 1 : 0) : v;
|
|
146
|
+
return `EXISTS (SELECT 1 FROM json_each(${target}) WHERE "json_each"."value" = ${bind(bound)})`;
|
|
147
|
+
});
|
|
148
|
+
return parts.length === 1 ? parts[0] : `(${parts.join(' AND ')})`;
|
|
149
|
+
}
|
|
150
|
+
// json_array_length takes the path directly as its second argument.
|
|
151
|
+
jsonLength(column, segments) {
|
|
152
|
+
return segments.length === 0
|
|
153
|
+
? `json_array_length(${column})`
|
|
154
|
+
: `json_array_length(${column}, ${jsonPathLiteral(segments)})`;
|
|
155
|
+
}
|
|
156
|
+
// json_set takes (path, value) varargs — one call covers every write on the
|
|
157
|
+
// column. `json(?)` parses the bound JSON text so all value types (string/
|
|
158
|
+
// number/boolean/null/array/object) land as real JSON values, not text.
|
|
159
|
+
jsonSet(column, writes, bind) {
|
|
160
|
+
const args = writes
|
|
161
|
+
.map(w => `${jsonPathLiteral(w.segments)}, json(${bind(JSON.stringify(w.value))})`)
|
|
162
|
+
.join(', ');
|
|
163
|
+
return `json_set(${column}, ${args})`;
|
|
164
|
+
}
|
|
165
|
+
// SQLite has no row-level pessimistic lock — a write transaction (BEGIN
|
|
166
|
+
// IMMEDIATE) already serializes writers, so the queue reservation is safe
|
|
167
|
+
// without a `FOR UPDATE` suffix. No-op, options included: with no row locks
|
|
168
|
+
// there is never a locked row to skip or fail on.
|
|
169
|
+
lockSql(_mode, _opts) {
|
|
170
|
+
return '';
|
|
171
|
+
}
|
|
172
|
+
// SQLite + Postgres share the ON CONFLICT (target) DO UPDATE / DO NOTHING form,
|
|
173
|
+
// referencing the rejected row's values via the `excluded` pseudo-table.
|
|
174
|
+
upsertClause(uniqueBy, update) {
|
|
175
|
+
const target = uniqueBy.map(c => this.quoteId(c)).join(', ');
|
|
176
|
+
if (update.length === 0)
|
|
177
|
+
return `ON CONFLICT (${target}) DO NOTHING`;
|
|
178
|
+
const sets = update.map(c => `${this.quoteId(c)} = excluded.${this.quoteId(c)}`).join(', ');
|
|
179
|
+
return `ON CONFLICT (${target}) DO UPDATE SET ${sets}`;
|
|
180
|
+
}
|
|
181
|
+
// SQLite has a small set of storage classes and no real type checking, so the
|
|
182
|
+
// mapping is coarse: TEXT for anything string-ish, INTEGER for ints/booleans,
|
|
183
|
+
// REAL/NUMERIC for floats/decimals, BLOB for binary. `length`/`precision` are
|
|
184
|
+
// recorded on the column for pg/mysql but carry no meaning in SQLite types.
|
|
185
|
+
columnTypeSql(column) {
|
|
186
|
+
if (column.autoIncrement) {
|
|
187
|
+
// SQLite bundles the PK into the type: an INTEGER PRIMARY KEY column is the
|
|
188
|
+
// rowid alias, and AUTOINCREMENT prevents id reuse. The compiler appends
|
|
189
|
+
// nothing else to this.
|
|
190
|
+
return 'INTEGER PRIMARY KEY AUTOINCREMENT';
|
|
191
|
+
}
|
|
192
|
+
switch (column.type) {
|
|
193
|
+
case 'increments': // only reached if an increments column isn't auto (defensive)
|
|
194
|
+
case 'integer':
|
|
195
|
+
case 'bigInteger':
|
|
196
|
+
case 'tinyInteger':
|
|
197
|
+
case 'smallInteger':
|
|
198
|
+
case 'mediumInteger':
|
|
199
|
+
case 'boolean':
|
|
200
|
+
return 'INTEGER';
|
|
201
|
+
case 'string':
|
|
202
|
+
case 'char':
|
|
203
|
+
case 'text':
|
|
204
|
+
case 'mediumText':
|
|
205
|
+
case 'longText':
|
|
206
|
+
case 'uuid':
|
|
207
|
+
case 'ulid':
|
|
208
|
+
case 'json':
|
|
209
|
+
case 'jsonb':
|
|
210
|
+
case 'date':
|
|
211
|
+
case 'time':
|
|
212
|
+
case 'dateTime':
|
|
213
|
+
case 'timestamp':
|
|
214
|
+
return 'TEXT';
|
|
215
|
+
case 'float':
|
|
216
|
+
case 'double':
|
|
217
|
+
return 'REAL';
|
|
218
|
+
case 'decimal':
|
|
219
|
+
return 'NUMERIC';
|
|
220
|
+
case 'binary':
|
|
221
|
+
return 'BLOB';
|
|
222
|
+
// SQLite has no enum/set type. Mirror Laravel's SQLite grammar: a TEXT
|
|
223
|
+
// column with a CHECK (… IN (…)) constraint. `set` genuinely has no
|
|
224
|
+
// single-column equivalent (multiple values), so it's unsupported.
|
|
225
|
+
case 'enum':
|
|
226
|
+
return `TEXT CHECK (${this.quoteId(column.name)} IN (${quoteValueList(column.enumValues ?? [])}))`;
|
|
227
|
+
case 'set':
|
|
228
|
+
throw new NativeOrmError('NATIVE_DDL_UNSUPPORTED_TYPE', `[RudderJS ORM native] SQLite has no SET column type ("${column.name}"). Use enum(), a json column, or a pivot table.`);
|
|
229
|
+
default: {
|
|
230
|
+
// Exhaustiveness guard — a new ColumnType must extend this switch.
|
|
231
|
+
const unreachable = column.type;
|
|
232
|
+
throw new NativeOrmError('NATIVE_DDL_UNKNOWN_TYPE', `[RudderJS ORM native] No SQLite type mapping for column type ${JSON.stringify(unreachable)}.`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=dialect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialect.js","sourceRoot":"","sources":["../../src/native/dialect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export type { Row, Executor, Transaction, Connection, TransactionOptions, TransactionIsolationLevel, } from '@rudderjs/contracts';
|
|
2
|
+
import type { Connection } from '@rudderjs/contracts';
|
|
3
|
+
/** Result metadata for a write run through {@link AffectingExecutor}. */
|
|
4
|
+
export interface AffectingResult {
|
|
5
|
+
/** The auto-increment id the write generated, or `null` when none (a
|
|
6
|
+
* non-auto-increment key, or an UPDATE/DELETE). */
|
|
7
|
+
insertId: number | null;
|
|
8
|
+
/** Rows the statement affected — the count callers return from
|
|
9
|
+
* `updateAll` / `deleteAll` and `DB.insert/update/delete`. */
|
|
10
|
+
affectedRows: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A write-with-metadata escape hatch for dialects WITHOUT `RETURNING` (MySQL).
|
|
14
|
+
* On SQLite/Postgres the engine reads written rows back via `RETURNING *`
|
|
15
|
+
* (`Executor.execute`), so those drivers don't implement this. The MySQL driver
|
|
16
|
+
* does: the query builder's no-RETURNING path reads `insertId` (for `create`)
|
|
17
|
+
* and `affectedRows` (for `updateAll`/`deleteAll`) from here, then re-SELECTs by
|
|
18
|
+
* primary key for terminals that must return the row. A native-only seam (not in
|
|
19
|
+
* `@rudderjs/contracts`) — accessed by capability check, never on the read path.
|
|
20
|
+
*/
|
|
21
|
+
export interface AffectingExecutor {
|
|
22
|
+
affectingExecute(sql: string, bindings: readonly unknown[]): Promise<AffectingResult>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A database connection the native engine drives — the per-platform seam.
|
|
26
|
+
* Structurally identical to the canonical {@link Connection}; the distinct name
|
|
27
|
+
* marks the swappable driver boundary (better-sqlite3 / postgres / RN / WASM).
|
|
28
|
+
*
|
|
29
|
+
* `transaction()` (via `Connection`) was defined in Phase 2 so the write path
|
|
30
|
+
* was transaction-aware by construction; Phase 4 wires the public
|
|
31
|
+
* `Model.transaction()` API to it.
|
|
32
|
+
*/
|
|
33
|
+
export interface Driver extends Connection {
|
|
34
|
+
/** Release the underlying connection/handle. Idempotent. */
|
|
35
|
+
close(): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../src/native/driver.ts"],"names":[],"mappings":"AAkBA,YAAY,EACV,GAAG,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EACtC,kBAAkB,EAAE,yBAAyB,GAC9C,MAAM,qBAAqB,CAAA;AAE5B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAErD,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC9B;wDACoD;IACpD,QAAQ,EAAM,MAAM,GAAG,IAAI,CAAA;IAC3B;mEAC+D;IAC/D,YAAY,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;CACtF;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,MAAO,SAAQ,UAAU;IACxC,4DAA4D;IAC5D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// ─── Driver seam (per-platform) ────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// The `Driver` is the ONLY part of the native engine that differs across
|
|
4
|
+
// platforms. It executes already-compiled SQL + bindings and returns rows.
|
|
5
|
+
// The compiler and `NativeQueryBuilder` talk to the {@link Executor} interface
|
|
6
|
+
// and never to a concrete driver — so a React Native (`op-sqlite`/`expo-sqlite`)
|
|
7
|
+
// or browser (WASM) driver drops in later without touching the SQL layer.
|
|
8
|
+
//
|
|
9
|
+
// This module is PURE: type-only. No `node:` import, no I/O. Concrete drivers
|
|
10
|
+
// (e.g. `drivers/better-sqlite3.ts`) live in their own node-only modules and
|
|
11
|
+
// lazy-load their package.
|
|
12
|
+
//
|
|
13
|
+
// The model-independent execution types (`Row`, `Executor`, `Transaction`,
|
|
14
|
+
// `Connection`) are now owned by `@rudderjs/contracts` (the zero-dep foundation)
|
|
15
|
+
// and surfaced to apps via `@rudderjs/database`'s `DB` facade. They're re-exported
|
|
16
|
+
// here unchanged so every existing `./driver.js` import site keeps working — the
|
|
17
|
+
// native engine implements the same contract.
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver.js","sourceRoot":"","sources":["../../src/native/driver.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,yEAAyE;AACzE,2EAA2E;AAC3E,+EAA+E;AAC/E,iFAAiF;AACjF,0EAA0E;AAC1E,EAAE;AACF,8EAA8E;AAC9E,6EAA6E;AAC7E,2BAA2B;AAC3B,EAAE;AACF,2EAA2E;AAC3E,iFAAiF;AACjF,mFAAmF;AACnF,iFAAiF;AACjF,8CAA8C"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Driver, Transaction, Row, TransactionOptions } from '../driver.js';
|
|
2
|
+
/** Connection config for {@link BetterSqlite3Driver.open}. */
|
|
3
|
+
export interface BetterSqlite3DriverConfig {
|
|
4
|
+
/**
|
|
5
|
+
* Database location. Accepts a filesystem path, a `file:` URL, or
|
|
6
|
+
* `':memory:'` for an in-memory database (the default). A leading `file:`
|
|
7
|
+
* scheme is stripped for better-sqlite3, which wants a bare path.
|
|
8
|
+
*/
|
|
9
|
+
filename?: string;
|
|
10
|
+
/** Forwarded to the better-sqlite3 `Database` constructor (e.g. `readonly`). */
|
|
11
|
+
options?: Record<string, unknown>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* {@link Driver} backed by better-sqlite3. Construct via the static
|
|
15
|
+
* {@link BetterSqlite3Driver.open} factory, which performs the lazy import.
|
|
16
|
+
*/
|
|
17
|
+
export declare class BetterSqlite3Driver implements Driver {
|
|
18
|
+
private readonly db;
|
|
19
|
+
/**
|
|
20
|
+
* Current transaction nesting depth. 0 = no open transaction; 1 = inside a
|
|
21
|
+
* top-level `BEGIN`; ≥2 = inside N−1 nested SAVEPOINTs. Drives the BEGIN-vs-
|
|
22
|
+
* SAVEPOINT choice in {@link transaction}. Single field is safe because
|
|
23
|
+
* better-sqlite3 is single-connection and synchronous — there is exactly one
|
|
24
|
+
* open transaction stack per driver instance.
|
|
25
|
+
*/
|
|
26
|
+
private depth;
|
|
27
|
+
private constructor();
|
|
28
|
+
/**
|
|
29
|
+
* Resolve the `better-sqlite3` package, open the database, and return a
|
|
30
|
+
* ready driver. Throws {@link NativeDriverError} with install guidance when
|
|
31
|
+
* the package isn't present (it's an optional peer).
|
|
32
|
+
*/
|
|
33
|
+
static open(config?: BetterSqlite3DriverConfig): Promise<BetterSqlite3Driver>;
|
|
34
|
+
execute(sql: string, bindings: readonly unknown[]): Promise<Row[]>;
|
|
35
|
+
/**
|
|
36
|
+
* Run `fn` inside a transaction. The top-level call wraps it in
|
|
37
|
+
* BEGIN/COMMIT/ROLLBACK; a nested call (depth ≥ 1) wraps it in a uniquely
|
|
38
|
+
* named SAVEPOINT so an inner failure rolls back only its own work, leaving
|
|
39
|
+
* the outer transaction intact. The transaction-scoped {@link Transaction} is
|
|
40
|
+
* the driver itself — better-sqlite3 is synchronous and single-connection, so
|
|
41
|
+
* every `execute` between the markers runs on the one open transaction.
|
|
42
|
+
*
|
|
43
|
+
* (We don't use better-sqlite3's own `db.transaction()` wrapper because it
|
|
44
|
+
* only accepts a *synchronous* function, and our `fn` is async — savepoints
|
|
45
|
+
* give us the same nesting semantics over an async callback.)
|
|
46
|
+
*
|
|
47
|
+
* **Single-connection caveat:** because there is one connection, two
|
|
48
|
+
* *concurrently* in-flight top-level `transaction()` calls would collide on
|
|
49
|
+
* the same connection. SQLite serializes writers anyway; the native engine
|
|
50
|
+
* assumes transactions are not run concurrently against one SQLite handle.
|
|
51
|
+
* Pooled drivers (pg/mysql, Phase 5/6) pin a dedicated client per transaction.
|
|
52
|
+
*/
|
|
53
|
+
transaction<T>(fn: (tx: Transaction) => Promise<T>, opts?: TransactionOptions): Promise<T>;
|
|
54
|
+
close(): Promise<void>;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=better-sqlite3.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"better-sqlite3.d.ts","sourceRoot":"","sources":["../../../src/native/drivers/better-sqlite3.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAmBhF,8DAA8D;AAC9D,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC;AAED;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,MAAM;IAU5B,OAAO,CAAC,QAAQ,CAAC,EAAE;IATvC;;;;;;OAMG;IACH,OAAO,CAAC,KAAK,CAAI;IAEjB,OAAO;IAEP;;;;OAIG;WACU,IAAI,CAAC,MAAM,GAAE,yBAA8B,GAAG,OAAO,CAAC,mBAAmB,CAAC;IA6BjF,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAaxE;;;;;;;;;;;;;;;;;OAiBG;IACG,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,CAAC,CAAC;IA0C1F,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
|