@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,171 @@
1
+ // ─── better-sqlite3 Driver (Node) ──────────────────────────
2
+ //
3
+ // Concrete {@link Driver} over the `better-sqlite3` package. NODE-ONLY:
4
+ // `better-sqlite3` is an optional peer of `@rudderjs/orm` and is loaded with a
5
+ // lazy `await import()` inside `open()` so this module never drags the native
6
+ // addon into a client bundle at eval time (cross-phase rule 5).
7
+ //
8
+ // better-sqlite3 is synchronous; we wrap its calls in resolved promises to
9
+ // satisfy the async {@link Driver} contract shared with RN/WASM drivers.
10
+ import { NativeDriverError } from '../errors.js';
11
+ /**
12
+ * {@link Driver} backed by better-sqlite3. Construct via the static
13
+ * {@link BetterSqlite3Driver.open} factory, which performs the lazy import.
14
+ */
15
+ export class BetterSqlite3Driver {
16
+ db;
17
+ /**
18
+ * Current transaction nesting depth. 0 = no open transaction; 1 = inside a
19
+ * top-level `BEGIN`; ≥2 = inside N−1 nested SAVEPOINTs. Drives the BEGIN-vs-
20
+ * SAVEPOINT choice in {@link transaction}. Single field is safe because
21
+ * better-sqlite3 is single-connection and synchronous — there is exactly one
22
+ * open transaction stack per driver instance.
23
+ */
24
+ depth = 0;
25
+ constructor(db) {
26
+ this.db = db;
27
+ }
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 async open(config = {}) {
34
+ const filename = normalizeFilename(config.filename);
35
+ let Database;
36
+ try {
37
+ // `better-sqlite3` uses `export =`, so a dynamic import wraps it in
38
+ // `.default`. Fall back to the namespace object for older interop.
39
+ const mod = await import('better-sqlite3');
40
+ Database = mod.default ?? mod;
41
+ }
42
+ catch (err) {
43
+ throw new NativeDriverError(`[RudderJS ORM native] Failed to load "better-sqlite3". It is an optional ` +
44
+ `peer of @rudderjs/orm — install it with \`pnpm add better-sqlite3\` to use ` +
45
+ `the native SQLite engine.`, { cause: err });
46
+ }
47
+ try {
48
+ const db = new Database(filename, config.options);
49
+ return new BetterSqlite3Driver(db);
50
+ }
51
+ catch (err) {
52
+ const msg = err instanceof Error ? err.message : String(err);
53
+ throw new NativeDriverError(`[RudderJS ORM native] Could not open SQLite database at ${JSON.stringify(filename)}: ${msg}`, { cause: err });
54
+ }
55
+ }
56
+ async execute(sql, bindings) {
57
+ const params = normalizeBindings(bindings);
58
+ const stmt = this.db.prepare(sql);
59
+ // `.all()` is only valid on statements that return rows. A SELECT — or any
60
+ // write with a `RETURNING` clause — is a reader; a plain INSERT/UPDATE/DELETE
61
+ // is not and routes through `.run()`, yielding no rows.
62
+ if (stmt.reader) {
63
+ return stmt.all(...params);
64
+ }
65
+ stmt.run(...params);
66
+ return [];
67
+ }
68
+ /**
69
+ * Run `fn` inside a transaction. The top-level call wraps it in
70
+ * BEGIN/COMMIT/ROLLBACK; a nested call (depth ≥ 1) wraps it in a uniquely
71
+ * named SAVEPOINT so an inner failure rolls back only its own work, leaving
72
+ * the outer transaction intact. The transaction-scoped {@link Transaction} is
73
+ * the driver itself — better-sqlite3 is synchronous and single-connection, so
74
+ * every `execute` between the markers runs on the one open transaction.
75
+ *
76
+ * (We don't use better-sqlite3's own `db.transaction()` wrapper because it
77
+ * only accepts a *synchronous* function, and our `fn` is async — savepoints
78
+ * give us the same nesting semantics over an async callback.)
79
+ *
80
+ * **Single-connection caveat:** because there is one connection, two
81
+ * *concurrently* in-flight top-level `transaction()` calls would collide on
82
+ * the same connection. SQLite serializes writers anyway; the native engine
83
+ * assumes transactions are not run concurrently against one SQLite handle.
84
+ * Pooled drivers (pg/mysql, Phase 5/6) pin a dedicated client per transaction.
85
+ */
86
+ async transaction(fn, opts) {
87
+ // SQLite has no SQL-standard isolation levels (one writer; readers see a
88
+ // serializable snapshot) — a requested level would silently mean nothing,
89
+ // so throw rather than no-op. Checked before the nesting branch: the error
90
+ // is the same at any depth.
91
+ if (opts?.isolationLevel) {
92
+ throw new Error('[RudderJS ORM native] SQLite does not support transaction isolation levels — ' +
93
+ 'its single-writer model is already serializable. Drop the isolationLevel ' +
94
+ 'option, or use the Postgres/MySQL engine.');
95
+ }
96
+ const top = this.depth === 0;
97
+ const savepoint = top ? null : `rudder_sp_${this.depth}`;
98
+ if (top)
99
+ this.db.exec('BEGIN');
100
+ else
101
+ this.db.exec(`SAVEPOINT ${savepoint}`);
102
+ this.depth++;
103
+ try {
104
+ const result = await fn(this);
105
+ if (top)
106
+ this.db.exec('COMMIT');
107
+ else
108
+ this.db.exec(`RELEASE ${savepoint}`);
109
+ return result;
110
+ }
111
+ catch (err) {
112
+ try {
113
+ if (top) {
114
+ this.db.exec('ROLLBACK');
115
+ }
116
+ else {
117
+ // Roll back to the savepoint, then release it so the saved name is
118
+ // discarded — otherwise it lingers on the outer transaction's stack.
119
+ this.db.exec(`ROLLBACK TO ${savepoint}`);
120
+ this.db.exec(`RELEASE ${savepoint}`);
121
+ }
122
+ }
123
+ catch {
124
+ // A failed ROLLBACK (e.g. the transaction already aborted) must not mask
125
+ // the original error — swallow it and re-throw the cause below.
126
+ }
127
+ throw err;
128
+ }
129
+ finally {
130
+ this.depth--;
131
+ }
132
+ }
133
+ async close() {
134
+ this.db.close();
135
+ }
136
+ }
137
+ /**
138
+ * better-sqlite3 binds only numbers, strings, bigints, buffers, and `null` —
139
+ * a JS `boolean` throws `TypeError: SQLite3 can only bind …`. SQLite has no
140
+ * boolean type, so map `true`/`false` to the integers `1`/`0`; this round-trips
141
+ * with the ORM's `boolean` cast (which reads `0`/`1` back). The mapping covers
142
+ * raw boolean values that bypass a column cast — an untyped `where('flag', true)`
143
+ * predicate, or a `query().create({ flag: true })` on a column without a
144
+ * boolean cast. Other unbindable values (`Date`, plain objects) are passed
145
+ * through so better-sqlite3 still rejects them with its own clear error.
146
+ *
147
+ * Returns the original array reference when nothing needed coercion, so the
148
+ * common boolean-free path allocates nothing.
149
+ *
150
+ * Any future SQLite driver (libsql, op-sqlite for React Native) needs the same
151
+ * mapping — share this helper rather than re-deriving it per driver.
152
+ */
153
+ function normalizeBindings(bindings) {
154
+ let hasBoolean = false;
155
+ for (const v of bindings) {
156
+ if (typeof v === 'boolean') {
157
+ hasBoolean = true;
158
+ break;
159
+ }
160
+ }
161
+ if (!hasBoolean)
162
+ return bindings;
163
+ return bindings.map(v => (typeof v === 'boolean' ? (v ? 1 : 0) : v));
164
+ }
165
+ /** Strip a `file:` scheme and default to an in-memory database. */
166
+ function normalizeFilename(filename) {
167
+ if (!filename)
168
+ return ':memory:';
169
+ return filename.replace(/^file:/, '');
170
+ }
171
+ //# sourceMappingURL=better-sqlite3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"better-sqlite3.js","sourceRoot":"","sources":["../../../src/native/drivers/better-sqlite3.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { Driver, Transaction, Row, AffectingExecutor, AffectingResult, TransactionOptions } from '../driver.js';
2
+ /** Connection config for {@link MysqlDriver.open}. */
3
+ export interface MysqlDriverConfig {
4
+ /** MySQL connection string, e.g. `mysql://user:pass@host:3306/db`. */
5
+ url: string;
6
+ /** Forwarded to `mysql2.createPool()` (e.g. `connectionLimit`, `ssl`). */
7
+ options?: Record<string, unknown>;
8
+ }
9
+ /**
10
+ * {@link Driver} backed by `mysql2`. Construct via the static
11
+ * {@link MysqlDriver.open} factory, which lazy-imports the package, builds a
12
+ * pool, and validates connectivity up front. Autocommit statements run on the
13
+ * pool; `transaction()` reserves a dedicated connection.
14
+ */
15
+ export declare class MysqlDriver implements Driver, AffectingExecutor {
16
+ private readonly pool;
17
+ private constructor();
18
+ /**
19
+ * Resolve `mysql2`, build a pool for `config.url`, validate the connection, and
20
+ * return a ready driver. Throws {@link NativeDriverError} with install guidance
21
+ * when the package is missing, or a connection error when the URL is
22
+ * unreachable — so failures surface at setup, not deep in a request.
23
+ */
24
+ static open(config: MysqlDriverConfig): Promise<MysqlDriver>;
25
+ execute(sql: string, bindings: readonly unknown[]): Promise<Row[]>;
26
+ affectingExecute(sql: string, bindings: readonly unknown[]): Promise<AffectingResult>;
27
+ transaction<T>(fn: (tx: Transaction) => Promise<T>, opts?: TransactionOptions): Promise<T>;
28
+ close(): Promise<void>;
29
+ }
30
+ //# sourceMappingURL=mysql.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mysql.d.ts","sourceRoot":"","sources":["../../../src/native/drivers/mysql.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,iBAAiB,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AA8BpH,sDAAsD;AACtD,MAAM,WAAW,iBAAiB;IAChC,sEAAsE;IACtE,GAAG,EAAE,MAAM,CAAA;IACX,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC;AA4DD;;;;;GAKG;AACH,qBAAa,WAAY,YAAW,MAAM,EAAE,iBAAiB;IACvC,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAzC,OAAO;IAEP;;;;;OAKG;WACU,IAAI,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC;IA2ClE,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAIlE,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC;IAU/E,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;IAmB1F,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
@@ -0,0 +1,176 @@
1
+ // ─── MySQL Driver (Node, mysql2/promise) ───────────────────
2
+ //
3
+ // Concrete {@link Driver} over the `mysql2` package (its `mysql2/promise` API).
4
+ // NODE-ONLY: `mysql2` is an optional peer of `@rudderjs/orm`, lazy-`import()`ed
5
+ // inside `open()` so this module never drags the driver into a client bundle at
6
+ // eval time (cross-phase rule 5). Mirrors the postgres driver's shape.
7
+ //
8
+ // Like postgres (and unlike single-connection better-sqlite3), mysql2 pools
9
+ // connections — so a transaction MUST pin one connection. The top-level driver
10
+ // runs autocommit statements on the pool; `transaction()` reserves a connection
11
+ // (`getConnection()` + `beginTransaction`), and nested transactions map to
12
+ // SAVEPOINTs on that pinned connection (same savepoint semantics the prisma/
13
+ // drizzle adapters use).
14
+ //
15
+ // MySQL has no `RETURNING`, so this driver also implements {@link
16
+ // AffectingExecutor}: writes report their auto-increment `insertId` and
17
+ // `affectedRows` from mysql2's `ResultSetHeader`, which the query builder's
18
+ // no-RETURNING path consumes.
19
+ import { NativeDriverError } from '../errors.js';
20
+ import { isolationLevelSql, nestedIsolationError } from '../isolation.js';
21
+ /** Monotonic counter for unique nested-transaction SAVEPOINT names. */
22
+ let savepointSeq = 0;
23
+ /** Run a statement on a queryable and normalize the row result to `Row[]`
24
+ * (a write's ResultSetHeader is not an array → no rows). */
25
+ async function runQuery(q, sql, bindings) {
26
+ const [result] = await q.query(sql, bindings);
27
+ return Array.isArray(result) ? result : [];
28
+ }
29
+ /** Run a write and read its metadata. A SELECT (array result) reports its row
30
+ * count as `affectedRows` and no `insertId`; a write reads the header. */
31
+ async function runAffecting(q, sql, bindings) {
32
+ const [result] = await q.query(sql, bindings);
33
+ if (Array.isArray(result))
34
+ return { insertId: null, affectedRows: result.length };
35
+ const header = result;
36
+ const insertId = typeof header.insertId === 'number' && header.insertId > 0 ? header.insertId : null;
37
+ return { insertId, affectedRows: header.affectedRows ?? 0 };
38
+ }
39
+ /**
40
+ * A {@link Transaction} scope pinned to one mysql2 connection. Every query on
41
+ * the scope runs on that connection, so a transaction-scoped query stays on the
42
+ * transaction's connection; nesting opens a SAVEPOINT on it.
43
+ */
44
+ class MysqlScope {
45
+ conn;
46
+ constructor(conn) {
47
+ this.conn = conn;
48
+ }
49
+ execute(sql, bindings) {
50
+ return runQuery(this.conn, sql, bindings);
51
+ }
52
+ affectingExecute(sql, bindings) {
53
+ return runAffecting(this.conn, sql, bindings);
54
+ }
55
+ // Nested transaction → SAVEPOINT on the current (already-transactional)
56
+ // connection, so an inner failure rolls back only its own work. An isolation
57
+ // level is rejected — the open transaction's isolation is already fixed (MySQL
58
+ // itself errors on SET TRANSACTION while a transaction is in progress).
59
+ async transaction(fn, opts) {
60
+ if (opts?.isolationLevel)
61
+ throw nestedIsolationError();
62
+ const name = `rudder_sp_${(savepointSeq = (savepointSeq + 1) % Number.MAX_SAFE_INTEGER)}`;
63
+ await this.conn.query(`SAVEPOINT ${name}`);
64
+ try {
65
+ const result = await fn(this);
66
+ await this.conn.query(`RELEASE SAVEPOINT ${name}`);
67
+ return result;
68
+ }
69
+ catch (err) {
70
+ try {
71
+ // Roll back to the savepoint, then release it so the name is discarded.
72
+ await this.conn.query(`ROLLBACK TO SAVEPOINT ${name}`);
73
+ await this.conn.query(`RELEASE SAVEPOINT ${name}`);
74
+ }
75
+ catch {
76
+ // A failed rollback must not mask the original error.
77
+ }
78
+ throw err;
79
+ }
80
+ }
81
+ }
82
+ /**
83
+ * {@link Driver} backed by `mysql2`. Construct via the static
84
+ * {@link MysqlDriver.open} factory, which lazy-imports the package, builds a
85
+ * pool, and validates connectivity up front. Autocommit statements run on the
86
+ * pool; `transaction()` reserves a dedicated connection.
87
+ */
88
+ export class MysqlDriver {
89
+ pool;
90
+ constructor(pool) {
91
+ this.pool = pool;
92
+ }
93
+ /**
94
+ * Resolve `mysql2`, build a pool for `config.url`, validate the connection, and
95
+ * return a ready driver. Throws {@link NativeDriverError} with install guidance
96
+ * when the package is missing, or a connection error when the URL is
97
+ * unreachable — so failures surface at setup, not deep in a request.
98
+ */
99
+ static async open(config) {
100
+ let mod;
101
+ try {
102
+ // mysql2 ships its promise API at `mysql2/promise`.
103
+ mod = await import('mysql2/promise');
104
+ }
105
+ catch (err) {
106
+ throw new NativeDriverError(`[RudderJS ORM native] Failed to load "mysql2". It is an optional peer of ` +
107
+ `@rudderjs/orm — install it with \`pnpm add mysql2\` to use the native MySQL engine.`, { cause: err });
108
+ }
109
+ const pool = mod.createPool({
110
+ uri: config.url,
111
+ // MySQL has no boolean type — `t.boolean()` columns are `tinyint(1)`
112
+ // (the BOOLEAN alias). Map them back to JS booleans on read so boolean
113
+ // columns round-trip like they do on Postgres (whose driver parses the
114
+ // native bool type). Only display-width-1 TINY columns qualify — a plain
115
+ // `t.tinyInt()` (width 4) stays numeric. `config.options` can override.
116
+ typeCast: (field, next) => {
117
+ if (field.type === 'TINY' && field.length === 1) {
118
+ const value = field.string();
119
+ return value === null ? null : value === '1';
120
+ }
121
+ return next();
122
+ },
123
+ ...config.options,
124
+ });
125
+ const driver = new MysqlDriver(pool);
126
+ try {
127
+ await pool.query('select 1');
128
+ }
129
+ catch (err) {
130
+ await pool.end().catch(() => { });
131
+ const msg = err instanceof Error ? err.message : String(err);
132
+ throw new NativeDriverError(`[RudderJS ORM native] Could not connect to MySQL at the configured URL: ${msg}`, { cause: err });
133
+ }
134
+ return driver;
135
+ }
136
+ execute(sql, bindings) {
137
+ return runQuery(this.pool, sql, bindings);
138
+ }
139
+ affectingExecute(sql, bindings) {
140
+ return runAffecting(this.pool, sql, bindings);
141
+ }
142
+ // Top-level transaction → reserve a connection, BEGIN, COMMIT (ROLLBACK on
143
+ // throw), always release. Every query inside runs on the pinned connection.
144
+ // An isolation level is applied via `SET TRANSACTION ISOLATION LEVEL` BEFORE
145
+ // `beginTransaction` — on MySQL the un-scoped form applies only to the NEXT
146
+ // transaction started on the connection (issuing it inside one errors), and
147
+ // it does not persist, so the pooled connection is released clean.
148
+ async transaction(fn, opts) {
149
+ const level = opts?.isolationLevel ? isolationLevelSql(opts.isolationLevel) : null;
150
+ const conn = await this.pool.getConnection();
151
+ try {
152
+ if (level)
153
+ await conn.query(`SET TRANSACTION ISOLATION LEVEL ${level}`);
154
+ await conn.beginTransaction();
155
+ try {
156
+ const result = await fn(new MysqlScope(conn));
157
+ await conn.commit();
158
+ return result;
159
+ }
160
+ catch (err) {
161
+ try {
162
+ await conn.rollback();
163
+ }
164
+ catch { /* best effort */ }
165
+ throw err;
166
+ }
167
+ }
168
+ finally {
169
+ conn.release();
170
+ }
171
+ }
172
+ async close() {
173
+ await this.pool.end();
174
+ }
175
+ }
176
+ //# sourceMappingURL=mysql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mysql.js","sourceRoot":"","sources":["../../../src/native/drivers/mysql.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import type { Driver, Transaction, Row, TransactionOptions } from '../driver.js';
2
+ /**
3
+ * The structural slice of porsager's `postgres` API we depend on. Typed here
4
+ * (not via `@types`) so the optional peer carries no compile-time dependency —
5
+ * same approach as the better-sqlite3 driver.
6
+ */
7
+ interface PgSql {
8
+ /** Run raw SQL with positional ($1, $2, …) params; resolves to the result rows
9
+ * (empty for statements with no result set). */
10
+ unsafe(query: string, params?: readonly unknown[]): Promise<unknown[]>;
11
+ /** Open a transaction; `fn` receives a connection-pinned `sql`. BEGIN/COMMIT,
12
+ * ROLLBACK on throw. */
13
+ begin<T>(fn: (sql: PgSql) => Promise<T>): Promise<T>;
14
+ /** Open a SAVEPOINT inside a transaction; only valid on a transaction `sql`. */
15
+ savepoint<T>(fn: (sql: PgSql) => Promise<T>): Promise<T>;
16
+ /** Drain the pool and close all connections. */
17
+ end(options?: {
18
+ timeout?: number;
19
+ }): Promise<void>;
20
+ }
21
+ /** Connection config for {@link PostgresDriver.open}. */
22
+ export interface PostgresDriverConfig {
23
+ /** Postgres connection string, e.g. `postgres://user:pass@host:5432/db`. */
24
+ url: string;
25
+ /** Forwarded to the porsager `postgres()` factory (e.g. `max`, `ssl`). */
26
+ options?: Record<string, unknown>;
27
+ }
28
+ /**
29
+ * A {@link Transaction} scope bound to one porsager `sql` handle — the pool, a
30
+ * transaction, or a savepoint. Every query on the scope runs on that handle, so
31
+ * a transaction-scoped query stays on the transaction's pinned connection.
32
+ */
33
+ declare class PgScope implements Transaction {
34
+ protected readonly sql: PgSql;
35
+ constructor(sql: PgSql);
36
+ execute(query: string, bindings: readonly unknown[]): Promise<Row[]>;
37
+ transaction<T>(fn: (tx: Transaction) => Promise<T>, opts?: TransactionOptions): Promise<T>;
38
+ }
39
+ /**
40
+ * {@link Driver} backed by porsager `postgres`. Construct via the static
41
+ * {@link PostgresDriver.open} factory, which lazy-imports the package and
42
+ * validates connectivity up front.
43
+ */
44
+ export declare class PostgresDriver extends PgScope implements Driver {
45
+ private constructor();
46
+ /**
47
+ * Resolve the `postgres` package, build a pool for `config.url`, validate the
48
+ * connection, and return a ready driver. Throws {@link NativeDriverError} with
49
+ * install guidance when the package is missing, or a connection error when the
50
+ * URL is unreachable — so failures surface at setup, not deep in a request.
51
+ */
52
+ static open(config: PostgresDriverConfig): Promise<PostgresDriver>;
53
+ transaction<T>(fn: (tx: Transaction) => Promise<T>, opts?: TransactionOptions): Promise<T>;
54
+ close(): Promise<void>;
55
+ }
56
+ export {};
57
+ //# sourceMappingURL=postgres.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../../src/native/drivers/postgres.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAIhF;;;;GAIG;AACH,UAAU,KAAK;IACb;qDACiD;IACjD,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;IACtE;6BACyB;IACzB,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;IACpD,gFAAgF;IAChF,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;IACxD,gDAAgD;IAChD,GAAG,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACnD;AAGD,yDAAyD;AACzD,MAAM,WAAW,oBAAoB;IACnC,4EAA4E;IAC5E,GAAG,EAAE,MAAM,CAAA;IACX,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC;AAED;;;;GAIG;AACH,cAAM,OAAQ,YAAW,WAAW;IACtB,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,KAAK;gBAAV,GAAG,EAAE,KAAK;IAEnC,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAgBpE,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;CAIjG;AAED;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,OAAQ,YAAW,MAAM;IAC3D,OAAO;IAIP;;;;;OAKG;WACU,IAAI,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC;IAyFzD,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;IAQnG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
@@ -0,0 +1,155 @@
1
+ // ─── postgres Driver (Node, porsager `postgres`) ───────────
2
+ //
3
+ // Concrete {@link Driver} over the `postgres` package (porsager). NODE-ONLY:
4
+ // `postgres` is an optional peer of `@rudderjs/orm`, lazy-`import()`ed inside
5
+ // `open()` so this module never drags the driver into a client bundle at eval
6
+ // time (cross-phase rule 5). Mirrors the same shape used by `@rudderjs/orm-drizzle`.
7
+ //
8
+ // Unlike better-sqlite3 (single synchronous connection), porsager pools
9
+ // connections. So a transaction MUST run on one pinned connection — we use
10
+ // porsager's own `sql.begin()` / `sql.savepoint()`, which reserve a connection
11
+ // for the whole scope, rather than issuing a bare `BEGIN` on the pool (which
12
+ // could land BEGIN and the following statements on different connections).
13
+ import { NativeDriverError } from '../errors.js';
14
+ import { isolationLevelSql, nestedIsolationError } from '../isolation.js';
15
+ /**
16
+ * A {@link Transaction} scope bound to one porsager `sql` handle — the pool, a
17
+ * transaction, or a savepoint. Every query on the scope runs on that handle, so
18
+ * a transaction-scoped query stays on the transaction's pinned connection.
19
+ */
20
+ class PgScope {
21
+ sql;
22
+ constructor(sql) {
23
+ this.sql = sql;
24
+ }
25
+ async execute(query, bindings) {
26
+ // porsager binds JS booleans / Dates / numbers to their native Postgres
27
+ // types, so no value coercion is needed (unlike the SQLite driver's
28
+ // boolean→0/1 mapping). A no-binding call (DDL) goes through the simple
29
+ // query protocol; statements with no result set resolve to an empty list.
30
+ const rows = bindings.length
31
+ ? await this.sql.unsafe(query, bindings)
32
+ : await this.sql.unsafe(query);
33
+ return rows;
34
+ }
35
+ // Nested transaction → SAVEPOINT on the current (already-transactional)
36
+ // connection. Reachable only from a scope created inside `begin` (the
37
+ // top-level driver overrides `transaction` to open the BEGIN), so `savepoint`
38
+ // is always valid here. An isolation level is rejected — a savepoint runs
39
+ // inside the open transaction, whose isolation is already fixed.
40
+ async transaction(fn, opts) {
41
+ if (opts?.isolationLevel)
42
+ throw nestedIsolationError();
43
+ return this.sql.savepoint((sp) => fn(new PgScope(sp)));
44
+ }
45
+ }
46
+ /**
47
+ * {@link Driver} backed by porsager `postgres`. Construct via the static
48
+ * {@link PostgresDriver.open} factory, which lazy-imports the package and
49
+ * validates connectivity up front.
50
+ */
51
+ export class PostgresDriver extends PgScope {
52
+ constructor(sql) {
53
+ super(sql);
54
+ }
55
+ /**
56
+ * Resolve the `postgres` package, build a pool for `config.url`, validate the
57
+ * connection, and return a ready driver. Throws {@link NativeDriverError} with
58
+ * install guidance when the package is missing, or a connection error when the
59
+ * URL is unreachable — so failures surface at setup, not deep in a request.
60
+ */
61
+ static async open(config) {
62
+ let factory;
63
+ try {
64
+ // porsager uses `export =`; a dynamic import wraps it in `.default`.
65
+ const mod = await import('postgres');
66
+ factory = mod.default ?? mod;
67
+ }
68
+ catch (err) {
69
+ throw new NativeDriverError(`[RudderJS ORM native] Failed to load "postgres". It is an optional peer of ` +
70
+ `@rudderjs/orm — install it with \`pnpm add postgres\` to use the native Postgres engine.`, { cause: err });
71
+ }
72
+ // Silence Postgres NOTICEs (e.g. "table does not exist, skipping" on DROP IF
73
+ // EXISTS) so they don't pollute CLI / migration output, and parse int8 /
74
+ // bigserial (OID 20) as a JS number rather than porsager's default string —
75
+ // so a model's auto-increment `id` is a number on Postgres just as it is on
76
+ // SQLite (INTEGER PK → number). Precision caveat: int8 values above 2^53 lose
77
+ // precision; that's fine for auto-increment ids, and a column needing the
78
+ // full int8 range should declare a cast.
79
+ const sql = factory(config.url, {
80
+ onnotice: () => { },
81
+ types: {
82
+ int8AsNumber: {
83
+ to: 20,
84
+ from: [20],
85
+ serialize: (x) => String(x),
86
+ parse: (x) => parseInt(x, 10),
87
+ },
88
+ // Replace porsager's default `date` type. Its serializer round-trips
89
+ // EVERY bound value through `new Date(x).toISOString()` — and because
90
+ // serializers register for all `from` OIDs, a param the server
91
+ // describes as date/timestamp/timestamptz (1082/1114/1184) hits it
92
+ // even when the JS value is a plain string. `new Date('2026-01-20
93
+ // 11:20:45')` parses as MACHINE-LOCAL time, so bound string timestamps
94
+ // were stored TZ-shifted on any non-UTC machine (silent data
95
+ // corruption; CI is UTC, which hid it). Strings now pass through
96
+ // verbatim — Postgres casts text natively, machine-TZ independent.
97
+ // `Date` values keep the exact previous behavior (`toISOString()`,
98
+ // same instant) and reads keep porsager's default parse (JS `Date`).
99
+ date: {
100
+ to: 1184,
101
+ from: [1082, 1114, 1184],
102
+ serialize: (x) => x instanceof Date ? x.toISOString()
103
+ : typeof x === 'number' ? new Date(x).toISOString()
104
+ : String(x),
105
+ parse: (x) => new Date(x),
106
+ },
107
+ // Replace porsager's default `json` type for the same reason as `date`
108
+ // above: its serializer `JSON.stringify`s EVERY bound value a server
109
+ // describes as json/jsonb (114/3802), so an already-stringified JSON
110
+ // param — the pg dialect's `jsonContains` binds `JSON.stringify(value)`,
111
+ // and apps porting sqlite-style code bind JSON text into jsonb columns —
112
+ // was DOUBLE-encoded: `'"php"'` arrived server-side as the JSON string
113
+ // `"\"php\""` and `@>` containment silently matched nothing. Strings now
114
+ // pass through verbatim (Postgres parses the JSON text natively; an
115
+ // invalid document surfaces as a clear server parse error); non-strings
116
+ // keep porsager's `JSON.stringify`, and reads keep its `JSON.parse`.
117
+ json: {
118
+ to: 114,
119
+ from: [114, 3802],
120
+ serialize: (x) => (typeof x === 'string' ? x : JSON.stringify(x)),
121
+ parse: (x) => JSON.parse(x),
122
+ },
123
+ },
124
+ ...config.options,
125
+ });
126
+ const driver = new PostgresDriver(sql);
127
+ try {
128
+ await sql.unsafe('select 1');
129
+ }
130
+ catch (err) {
131
+ await sql.end({ timeout: 1 }).catch(() => { });
132
+ const msg = err instanceof Error ? err.message : String(err);
133
+ throw new NativeDriverError(`[RudderJS ORM native] Could not connect to Postgres at the configured URL: ${msg}`, { cause: err });
134
+ }
135
+ return driver;
136
+ }
137
+ // Top-level transaction → BEGIN/COMMIT (ROLLBACK on throw). porsager's `begin`
138
+ // reserves a connection for the whole scope, so every query inside runs on it.
139
+ // An isolation level is applied via `SET TRANSACTION ISOLATION LEVEL` as the
140
+ // FIRST statement inside the transaction — Postgres allows it any time before
141
+ // the first query, and `isolationLevelSql` validates the level (the keyword is
142
+ // spliced, never bound).
143
+ async transaction(fn, opts) {
144
+ const level = opts?.isolationLevel ? isolationLevelSql(opts.isolationLevel) : null;
145
+ return this.sql.begin(async (tx) => {
146
+ if (level)
147
+ await tx.unsafe(`SET TRANSACTION ISOLATION LEVEL ${level}`);
148
+ return fn(new PgScope(tx));
149
+ });
150
+ }
151
+ async close() {
152
+ await this.sql.end({ timeout: 5 });
153
+ }
154
+ }
155
+ //# sourceMappingURL=postgres.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../../src/native/drivers/postgres.ts"],"names":[],"mappings":"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"}