@nextlyhq/adapter-drizzle 0.0.2-alpha.5 → 0.0.2-alpha.50
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/dist/{adapter-BxJVtttb.d.ts → adapter-C-DmzBg8.d.ts} +90 -58
- package/dist/{adapter-nvlxFkF-.d.cts → adapter-CZUQ2aV4.d.cts} +90 -58
- package/dist/{error-um1d_3Uo.d.cts → error-BrdknH2s.d.cts} +18 -1
- package/dist/{error-um1d_3Uo.d.ts → error-BrdknH2s.d.ts} +18 -1
- package/dist/index.cjs +215 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.mjs +216 -39
- package/dist/index.mjs.map +1 -1
- package/dist/{migration-BbO5meEV.d.cts → migration-BUc56kip.d.cts} +78 -0
- package/dist/{migration-Qe70wDOC.d.ts → migration-Bj84e15B.d.ts} +78 -0
- package/dist/migrations.d.cts +5 -4
- package/dist/migrations.d.ts +5 -4
- package/dist/types/index.cjs +8 -0
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.cts +3 -2
- package/dist/types/index.d.ts +3 -2
- package/dist/types/index.mjs +8 -1
- package/dist/types/index.mjs.map +1 -1
- package/dist/version-check.d.cts +1 -1
- package/dist/version-check.d.ts +1 -1
- package/package.json +9 -9
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getColumns, desc, asc, and, or, not, like, notBetween, between, isNotNull, isNull, notInArray, inArray, ilike, lte, gte, lt, gt, ne, eq } from 'drizzle-orm';
|
|
2
2
|
|
|
3
3
|
// src/adapter.ts
|
|
4
4
|
function buildDrizzleWhere(table, where) {
|
|
5
|
-
const columns =
|
|
5
|
+
const columns = getColumns(table);
|
|
6
6
|
return processWhereClause(columns, where);
|
|
7
7
|
}
|
|
8
8
|
function processWhereClause(columns, where) {
|
|
@@ -106,6 +106,21 @@ function createDatabaseError(options) {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
// src/adapter.ts
|
|
109
|
+
function affectedRowCount(result) {
|
|
110
|
+
if (Array.isArray(result)) {
|
|
111
|
+
const header = result[0];
|
|
112
|
+
if (header && typeof header.affectedRows === "number") {
|
|
113
|
+
return header.affectedRows;
|
|
114
|
+
}
|
|
115
|
+
return result.length;
|
|
116
|
+
}
|
|
117
|
+
const record = result;
|
|
118
|
+
const rowCount = record?.rowCount;
|
|
119
|
+
if (typeof rowCount === "number") return rowCount;
|
|
120
|
+
const changes = record?.changes;
|
|
121
|
+
if (typeof changes === "number") return changes;
|
|
122
|
+
return 0;
|
|
123
|
+
}
|
|
109
124
|
var DrizzleAdapter = class {
|
|
110
125
|
// ============================================================
|
|
111
126
|
// Drizzle Query API Support
|
|
@@ -134,6 +149,45 @@ var DrizzleAdapter = class {
|
|
|
134
149
|
getTableObject(tableName) {
|
|
135
150
|
return this.tableResolver?.getTable(tableName) ?? null;
|
|
136
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* Run a Drizzle-built statement and return its rows.
|
|
154
|
+
*
|
|
155
|
+
* @remarks
|
|
156
|
+
* The CRUD methods resolve their table through the schema registry and reject
|
|
157
|
+
* any name it does not declare, which leaves no way to read from a table the
|
|
158
|
+
* ORM does not know — one mid-rename, above all — except by assembling SQL and
|
|
159
|
+
* quoting identifiers by hand. This takes Drizzle's `sql` template instead, so
|
|
160
|
+
* the dialect in use decides the quoting and the parameter binding.
|
|
161
|
+
*
|
|
162
|
+
* Concrete rather than abstract so existing adapters keep working unchanged.
|
|
163
|
+
* The three drivers disagree about both the call and the result: node-postgres
|
|
164
|
+
* returns `{ rows }`, mysql2 a `[rows, fields]` tuple, and better-sqlite3 has
|
|
165
|
+
* no `execute` at all and answers `all`. Keeping that here rather than at each
|
|
166
|
+
* call site is the point — a caller reasoning about it would be reasoning
|
|
167
|
+
* about a driver it cannot see.
|
|
168
|
+
*
|
|
169
|
+
* @param statement - Drizzle `sql` template to run
|
|
170
|
+
* @returns Rows the statement produced
|
|
171
|
+
*/
|
|
172
|
+
async queryStatement(statement) {
|
|
173
|
+
if (this.getCapabilities().dialect === "sqlite") {
|
|
174
|
+
const db2 = this.getDrizzle();
|
|
175
|
+
return await db2.all(statement);
|
|
176
|
+
}
|
|
177
|
+
const db = this.getDrizzle();
|
|
178
|
+
const result = await db.execute(statement);
|
|
179
|
+
if (Array.isArray(result)) {
|
|
180
|
+
return Array.isArray(result[0]) ? result[0] : result;
|
|
181
|
+
}
|
|
182
|
+
if (typeof result === "object" && result !== null && Array.isArray(result.rows)) {
|
|
183
|
+
return result.rows;
|
|
184
|
+
}
|
|
185
|
+
throw this.createDatabaseError(
|
|
186
|
+
"query",
|
|
187
|
+
"Drizzle statement returned a result shape this adapter does not recognise; refusing to report it as an empty result.",
|
|
188
|
+
void 0
|
|
189
|
+
);
|
|
190
|
+
}
|
|
137
191
|
/**
|
|
138
192
|
* Map data keys from SQL column names (snake_case) to Drizzle JS property names (camelCase).
|
|
139
193
|
* Drizzle schemas define columns as e.g. `createdAt: timestamp("created_at")` — the JS
|
|
@@ -173,6 +227,107 @@ var DrizzleAdapter = class {
|
|
|
173
227
|
}
|
|
174
228
|
return mapped;
|
|
175
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* Map data keys from Drizzle JS property names to SQL column names for the
|
|
232
|
+
* raw-SQL transaction insert path. The transaction context builds INSERT
|
|
233
|
+
* statements from Object.keys(data) used directly as column identifiers, so a
|
|
234
|
+
* table whose Drizzle property names differ from its SQL column names
|
|
235
|
+
* (camelCase core tables like nextly_versions) needs its keys translated
|
|
236
|
+
* first. For tables whose property names already equal their column names
|
|
237
|
+
* (the dynamic dc_/single_/comp_ tables) every lookup is identity, so
|
|
238
|
+
* existing callers are unaffected.
|
|
239
|
+
*/
|
|
240
|
+
mapKeysToSqlColumns(tableObj, data) {
|
|
241
|
+
if (!tableObj || typeof tableObj !== "object") return data;
|
|
242
|
+
const jsToSql = /* @__PURE__ */ new Map();
|
|
243
|
+
for (const [jsName, colDef] of Object.entries(
|
|
244
|
+
tableObj
|
|
245
|
+
)) {
|
|
246
|
+
if (colDef && typeof colDef === "object" && "name" in colDef && typeof colDef.name === "string") {
|
|
247
|
+
jsToSql.set(jsName, colDef.name);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (jsToSql.size === 0) return data;
|
|
251
|
+
const out = {};
|
|
252
|
+
for (const [key, value] of Object.entries(data)) {
|
|
253
|
+
out[jsToSql.get(key) ?? key] = value;
|
|
254
|
+
}
|
|
255
|
+
return out;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Map a list of column identifiers (Drizzle property names) to their SQL
|
|
259
|
+
* column names, for the raw-SQL transaction insert paths that build a
|
|
260
|
+
* RETURNING clause from `options.returning`. Same identity behavior as
|
|
261
|
+
* `mapKeysToSqlColumns`: names that are already SQL columns (the dynamic
|
|
262
|
+
* dc_/single_/comp_ tables) pass through unchanged.
|
|
263
|
+
*/
|
|
264
|
+
mapColumnNamesToSql(tableObj, names) {
|
|
265
|
+
if (!tableObj || typeof tableObj !== "object") return names;
|
|
266
|
+
const jsToSql = /* @__PURE__ */ new Map();
|
|
267
|
+
for (const [jsName, colDef] of Object.entries(
|
|
268
|
+
tableObj
|
|
269
|
+
)) {
|
|
270
|
+
if (colDef && typeof colDef === "object" && "name" in colDef && typeof colDef.name === "string") {
|
|
271
|
+
jsToSql.set(jsName, colDef.name);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (jsToSql.size === 0) return names;
|
|
275
|
+
return names.map((n) => jsToSql.get(n) ?? n);
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Remap a raw-SQL result row's KEYS from SQL column names to Drizzle property
|
|
279
|
+
* names, so the raw-SQL transaction insert paths return the same key casing
|
|
280
|
+
* as the non-transactional (Drizzle) insert. Keys only - values are left
|
|
281
|
+
* untouched, so this does not change how JSON/date columns are decoded. For
|
|
282
|
+
* tables whose property names already equal their SQL columns (the dynamic
|
|
283
|
+
* dc_/single_/comp_ tables) every lookup is identity, so existing callers see
|
|
284
|
+
* no change.
|
|
285
|
+
*/
|
|
286
|
+
mapRowKeysToJs(tableObj, row) {
|
|
287
|
+
if (!tableObj || typeof tableObj !== "object" || !row || typeof row !== "object") {
|
|
288
|
+
return row;
|
|
289
|
+
}
|
|
290
|
+
const sqlToJs = /* @__PURE__ */ new Map();
|
|
291
|
+
for (const [jsName, colDef] of Object.entries(
|
|
292
|
+
tableObj
|
|
293
|
+
)) {
|
|
294
|
+
if (colDef && typeof colDef === "object" && "name" in colDef && typeof colDef.name === "string") {
|
|
295
|
+
sqlToJs.set(colDef.name, jsName);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (sqlToJs.size === 0) return row;
|
|
299
|
+
const out = {};
|
|
300
|
+
for (const [key, value] of Object.entries(row)) {
|
|
301
|
+
out[sqlToJs.get(key) ?? key] = value;
|
|
302
|
+
}
|
|
303
|
+
return out;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Build a Drizzle column projection object (`{ propertyName: column }`) from a
|
|
307
|
+
* requested column list, used by `select` (columns) and `insert` (returning).
|
|
308
|
+
* A requested name resolves against either the Drizzle property name
|
|
309
|
+
* (camelCase) or the SQL column name (snake_case); the projection is keyed by
|
|
310
|
+
* the property name so the row shape matches a full select. Returns undefined
|
|
311
|
+
* for `"*"` or when nothing resolves, so callers fall back to all columns.
|
|
312
|
+
*/
|
|
313
|
+
buildColumnProjection(tableObj, names) {
|
|
314
|
+
if (names == null || names === "*" || !tableObj || typeof tableObj !== "object") {
|
|
315
|
+
return void 0;
|
|
316
|
+
}
|
|
317
|
+
const cols = getColumns(tableObj);
|
|
318
|
+
const byAnyName = {};
|
|
319
|
+
for (const [jsName, col] of Object.entries(cols)) {
|
|
320
|
+
byAnyName[jsName] = { jsName, col };
|
|
321
|
+
const sqlName = col?.name;
|
|
322
|
+
if (typeof sqlName === "string") byAnyName[sqlName] = { jsName, col };
|
|
323
|
+
}
|
|
324
|
+
const projection = {};
|
|
325
|
+
for (const name of names) {
|
|
326
|
+
const hit = byAnyName[name];
|
|
327
|
+
if (hit) projection[hit.jsName] = hit.col;
|
|
328
|
+
}
|
|
329
|
+
return Object.keys(projection).length ? projection : void 0;
|
|
330
|
+
}
|
|
176
331
|
// ============================================================
|
|
177
332
|
// Connection Status (Default implementations, can override)
|
|
178
333
|
// ============================================================
|
|
@@ -326,12 +481,13 @@ var DrizzleAdapter = class {
|
|
|
326
481
|
* });
|
|
327
482
|
* ```
|
|
328
483
|
*/
|
|
329
|
-
async select(table, options) {
|
|
484
|
+
async select(table, options, executor) {
|
|
330
485
|
const tableObj = this.getTableObject(table);
|
|
331
486
|
if (tableObj) {
|
|
332
487
|
try {
|
|
333
|
-
const db = this.getDrizzle();
|
|
334
|
-
|
|
488
|
+
const db = executor ?? this.getDrizzle();
|
|
489
|
+
const projection = options?.columns?.length ? this.buildColumnProjection(tableObj, options.columns) : void 0;
|
|
490
|
+
let query = projection ? db.select(projection).from(tableObj) : db.select().from(tableObj);
|
|
335
491
|
if (options?.where) {
|
|
336
492
|
const whereCondition = buildDrizzleWhere(
|
|
337
493
|
tableObj,
|
|
@@ -342,7 +498,7 @@ var DrizzleAdapter = class {
|
|
|
342
498
|
}
|
|
343
499
|
}
|
|
344
500
|
if (options?.orderBy?.length) {
|
|
345
|
-
const columns =
|
|
501
|
+
const columns = getColumns(tableObj);
|
|
346
502
|
const orderClauses = options.orderBy.map((o) => {
|
|
347
503
|
const col = columns[o.column];
|
|
348
504
|
if (!col) return void 0;
|
|
@@ -358,6 +514,16 @@ var DrizzleAdapter = class {
|
|
|
358
514
|
if (options?.offset !== void 0) {
|
|
359
515
|
query = query.offset(options.offset);
|
|
360
516
|
}
|
|
517
|
+
if (options?.forUpdate && !executor) {
|
|
518
|
+
throw this.createDatabaseError(
|
|
519
|
+
"query",
|
|
520
|
+
"forUpdate requires a transaction executor: a lock request on the pooled connection takes no durable lock and cannot prevent a concurrent write.",
|
|
521
|
+
void 0
|
|
522
|
+
);
|
|
523
|
+
}
|
|
524
|
+
if (options?.forUpdate && this.dialect !== "sqlite") {
|
|
525
|
+
query = query.for("update");
|
|
526
|
+
}
|
|
361
527
|
return await query;
|
|
362
528
|
} catch (error) {
|
|
363
529
|
throw this.handleQueryError(error, "select", table);
|
|
@@ -389,8 +555,12 @@ var DrizzleAdapter = class {
|
|
|
389
555
|
* });
|
|
390
556
|
* ```
|
|
391
557
|
*/
|
|
392
|
-
async selectOne(table, options) {
|
|
393
|
-
const results = await this.select(
|
|
558
|
+
async selectOne(table, options, executor) {
|
|
559
|
+
const results = await this.select(
|
|
560
|
+
table,
|
|
561
|
+
{ ...options, limit: 1 },
|
|
562
|
+
executor
|
|
563
|
+
);
|
|
394
564
|
return results.length > 0 ? results[0] : null;
|
|
395
565
|
}
|
|
396
566
|
/**
|
|
@@ -422,19 +592,22 @@ var DrizzleAdapter = class {
|
|
|
422
592
|
const mappedData = this.mapDataToColumnNames(tableObj, data);
|
|
423
593
|
const db = this.getDrizzle();
|
|
424
594
|
const caps = this.getCapabilities();
|
|
425
|
-
|
|
426
|
-
|
|
595
|
+
const returning = options?.returning;
|
|
596
|
+
const wantsReturning = returning != null && !(Array.isArray(returning) && returning.length === 0);
|
|
597
|
+
if (caps.supportsReturning && wantsReturning) {
|
|
598
|
+
const projection = this.buildColumnProjection(tableObj, returning);
|
|
599
|
+
const insertQuery = db.insert(tableObj).values(mappedData);
|
|
600
|
+
const result2 = await (projection ? insertQuery.returning(projection) : insertQuery.returning());
|
|
427
601
|
return Array.isArray(result2) ? result2[0] : result2;
|
|
428
602
|
}
|
|
429
603
|
const result = await db.insert(tableObj).values(mappedData);
|
|
430
|
-
if (!caps.supportsReturning &&
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
}
|
|
604
|
+
if (!caps.supportsReturning && wantsReturning && data.id !== void 0) {
|
|
605
|
+
return await this.selectOne(table, {
|
|
606
|
+
columns: returning === "*" ? void 0 : returning,
|
|
607
|
+
where: {
|
|
608
|
+
and: [{ column: "id", op: "=", value: data.id }]
|
|
609
|
+
}
|
|
610
|
+
});
|
|
438
611
|
}
|
|
439
612
|
return Array.isArray(result) ? result[0] : result;
|
|
440
613
|
} catch (error) {
|
|
@@ -504,11 +677,11 @@ var DrizzleAdapter = class {
|
|
|
504
677
|
* );
|
|
505
678
|
* ```
|
|
506
679
|
*/
|
|
507
|
-
async update(table, data, where, options) {
|
|
680
|
+
async update(table, data, where, options, executor) {
|
|
508
681
|
const tableObj = this.getTableObject(table);
|
|
509
682
|
if (tableObj) {
|
|
510
683
|
try {
|
|
511
|
-
const db = this.getDrizzle();
|
|
684
|
+
const db = executor ?? this.getDrizzle();
|
|
512
685
|
const caps = this.getCapabilities();
|
|
513
686
|
const mappedData = this.mapDataToColumnNames(tableObj, data);
|
|
514
687
|
let query = db.update(tableObj).set(mappedData);
|
|
@@ -521,7 +694,7 @@ var DrizzleAdapter = class {
|
|
|
521
694
|
}
|
|
522
695
|
await query;
|
|
523
696
|
if (!caps.supportsReturning && options?.returning) {
|
|
524
|
-
return await this.select(table, { where });
|
|
697
|
+
return await this.select(table, { where }, executor);
|
|
525
698
|
}
|
|
526
699
|
return [];
|
|
527
700
|
} catch (error) {
|
|
@@ -556,18 +729,18 @@ var DrizzleAdapter = class {
|
|
|
556
729
|
* console.log(`Deleted ${count} users`);
|
|
557
730
|
* ```
|
|
558
731
|
*/
|
|
559
|
-
async delete(table, where, _options) {
|
|
732
|
+
async delete(table, where, _options, executor) {
|
|
560
733
|
const tableObj = this.getTableObject(table);
|
|
561
734
|
if (tableObj) {
|
|
562
735
|
try {
|
|
563
|
-
const db = this.getDrizzle();
|
|
736
|
+
const db = executor ?? this.getDrizzle();
|
|
564
737
|
let query = db.delete(tableObj);
|
|
565
738
|
const whereCondition = buildDrizzleWhere(tableObj, where);
|
|
566
739
|
if (whereCondition) {
|
|
567
740
|
query = query.where(whereCondition);
|
|
568
741
|
}
|
|
569
742
|
const result = await query;
|
|
570
|
-
return
|
|
743
|
+
return affectedRowCount(result);
|
|
571
744
|
} catch (error) {
|
|
572
745
|
throw this.handleQueryError(error, "delete", table);
|
|
573
746
|
}
|
|
@@ -605,13 +778,13 @@ var DrizzleAdapter = class {
|
|
|
605
778
|
* });
|
|
606
779
|
* ```
|
|
607
780
|
*/
|
|
608
|
-
async upsert(table, data, options) {
|
|
781
|
+
async upsert(table, data, options, executor) {
|
|
609
782
|
const tableObj = this.getTableObject(table);
|
|
610
783
|
if (tableObj) {
|
|
611
784
|
try {
|
|
612
|
-
const db = this.getDrizzle();
|
|
785
|
+
const db = executor ?? this.getDrizzle();
|
|
613
786
|
const caps = this.getCapabilities();
|
|
614
|
-
const columns =
|
|
787
|
+
const columns = getColumns(tableObj);
|
|
615
788
|
const conflictTarget = options.conflictColumns.map((col) => columns[col]).filter(Boolean);
|
|
616
789
|
const conflictSet = new Set(options.conflictColumns);
|
|
617
790
|
const updateData = {};
|
|
@@ -636,17 +809,21 @@ var DrizzleAdapter = class {
|
|
|
636
809
|
}
|
|
637
810
|
await query;
|
|
638
811
|
if (options.conflictColumns.length && data[options.conflictColumns[0]] !== void 0) {
|
|
639
|
-
return await this.selectOne(
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
812
|
+
return await this.selectOne(
|
|
813
|
+
table,
|
|
814
|
+
{
|
|
815
|
+
where: {
|
|
816
|
+
and: [
|
|
817
|
+
{
|
|
818
|
+
column: options.conflictColumns[0],
|
|
819
|
+
op: "=",
|
|
820
|
+
value: data[options.conflictColumns[0]]
|
|
821
|
+
}
|
|
822
|
+
]
|
|
823
|
+
}
|
|
824
|
+
},
|
|
825
|
+
executor
|
|
826
|
+
);
|
|
650
827
|
}
|
|
651
828
|
return data;
|
|
652
829
|
} catch (error) {
|
|
@@ -972,7 +1149,7 @@ var DrizzleAdapter = class {
|
|
|
972
1149
|
break;
|
|
973
1150
|
case "mysql":
|
|
974
1151
|
sql = `
|
|
975
|
-
SELECT table_name
|
|
1152
|
+
SELECT table_name AS table_name
|
|
976
1153
|
FROM information_schema.tables
|
|
977
1154
|
WHERE table_schema = DATABASE()
|
|
978
1155
|
AND table_type = 'BASE TABLE'
|