@rudderjs/database 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +70 -0
  2. package/dist/db.d.ts +21 -3
  3. package/dist/db.d.ts.map +1 -1
  4. package/dist/db.js +27 -5
  5. package/dist/db.js.map +1 -1
  6. package/dist/index.d.ts +14 -2
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +23 -4
  9. package/dist/index.js.map +1 -1
  10. package/dist/native/adapter.d.ts +202 -0
  11. package/dist/native/adapter.d.ts.map +1 -0
  12. package/dist/native/adapter.js +440 -0
  13. package/dist/native/adapter.js.map +1 -0
  14. package/dist/native/compiler.d.ts +371 -0
  15. package/dist/native/compiler.d.ts.map +1 -0
  16. package/dist/native/compiler.js +978 -0
  17. package/dist/native/compiler.js.map +1 -0
  18. package/dist/native/dialect-mysql.d.ts +26 -0
  19. package/dist/native/dialect-mysql.d.ts.map +1 -0
  20. package/dist/native/dialect-mysql.js +188 -0
  21. package/dist/native/dialect-mysql.js.map +1 -0
  22. package/dist/native/dialect-pg.d.ts +26 -0
  23. package/dist/native/dialect-pg.d.ts.map +1 -0
  24. package/dist/native/dialect-pg.js +192 -0
  25. package/dist/native/dialect-pg.js.map +1 -0
  26. package/dist/native/dialect.d.ts +255 -0
  27. package/dist/native/dialect.d.ts.map +1 -0
  28. package/dist/native/dialect.js +237 -0
  29. package/dist/native/dialect.js.map +1 -0
  30. package/dist/native/driver.d.ts +37 -0
  31. package/dist/native/driver.d.ts.map +1 -0
  32. package/dist/native/driver.js +19 -0
  33. package/dist/native/driver.js.map +1 -0
  34. package/dist/native/drivers/better-sqlite3.d.ts +56 -0
  35. package/dist/native/drivers/better-sqlite3.d.ts.map +1 -0
  36. package/dist/native/drivers/better-sqlite3.js +171 -0
  37. package/dist/native/drivers/better-sqlite3.js.map +1 -0
  38. package/dist/native/drivers/mysql.d.ts +30 -0
  39. package/dist/native/drivers/mysql.d.ts.map +1 -0
  40. package/dist/native/drivers/mysql.js +176 -0
  41. package/dist/native/drivers/mysql.js.map +1 -0
  42. package/dist/native/drivers/postgres.d.ts +57 -0
  43. package/dist/native/drivers/postgres.d.ts.map +1 -0
  44. package/dist/native/drivers/postgres.js +155 -0
  45. package/dist/native/drivers/postgres.js.map +1 -0
  46. package/dist/native/errors.d.ts +43 -0
  47. package/dist/native/errors.d.ts.map +1 -0
  48. package/dist/native/errors.js +64 -0
  49. package/dist/native/errors.js.map +1 -0
  50. package/dist/native/index.d.ts +27 -0
  51. package/dist/native/index.d.ts.map +1 -0
  52. package/dist/native/index.js +55 -0
  53. package/dist/native/index.js.map +1 -0
  54. package/dist/native/isolation.d.ts +14 -0
  55. package/dist/native/isolation.d.ts.map +1 -0
  56. package/dist/native/isolation.js +37 -0
  57. package/dist/native/isolation.js.map +1 -0
  58. package/dist/native/query-builder.d.ts +303 -0
  59. package/dist/native/query-builder.d.ts.map +1 -0
  60. package/dist/native/query-builder.js +984 -0
  61. package/dist/native/query-builder.js.map +1 -0
  62. package/dist/native/replica-picker.d.ts +22 -0
  63. package/dist/native/replica-picker.d.ts.map +1 -0
  64. package/dist/native/replica-picker.js +65 -0
  65. package/dist/native/replica-picker.js.map +1 -0
  66. package/dist/native/schema/alter-blueprint.d.ts +37 -0
  67. package/dist/native/schema/alter-blueprint.d.ts.map +1 -0
  68. package/dist/native/schema/alter-blueprint.js +56 -0
  69. package/dist/native/schema/alter-blueprint.js.map +1 -0
  70. package/dist/native/schema/blueprint.d.ts +151 -0
  71. package/dist/native/schema/blueprint.d.ts.map +1 -0
  72. package/dist/native/schema/blueprint.js +286 -0
  73. package/dist/native/schema/blueprint.js.map +1 -0
  74. package/dist/native/schema/column.d.ts +168 -0
  75. package/dist/native/schema/column.d.ts.map +1 -0
  76. package/dist/native/schema/column.js +190 -0
  77. package/dist/native/schema/column.js.map +1 -0
  78. package/dist/native/schema/ddl-compiler.d.ts +34 -0
  79. package/dist/native/schema/ddl-compiler.d.ts.map +1 -0
  80. package/dist/native/schema/ddl-compiler.js +352 -0
  81. package/dist/native/schema/ddl-compiler.js.map +1 -0
  82. package/dist/native/schema/inspect.d.ts +67 -0
  83. package/dist/native/schema/inspect.d.ts.map +1 -0
  84. package/dist/native/schema/inspect.js +312 -0
  85. package/dist/native/schema/inspect.js.map +1 -0
  86. package/dist/native/schema/introspect.d.ts +34 -0
  87. package/dist/native/schema/introspect.d.ts.map +1 -0
  88. package/dist/native/schema/introspect.js +101 -0
  89. package/dist/native/schema/introspect.js.map +1 -0
  90. package/dist/native/schema/migration.d.ts +8 -0
  91. package/dist/native/schema/migration.d.ts.map +1 -0
  92. package/dist/native/schema/migration.js +19 -0
  93. package/dist/native/schema/migration.js.map +1 -0
  94. package/dist/native/schema/migrator.d.ts +144 -0
  95. package/dist/native/schema/migrator.d.ts.map +1 -0
  96. package/dist/native/schema/migrator.js +240 -0
  97. package/dist/native/schema/migrator.js.map +1 -0
  98. package/dist/native/schema/rebuild.d.ts +11 -0
  99. package/dist/native/schema/rebuild.d.ts.map +1 -0
  100. package/dist/native/schema/rebuild.js +92 -0
  101. package/dist/native/schema/rebuild.js.map +1 -0
  102. package/dist/native/schema/schema-builder.d.ts +46 -0
  103. package/dist/native/schema/schema-builder.d.ts.map +1 -0
  104. package/dist/native/schema/schema-builder.js +153 -0
  105. package/dist/native/schema/schema-builder.js.map +1 -0
  106. package/dist/native/schema/schema-facade.d.ts +63 -0
  107. package/dist/native/schema/schema-facade.d.ts.map +1 -0
  108. package/dist/native/schema/schema-facade.js +124 -0
  109. package/dist/native/schema/schema-facade.js.map +1 -0
  110. package/dist/native/schema/schema-types.d.ts +27 -0
  111. package/dist/native/schema/schema-types.d.ts.map +1 -0
  112. package/dist/native/schema/schema-types.js +52 -0
  113. package/dist/native/schema/schema-types.js.map +1 -0
  114. package/dist/native/schema/types-generator.d.ts +73 -0
  115. package/dist/native/schema/types-generator.d.ts.map +1 -0
  116. package/dist/native/schema/types-generator.js +181 -0
  117. package/dist/native/schema/types-generator.js.map +1 -0
  118. package/dist/registry-bridge.d.ts +24 -4
  119. package/dist/registry-bridge.d.ts.map +1 -1
  120. package/dist/registry-bridge.js +20 -0
  121. package/dist/registry-bridge.js.map +1 -1
  122. package/dist/sticky.d.ts +22 -0
  123. package/dist/sticky.d.ts.map +1 -0
  124. package/dist/sticky.js +61 -0
  125. package/dist/sticky.js.map +1 -0
  126. 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"}