@nextlyhq/adapter-sqlite 0.0.2-alpha.73 → 0.0.2-alpha.74
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.cjs +81 -259
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -97
- package/dist/index.d.ts +14 -97
- package/dist/index.mjs +81 -259
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -68,7 +68,7 @@ Most users do not need this.
|
|
|
68
68
|
|
|
69
69
|
- **Single writer.** SQLite serializes writes; concurrent transactions queue. Fine for one user, painful for production traffic.
|
|
70
70
|
- **No SSL or TLS.** Not applicable to a local file.
|
|
71
|
-
- **Limited types.** No native arrays, no JSONB; JSON is stored as TEXT. ILIKE
|
|
71
|
+
- **Limited types.** No native arrays, no JSONB; JSON is stored as TEXT. ILIKE and case-insensitive `contains` fold both sides with `nextly_fold_case()`, a Unicode case fold the adapter registers on every connection it opens (SQLite's own `LOWER()` folds ASCII letters only), then compare with `LIKE`.
|
|
72
72
|
- **Savepoints.** Supported.
|
|
73
73
|
- **`RETURNING` clause.** Supported (SQLite 3.35+).
|
|
74
74
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,10 +1,26 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
let node_async_hooks = require("node:async_hooks");
|
|
3
2
|
let _nextlyhq_adapter_drizzle = require("@nextlyhq/adapter-drizzle");
|
|
4
3
|
let _nextlyhq_adapter_drizzle_types = require("@nextlyhq/adapter-drizzle/types");
|
|
5
4
|
let _nextlyhq_adapter_drizzle_version_check = require("@nextlyhq/adapter-drizzle/version-check");
|
|
6
5
|
let drizzle_orm_better_sqlite3 = require("drizzle-orm/better-sqlite3");
|
|
7
6
|
let drizzle_orm_sqlite_core = require("drizzle-orm/sqlite-core");
|
|
7
|
+
let _nextlyhq_adapter_drizzle_text_match = require("@nextlyhq/adapter-drizzle/text-match");
|
|
8
|
+
// src/sql-functions.ts
|
|
9
|
+
/**
|
|
10
|
+
* The SQL functions a SQLite connection needs before Nextly's statements run on it.
|
|
11
|
+
*
|
|
12
|
+
* @module sql-functions
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Register the SQL functions Nextly's statements call on SQLite, on `db`: the Unicode case fold
|
|
16
|
+
* (`nextly_fold_case`), since SQLite's own `lower()` folds ASCII letters only.
|
|
17
|
+
*
|
|
18
|
+
* Every connection the adapter opens is handed here as it opens, before anything runs on it, so
|
|
19
|
+
* no statement can reach a connection without the function.
|
|
20
|
+
*/
|
|
21
|
+
function registerSqliteFunctions(db) {
|
|
22
|
+
(0, _nextlyhq_adapter_drizzle_text_match.registerSqliteFoldCase)(db);
|
|
23
|
+
}
|
|
8
24
|
// src/index.ts
|
|
9
25
|
/**
|
|
10
26
|
* @nextlyhq/adapter-sqlite
|
|
@@ -106,7 +122,8 @@ function sanitizeSqliteValue(v) {
|
|
|
106
122
|
* - No connection pooling (single file/connection)
|
|
107
123
|
* - RETURNING clause supported (SQLite 3.35+)
|
|
108
124
|
* - Savepoints supported via nested transactions
|
|
109
|
-
* - No native ILIKE (
|
|
125
|
+
* - No native ILIKE (both sides case-folded, then LIKE; the fold is Nextly's own
|
|
126
|
+
* `nextly_fold_case`, registered on connect, since SQLite's `lower()` folds ASCII only)
|
|
110
127
|
* - JSON support (not JSONB)
|
|
111
128
|
* - No array types
|
|
112
129
|
*
|
|
@@ -162,18 +179,6 @@ var SqliteAdapter = class extends _nextlyhq_adapter_drizzle.DrizzleAdapter {
|
|
|
162
179
|
*/
|
|
163
180
|
transactionQueue = Promise.resolve();
|
|
164
181
|
/**
|
|
165
|
-
* The transaction the current async chain is running inside, if any.
|
|
166
|
-
*
|
|
167
|
-
* A `transaction()` call made from INSIDE a transaction's work — a store
|
|
168
|
-
* writing on behalf of the caller, a plugin's write inside its own
|
|
169
|
-
* `ctx.db.transaction` — used to queue behind the very transaction that
|
|
170
|
-
* was waiting for it, and neither ever settled: that hung every later
|
|
171
|
-
* transaction on the instance too. Such a call now runs as a SAVEPOINT of
|
|
172
|
-
* the active transaction instead, so it commits or rolls back with it and
|
|
173
|
-
* its own failure undoes only its own part.
|
|
174
|
-
*/
|
|
175
|
-
transactionScope = new node_async_hooks.AsyncLocalStorage();
|
|
176
|
-
/**
|
|
177
182
|
* Creates a new SQLite adapter instance.
|
|
178
183
|
*
|
|
179
184
|
* @param config - Adapter configuration
|
|
@@ -210,6 +215,7 @@ var SqliteAdapter = class extends _nextlyhq_adapter_drizzle.DrizzleAdapter {
|
|
|
210
215
|
readonly: this.config.readonly ?? false,
|
|
211
216
|
timeout: this.config.busyTimeout ?? DEFAULT_CONFIG.busyTimeout
|
|
212
217
|
});
|
|
218
|
+
registerSqliteFunctions(this.db);
|
|
213
219
|
if ((this.config.wal ?? DEFAULT_CONFIG.wal) && dbPath !== ":memory:" && !this.config.readonly) this.db.pragma("journal_mode = WAL");
|
|
214
220
|
if (this.config.foreignKeys ?? DEFAULT_CONFIG.foreignKeys) this.db.pragma("foreign_keys = ON");
|
|
215
221
|
await (0, _nextlyhq_adapter_drizzle_version_check.checkDialectVersion)(this.db, "sqlite");
|
|
@@ -300,6 +306,10 @@ var SqliteAdapter = class extends _nextlyhq_adapter_drizzle.DrizzleAdapter {
|
|
|
300
306
|
throw this.classifyError(error, sql);
|
|
301
307
|
}
|
|
302
308
|
}
|
|
309
|
+
/** How long a transaction waits for the connection: `pool.connectionTimeoutMs`. */
|
|
310
|
+
transactionWaitMs() {
|
|
311
|
+
return this.config.pool?.connectionTimeoutMs ?? DEFAULT_CONFIG.connectionTimeoutMs;
|
|
312
|
+
}
|
|
303
313
|
/**
|
|
304
314
|
* Execute work within a transaction.
|
|
305
315
|
*
|
|
@@ -323,18 +333,16 @@ var SqliteAdapter = class extends _nextlyhq_adapter_drizzle.DrizzleAdapter {
|
|
|
323
333
|
* Note: SQLite uses DEFERRED, IMMEDIATE, or EXCLUSIVE transaction modes
|
|
324
334
|
* rather than isolation levels. This adapter uses IMMEDIATE.
|
|
325
335
|
*/
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
await this.runHeldEffects(effects);
|
|
337
|
-
return result;
|
|
336
|
+
transaction(work, options) {
|
|
337
|
+
return this.openOrJoin(work, options, {
|
|
338
|
+
run: () => this.takeTurn(() => this.runTransaction(work, options)),
|
|
339
|
+
retryable: () => false,
|
|
340
|
+
describe: () => ({
|
|
341
|
+
label: "a retryable error",
|
|
342
|
+
detail: {}
|
|
343
|
+
}),
|
|
344
|
+
logger: this.config.logger
|
|
345
|
+
});
|
|
338
346
|
}
|
|
339
347
|
/**
|
|
340
348
|
* Runs `work` outside a transaction, each statement committing as it runs,
|
|
@@ -361,189 +369,58 @@ var SqliteAdapter = class extends _nextlyhq_adapter_drizzle.DrizzleAdapter {
|
|
|
361
369
|
this.transactionQueue = previous.then(() => next).catch(() => void 0);
|
|
362
370
|
return next;
|
|
363
371
|
}
|
|
364
|
-
/**
|
|
365
|
-
|
|
366
|
-
* or run it now when none does.
|
|
367
|
-
*
|
|
368
|
-
* The effect belongs to the scope this async context runs in, even one
|
|
369
|
-
* that has already released or rolled back: a service whose own
|
|
370
|
-
* transaction nested as a savepoint registers from its caller's scope once
|
|
371
|
-
* that savepoint has released, and the change is undoable for as long as
|
|
372
|
-
* any scope around it is. The outermost transaction runs the effect once
|
|
373
|
-
* its COMMIT succeeds, unless a scope between the effect's scope and the
|
|
374
|
-
* outermost transaction rolled back, and drops every effect on ROLLBACK or
|
|
375
|
-
* a failed COMMIT. A context whose outermost transaction has already
|
|
376
|
-
* finished is outside any transaction, so its effect runs now, unless what
|
|
377
|
-
* it announces was undone and it has run no transaction since.
|
|
378
|
-
*/
|
|
379
|
-
async afterCommit(effect, onDeferredFailure) {
|
|
380
|
-
const scope = this.transactionScope.getStore();
|
|
381
|
-
if (!scope) {
|
|
382
|
-
await effect();
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
const root = outermost(scope);
|
|
386
|
-
if (!root.finished) {
|
|
387
|
-
root.held.push({
|
|
388
|
-
effect: this.inRegisteringContext(effect),
|
|
389
|
-
onDeferredFailure,
|
|
390
|
-
scope,
|
|
391
|
-
writesBefore: scope.writesAfterClosing
|
|
392
|
-
});
|
|
393
|
-
return;
|
|
394
|
-
}
|
|
395
|
-
if (!undone(scope, scope.writesAfterClosing)) await effect();
|
|
396
|
-
}
|
|
397
|
-
/**
|
|
398
|
-
* `effect`, bound to the async context it is registered from.
|
|
399
|
-
*
|
|
400
|
-
* A held effect runs after the outermost COMMIT, from the code that ran the
|
|
401
|
-
* outermost transaction, so without this it sees that code's context rather
|
|
402
|
-
* than its own: whatever its caller pinned around the write is gone. That
|
|
403
|
-
* includes who is calling. A scope pinned for a scoped API key lost there
|
|
404
|
-
* leaves a hook's nested call judged by the key's owner instead of the key,
|
|
405
|
-
* and a person's frame lost there leaves the hook told of nobody.
|
|
406
|
-
*
|
|
407
|
-
* The adapter's own transaction scope is the one store it leaves: the
|
|
408
|
-
* effect runs once that transaction has finished, outside it, as an effect
|
|
409
|
-
* held to the outermost commit always has.
|
|
410
|
-
*/
|
|
411
|
-
inRegisteringContext(effect) {
|
|
412
|
-
return node_async_hooks.AsyncResource.bind(() => this.transactionScope.exit(effect));
|
|
413
|
-
}
|
|
414
|
-
/**
|
|
415
|
-
* Run the effects a committed transaction held, in order. A failure is
|
|
416
|
-
* reported, never thrown: the change is durable, and reporting the
|
|
417
|
-
* transaction as failed would invite a retry of something already done.
|
|
418
|
-
*/
|
|
419
|
-
async runHeldEffects(effects) {
|
|
420
|
-
for (const { effect, onDeferredFailure } of effects) try {
|
|
421
|
-
await effect();
|
|
422
|
-
} catch (error) {
|
|
423
|
-
this.reportHeldEffectFailure(error, onDeferredFailure);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
/** Hand a held effect's failure to its reporter, or to the adapter's log. */
|
|
427
|
-
reportHeldEffectFailure(error, onDeferredFailure) {
|
|
428
|
-
try {
|
|
429
|
-
if (onDeferredFailure) {
|
|
430
|
-
onDeferredFailure(error);
|
|
431
|
-
return;
|
|
432
|
-
}
|
|
433
|
-
} catch {}
|
|
434
|
-
const failure = error instanceof Error ? error : new Error(String(error));
|
|
372
|
+
/** A held effect's failure that no reporter took goes to the adapter's logger. */
|
|
373
|
+
logHeldEffectFailure(failure) {
|
|
435
374
|
if (this.config.logger?.error) this.config.logger.error(failure, { phase: "after-commit" });
|
|
436
|
-
else
|
|
437
|
-
}
|
|
438
|
-
/**
|
|
439
|
-
* Whether a `transaction()` call made here would join an open transaction
|
|
440
|
-
* as a savepoint. On SQLite it would: the connection is the only one, so a
|
|
441
|
-
* transaction open on it encloses whatever the async chain that opened it
|
|
442
|
-
* starts.
|
|
443
|
-
*/
|
|
444
|
-
inTransaction() {
|
|
445
|
-
return this.nestingScope() !== void 0;
|
|
446
|
-
}
|
|
447
|
-
/**
|
|
448
|
-
* Whether the calling async flow is inside a transaction that has not
|
|
449
|
-
* finished, judged from the transaction this flow was started inside,
|
|
450
|
-
* never from the connection: another request's open transaction answers
|
|
451
|
-
* false here, where its own `transaction()` queues behind that one.
|
|
452
|
-
*
|
|
453
|
-
* A flow started inside a transaction, even inside a savepoint that has
|
|
454
|
-
* since released, stays inside it until its outermost transaction has
|
|
455
|
-
* committed or rolled back: until then whatever it writes on the one
|
|
456
|
-
* connection lands in that transaction.
|
|
457
|
-
*/
|
|
458
|
-
transactionOpenInFlow() {
|
|
459
|
-
const own = this.transactionScope.getStore();
|
|
460
|
-
return own !== void 0 && !outermost(own).finished;
|
|
461
|
-
}
|
|
462
|
-
/**
|
|
463
|
-
* The scope a `transaction()` call made here nests in, or none when it
|
|
464
|
-
* opens a transaction of its own.
|
|
465
|
-
*
|
|
466
|
-
* A call made later from inside a savepoint that has since released runs
|
|
467
|
-
* inside the innermost scope open on the connection. Queued on an enclosing
|
|
468
|
-
* scope, or on the instance, it would wait behind the scope running there,
|
|
469
|
-
* which may be the one awaiting it. Savepoints on one connection form a
|
|
470
|
-
* stack, so whatever opens now is inside that innermost scope anyway; when
|
|
471
|
-
* none is open the call queues on the instance.
|
|
472
|
-
*
|
|
473
|
-
* The innermost open scope need not be related to the call. When it is a
|
|
474
|
-
* sibling savepoint that later rolls back, the call's write rolls back with
|
|
475
|
-
* it, although the call itself already resolved. Waiting for an unrelated
|
|
476
|
-
* scope instead could wait on the very scope that awaits the call.
|
|
477
|
-
*/
|
|
478
|
-
nestingScope() {
|
|
479
|
-
const own = this.transactionScope.getStore();
|
|
480
|
-
return own?.active ? own : own?.open.at(-1);
|
|
375
|
+
else super.logHeldEffectFailure(failure);
|
|
481
376
|
}
|
|
482
377
|
/**
|
|
483
|
-
*
|
|
484
|
-
* resolves, rolled back to when it throws.
|
|
378
|
+
* The statements of a savepoint `depth` deep on the one connection:
|
|
379
|
+
* released when its work resolves, rolled back to when it throws.
|
|
485
380
|
*/
|
|
486
|
-
|
|
381
|
+
savepointSteps(depth) {
|
|
487
382
|
const db = this.ensureDb();
|
|
488
|
-
const name = `nextly_sp_${
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
383
|
+
const name = `nextly_sp_${depth}`;
|
|
384
|
+
return {
|
|
385
|
+
context: this.createTransactionContext(db),
|
|
386
|
+
begin: () => {
|
|
387
|
+
db.exec(`SAVEPOINT ${name}`);
|
|
388
|
+
},
|
|
389
|
+
commit: () => {
|
|
390
|
+
db.exec(`RELEASE ${name}`);
|
|
391
|
+
},
|
|
392
|
+
rollback: () => {
|
|
393
|
+
db.exec(`ROLLBACK TO ${name}`);
|
|
496
394
|
db.exec(`RELEASE ${name}`);
|
|
497
|
-
return result;
|
|
498
|
-
} catch (error) {
|
|
499
|
-
await settleNested(scope);
|
|
500
|
-
scope.rolledBack = true;
|
|
501
|
-
try {
|
|
502
|
-
db.exec(`ROLLBACK TO ${name}`);
|
|
503
|
-
db.exec(`RELEASE ${name}`);
|
|
504
|
-
} catch {}
|
|
505
|
-
throw error;
|
|
506
395
|
}
|
|
507
|
-
}
|
|
508
|
-
if ((0, _nextlyhq_adapter_drizzle_types.isApplicationError)(error)) throw error;
|
|
509
|
-
throw this.classifyError(error);
|
|
510
|
-
}
|
|
396
|
+
};
|
|
511
397
|
}
|
|
512
398
|
/**
|
|
513
|
-
*
|
|
514
|
-
*
|
|
515
|
-
*
|
|
399
|
+
* One attempt's transaction body, settled rather than rejected for the
|
|
400
|
+
* transaction's own failure (`runOutermost`). Kept private so callers always
|
|
401
|
+
* go through the serialized `transaction()` queue above and the
|
|
402
|
+
* BEGIN/COMMIT pair is never invoked outside of it.
|
|
516
403
|
*/
|
|
517
|
-
async runTransaction(work) {
|
|
404
|
+
async runTransaction(work, options) {
|
|
518
405
|
const db = this.ensureDb();
|
|
519
|
-
const startTime = Date.now();
|
|
520
406
|
try {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
407
|
+
return await this.settleOutermost({
|
|
408
|
+
context: this.createTransactionContext(db),
|
|
409
|
+
join: { adapter: (depth) => this.savepointSteps(depth) },
|
|
410
|
+
begin: () => {
|
|
411
|
+
db.exec("BEGIN IMMEDIATE");
|
|
412
|
+
},
|
|
413
|
+
commit: () => {
|
|
414
|
+
db.exec("COMMIT");
|
|
415
|
+
},
|
|
416
|
+
rollback: () => {
|
|
417
|
+
try {
|
|
418
|
+
db.exec("ROLLBACK");
|
|
419
|
+
} catch (error) {
|
|
420
|
+
if (db.inTransaction) throw error;
|
|
421
|
+
}
|
|
532
422
|
}
|
|
533
|
-
|
|
534
|
-
result,
|
|
535
|
-
effects: scope.held.filter((held) => !undone(held.scope, held.writesBefore))
|
|
536
|
-
};
|
|
537
|
-
} catch (error) {
|
|
538
|
-
await settleNested(scope);
|
|
539
|
-
scope.rolledBack = true;
|
|
540
|
-
scope.finished = true;
|
|
541
|
-
scope.held.length = 0;
|
|
542
|
-
try {
|
|
543
|
-
db.exec("ROLLBACK");
|
|
544
|
-
} catch {}
|
|
545
|
-
throw error;
|
|
546
|
-
}
|
|
423
|
+
}, work, options);
|
|
547
424
|
} catch (error) {
|
|
548
425
|
if ((0, _nextlyhq_adapter_drizzle_types.isApplicationError)(error)) throw error;
|
|
549
426
|
throw this.classifyError(error);
|
|
@@ -587,6 +464,7 @@ var SqliteAdapter = class extends _nextlyhq_adapter_drizzle.DrizzleAdapter {
|
|
|
587
464
|
if (data.length === 0) return [];
|
|
588
465
|
const db = this.ensureDb();
|
|
589
466
|
if (data.length === 1) return [await this.insert(table, data[0], options)];
|
|
467
|
+
const tableObj = this.resolvedTableObject(table);
|
|
590
468
|
const columns = Object.keys(data[0]);
|
|
591
469
|
const params = [];
|
|
592
470
|
const valuesClauses = [];
|
|
@@ -605,9 +483,7 @@ var SqliteAdapter = class extends _nextlyhq_adapter_drizzle.DrizzleAdapter {
|
|
|
605
483
|
sql += ` RETURNING ${returning}`;
|
|
606
484
|
} else sql += " RETURNING *";
|
|
607
485
|
try {
|
|
608
|
-
|
|
609
|
-
const tableObj = this.getTableObject(table);
|
|
610
|
-
return rows.map((r) => this.mapRowFromRawSql(tableObj, r));
|
|
486
|
+
return db.prepare(sql).all(...params).map((r) => this.mapRowFromRawSql(tableObj, r));
|
|
611
487
|
} catch (error) {
|
|
612
488
|
throw this.handleQueryError(error, "insertMany", table);
|
|
613
489
|
}
|
|
@@ -694,7 +570,8 @@ var SqliteAdapter = class extends _nextlyhq_adapter_drizzle.DrizzleAdapter {
|
|
|
694
570
|
}
|
|
695
571
|
},
|
|
696
572
|
insert: async (table, data, options) => {
|
|
697
|
-
const
|
|
573
|
+
const tableObj = this.resolvedTableObject(table);
|
|
574
|
+
const mapped = this.mapKeysToSqlColumns(tableObj, data);
|
|
698
575
|
const columns = Object.keys(mapped);
|
|
699
576
|
const values = Object.values(mapped).map(sanitizeSqliteValue);
|
|
700
577
|
const placeholders = values.map(() => "?").join(", ");
|
|
@@ -702,7 +579,7 @@ var SqliteAdapter = class extends _nextlyhq_adapter_drizzle.DrizzleAdapter {
|
|
|
702
579
|
const ret = options?.returning;
|
|
703
580
|
const returningEmpty = Array.isArray(ret) && ret.length === 0;
|
|
704
581
|
if (!returningEmpty) {
|
|
705
|
-
const returning = !ret || ret === "*" ? "*" : this.mapColumnNamesToSql(
|
|
582
|
+
const returning = !ret || ret === "*" ? "*" : this.mapColumnNamesToSql(tableObj, ret).map((col) => this.escapeIdentifier(col)).join(", ");
|
|
706
583
|
sql += ` RETURNING ${returning}`;
|
|
707
584
|
}
|
|
708
585
|
const stmt = db.prepare(sql);
|
|
@@ -711,11 +588,11 @@ var SqliteAdapter = class extends _nextlyhq_adapter_drizzle.DrizzleAdapter {
|
|
|
711
588
|
return;
|
|
712
589
|
}
|
|
713
590
|
const rows = stmt.all(...values);
|
|
714
|
-
return this.mapRowFromRawSql(
|
|
591
|
+
return this.mapRowFromRawSql(tableObj, rows[0]);
|
|
715
592
|
},
|
|
716
593
|
insertMany: async (table, data, options) => {
|
|
717
594
|
if (data.length === 0) return [];
|
|
718
|
-
const tableObj = this.
|
|
595
|
+
const tableObj = this.resolvedTableObject(table);
|
|
719
596
|
const mappedRecords = data.map((r) => this.mapKeysToSqlColumns(tableObj, r));
|
|
720
597
|
const columns = Object.keys(mappedRecords[0]);
|
|
721
598
|
const allValues = [];
|
|
@@ -732,7 +609,7 @@ var SqliteAdapter = class extends _nextlyhq_adapter_drizzle.DrizzleAdapter {
|
|
|
732
609
|
const ret = options?.returning;
|
|
733
610
|
const returningEmpty = Array.isArray(ret) && ret.length === 0;
|
|
734
611
|
if (!returningEmpty) {
|
|
735
|
-
const returning = !ret || ret === "*" ? "*" : this.mapColumnNamesToSql(
|
|
612
|
+
const returning = !ret || ret === "*" ? "*" : this.mapColumnNamesToSql(tableObj, ret).map((col) => this.escapeIdentifier(col)).join(", ");
|
|
736
613
|
sql += ` RETURNING ${returning}`;
|
|
737
614
|
}
|
|
738
615
|
const stmt = db.prepare(sql);
|
|
@@ -839,44 +716,6 @@ function isSqliteAdapter(value) {
|
|
|
839
716
|
return value instanceof SqliteAdapter;
|
|
840
717
|
}
|
|
841
718
|
/**
|
|
842
|
-
* Open the scope of a savepoint inside `parent`, or of an outermost
|
|
843
|
-
* transaction when there is none, and record it among the connection's open
|
|
844
|
-
* scopes.
|
|
845
|
-
*/
|
|
846
|
-
function openScope(parent) {
|
|
847
|
-
const scope = {
|
|
848
|
-
active: true,
|
|
849
|
-
depth: parent ? parent.depth + 1 : 0,
|
|
850
|
-
parent,
|
|
851
|
-
rolledBack: false,
|
|
852
|
-
writesAfterClosing: 0,
|
|
853
|
-
finished: false,
|
|
854
|
-
held: [],
|
|
855
|
-
queue: Promise.resolve(),
|
|
856
|
-
open: parent ? parent.open : []
|
|
857
|
-
};
|
|
858
|
-
scope.open.push(scope);
|
|
859
|
-
return scope;
|
|
860
|
-
}
|
|
861
|
-
/** The outermost transaction `scope` runs inside; itself for that one. */
|
|
862
|
-
function outermost(scope) {
|
|
863
|
-
let at = scope;
|
|
864
|
-
while (at.parent) at = at.parent;
|
|
865
|
-
return at;
|
|
866
|
-
}
|
|
867
|
-
/**
|
|
868
|
-
* Whether an effect registered from `scope` describes a write that was
|
|
869
|
-
* undone: `scope`, or a scope it runs inside, rolled back, and no
|
|
870
|
-
* transaction had run from its context since it closed when the effect was
|
|
871
|
-
* registered (`writesBefore`). An effect registered before such a write
|
|
872
|
-
* still describes the undone one.
|
|
873
|
-
*/
|
|
874
|
-
function undone(scope, writesBefore) {
|
|
875
|
-
if (writesBefore > 0) return false;
|
|
876
|
-
for (let at = scope; at; at = at.parent) if (at.rolledBack) return true;
|
|
877
|
-
return false;
|
|
878
|
-
}
|
|
879
|
-
/**
|
|
880
719
|
* Settles once `turn` does, or rejects with the pool-wait timeout error once
|
|
881
720
|
* `boundMs` passes first. A bound of 0 waits without limit, as pg-pool reads a
|
|
882
721
|
* `connectionTimeoutMillis` of 0.
|
|
@@ -892,23 +731,6 @@ function waitForTurn(turn, boundMs) {
|
|
|
892
731
|
});
|
|
893
732
|
});
|
|
894
733
|
}
|
|
895
|
-
/** Chain `run` onto a scope's queue, keeping the queue itself unrejected. */
|
|
896
|
-
function enqueueIn(scope, run) {
|
|
897
|
-
const next = scope.queue.then(run, run);
|
|
898
|
-
scope.queue = next.catch(() => void 0);
|
|
899
|
-
return next;
|
|
900
|
-
}
|
|
901
|
-
/**
|
|
902
|
-
* Close a scope to new nested calls and wait for those already queued. A call
|
|
903
|
-
* arriving after this joins the innermost scope still open on the connection,
|
|
904
|
-
* or, when none is, goes to the instance queue behind the transaction.
|
|
905
|
-
*/
|
|
906
|
-
async function settleNested(scope) {
|
|
907
|
-
scope.active = false;
|
|
908
|
-
const index = scope.open.indexOf(scope);
|
|
909
|
-
if (index !== -1) scope.open.splice(index, 1);
|
|
910
|
-
await scope.queue;
|
|
911
|
-
}
|
|
912
734
|
exports.SqliteAdapter = SqliteAdapter;
|
|
913
735
|
exports.VERSION = VERSION;
|
|
914
736
|
exports.createSqliteAdapter = createSqliteAdapter;
|