@vibeorm/runtime 2.5.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +3 -1
- package/dist/adapter-kit/adapter-lifecycle.d.ts +79 -0
- package/dist/adapter-kit/deferred-control.d.ts +58 -0
- package/dist/adapter-kit/index.d.ts +10 -3
- package/dist/adapter-kit/index.js +317 -24
- package/dist/adapter-kit/index.js.map +10 -7
- package/dist/adapter-kit/nested-options.d.ts +16 -2
- package/dist/adapter-kit/row-changes.d.ts +15 -1
- package/dist/adapter-kit/savepoint-gate.d.ts +17 -3
- package/dist/adapter-kit/transaction-budget.d.ts +23 -13
- package/dist/adapter-kit/transaction-outcome.d.ts +167 -0
- package/dist/adapter.d.ts +103 -11
- package/dist/client.d.ts +7 -0
- package/dist/codecs.d.ts +35 -0
- package/dist/config.d.ts +15 -0
- package/dist/extensions.d.ts +10 -0
- package/dist/find-page.d.ts +9 -2
- package/dist/index.d.ts +8 -4
- package/dist/index.js +4088 -1296
- package/dist/index.js.map +40 -28
- package/dist/keyset-iterator.d.ts +12 -2
- package/dist/keyset.d.ts +72 -16
- package/dist/lateral-projection.d.ts +31 -1
- package/dist/model-meta.d.ts +12 -0
- package/dist/nested-fold.d.ts +98 -0
- package/dist/nested-update-data.d.ts +11 -0
- package/dist/nested-writes.d.ts +38 -1
- package/dist/query-builder.d.ts +78 -19
- package/dist/read-only.d.ts +5 -0
- package/dist/relation-key.d.ts +50 -0
- package/dist/relation-loader.d.ts +13 -1
- package/dist/relation-plan.d.ts +16 -0
- package/dist/strict-args.d.ts +1 -0
- package/dist/upsert-fold.d.ts +77 -0
- package/dist/write-scope.d.ts +9 -0
- package/package.json +7 -5
- package/dist/adapter-kit/index.d.ts.map +0 -1
- package/dist/adapter-kit/nested-options.d.ts.map +0 -1
- package/dist/adapter-kit/row-changes.d.ts.map +0 -1
- package/dist/adapter-kit/savepoint-gate.d.ts.map +0 -1
- package/dist/adapter-kit/savepoints.d.ts.map +0 -1
- package/dist/adapter-kit/session.d.ts.map +0 -1
- package/dist/adapter-kit/sqlite-session.d.ts.map +0 -1
- package/dist/adapter-kit/transaction-budget.d.ts.map +0 -1
- package/dist/adapter.d.ts.map +0 -1
- package/dist/advisory-key.d.ts.map +0 -1
- package/dist/advisory-lock.d.ts.map +0 -1
- package/dist/bulk-upsert.d.ts.map +0 -1
- package/dist/client-types.d.ts.map +0 -1
- package/dist/client.d.ts.map +0 -1
- package/dist/codecs.d.ts.map +0 -1
- package/dist/computed.d.ts.map +0 -1
- package/dist/database-module.d.ts.map +0 -1
- package/dist/db-now.d.ts.map +0 -1
- package/dist/diagnostics/index.d.ts.map +0 -1
- package/dist/diagnostics/insight.d.ts.map +0 -1
- package/dist/diagnostics/plan.d.ts.map +0 -1
- package/dist/diagnostics/preview.d.ts.map +0 -1
- package/dist/diagnostics/statement-diagnostics.d.ts.map +0 -1
- package/dist/diagnostics/types.d.ts.map +0 -1
- package/dist/diagnostics/workload.d.ts.map +0 -1
- package/dist/extensions.d.ts.map +0 -1
- package/dist/find-page.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/keyset-iterator.d.ts.map +0 -1
- package/dist/keyset-projection.d.ts.map +0 -1
- package/dist/keyset.d.ts.map +0 -1
- package/dist/lateral-projection.d.ts.map +0 -1
- package/dist/model-meta.d.ts.map +0 -1
- package/dist/module-context.d.ts.map +0 -1
- package/dist/nested-writes.d.ts.map +0 -1
- package/dist/policy-operation.d.ts.map +0 -1
- package/dist/policy.d.ts.map +0 -1
- package/dist/query-builder.d.ts.map +0 -1
- package/dist/read-only.d.ts.map +0 -1
- package/dist/relation-key.d.ts.map +0 -1
- package/dist/relation-loader.d.ts.map +0 -1
- package/dist/relation-plan.d.ts.map +0 -1
- package/dist/render-cache.d.ts.map +0 -1
- package/dist/rls-context.d.ts.map +0 -1
- package/dist/rls-readiness.d.ts.map +0 -1
- package/dist/scoped.d.ts.map +0 -1
- package/dist/sql-access.d.ts.map +0 -1
- package/dist/sql.d.ts.map +0 -1
- package/dist/strict-args.d.ts.map +0 -1
- package/dist/telemetry/collector.d.ts.map +0 -1
- package/dist/telemetry/config.d.ts.map +0 -1
- package/dist/telemetry/fingerprint.d.ts.map +0 -1
- package/dist/telemetry/index.d.ts.map +0 -1
- package/dist/telemetry/recorder.d.ts.map +0 -1
- package/dist/telemetry/statement.d.ts.map +0 -1
- package/dist/telemetry/types.d.ts.map +0 -1
- package/dist/transaction-row-changes.d.ts.map +0 -1
- package/dist/validators.d.ts.map +0 -1
- package/dist/views.d.ts.map +0 -1
- package/dist/write-scope.d.ts.map +0 -1
|
@@ -62,10 +62,14 @@ async function runNestedSavepoint(params) {
|
|
|
62
62
|
await drainDescendants({ node });
|
|
63
63
|
assertNotPoisoned({ state: scope.state });
|
|
64
64
|
if (execute !== undefined) {
|
|
65
|
+
const cleanup = params.cleanup ?? execute;
|
|
66
|
+
let cleanupStage = "rollback";
|
|
65
67
|
try {
|
|
66
|
-
await
|
|
68
|
+
await cleanup(`ROLLBACK TO SAVEPOINT ${node.name}`);
|
|
69
|
+
cleanupStage = "release";
|
|
70
|
+
await cleanup(`RELEASE SAVEPOINT ${node.name}`);
|
|
67
71
|
} catch (rollbackFailure) {
|
|
68
|
-
const poisoned = savepointRollbackFailedError({ cause: error, rollbackFailure });
|
|
72
|
+
const poisoned = savepointRollbackFailedError({ cause: error, rollbackFailure, cleanupStage });
|
|
69
73
|
scope.state.poisoned = poisoned;
|
|
70
74
|
throw poisoned;
|
|
71
75
|
}
|
|
@@ -85,14 +89,16 @@ function markSavepointOpened(params) {
|
|
|
85
89
|
}
|
|
86
90
|
function savepointRollbackFailedError(params) {
|
|
87
91
|
const { cause, rollbackFailure } = params;
|
|
92
|
+
const releaseFailed = params.cleanupStage === "release";
|
|
88
93
|
const rollbackErrorCode = rollbackFailure instanceof VibeError ? rollbackFailure.code : undefined;
|
|
89
94
|
return new VibeError({
|
|
90
95
|
code: "VIBE_TRANSACTION",
|
|
91
|
-
message: "a nested transaction failed and
|
|
96
|
+
message: (releaseFailed ? "a nested transaction failed and RELEASE SAVEPOINT after its confirmed rollback failed too. " : "a nested transaction failed and ROLLBACK TO SAVEPOINT failed too. ") + "The savepoint stack no longer describes this connection, so the commit state of the whole transaction " + "is UNKNOWN and no further statement is accepted on any of its handles. The top-level transaction is " + "being rolled back; nothing is retried automatically.",
|
|
92
97
|
meta: {
|
|
93
98
|
reason: "savepoint-rollback-failed",
|
|
94
99
|
outcome: "unknown",
|
|
95
|
-
rollbackFailed:
|
|
100
|
+
rollbackFailed: !releaseFailed,
|
|
101
|
+
...releaseFailed ? { cleanupStage: "release" } : {},
|
|
96
102
|
...rollbackErrorCode === undefined ? {} : { rollbackErrorCode }
|
|
97
103
|
},
|
|
98
104
|
cause
|
|
@@ -103,7 +109,7 @@ function isSavepointRollbackFailedError(error) {
|
|
|
103
109
|
return reason === "savepoint-rollback-failed";
|
|
104
110
|
}
|
|
105
111
|
function transactionAbortedError(params) {
|
|
106
|
-
const cause = params.cause;
|
|
112
|
+
const cause = mappedCauseOf({ error: params.cause }) ?? params.cause;
|
|
107
113
|
const causeCode = cause instanceof VibeError ? cause.code : undefined;
|
|
108
114
|
const sqlstate = cause instanceof VibeError && typeof cause.meta.sqlstate === "string" ? cause.meta.sqlstate : undefined;
|
|
109
115
|
return new VibeError({
|
|
@@ -111,13 +117,23 @@ function transactionAbortedError(params) {
|
|
|
111
117
|
message: "the transaction is aborted: a statement inside it failed and PostgreSQL discards every later statement and the COMMIT itself " + "(the server answers COMMIT with ROLLBACK and no error). Nothing from this transaction was committed. " + "Let the failure propagate out of the callback, or run the statement that may fail inside a nested transaction so its savepoint is rolled back.",
|
|
112
118
|
meta: {
|
|
113
119
|
reason: "aborted",
|
|
114
|
-
outcome: "
|
|
120
|
+
outcome: "not-committed",
|
|
115
121
|
...causeCode === undefined ? {} : { causeCode },
|
|
116
122
|
...sqlstate === undefined ? {} : { sqlstate }
|
|
117
123
|
},
|
|
118
124
|
...cause === undefined ? {} : { cause }
|
|
119
125
|
});
|
|
120
126
|
}
|
|
127
|
+
var MAPPED_CAUSE = Symbol.for("vibeorm.adapter-kit.mapped-cause");
|
|
128
|
+
function recordMappedCause(params) {
|
|
129
|
+
Object.defineProperty(params.raw, MAPPED_CAUSE, { value: params.mapped, enumerable: false, configurable: true, writable: false });
|
|
130
|
+
}
|
|
131
|
+
function mappedCauseOf(params) {
|
|
132
|
+
if (!(params.error instanceof Error))
|
|
133
|
+
return;
|
|
134
|
+
const mapped = params.error[MAPPED_CAUSE];
|
|
135
|
+
return mapped instanceof VibeError ? mapped : undefined;
|
|
136
|
+
}
|
|
121
137
|
function isTransactionAbortedError(error) {
|
|
122
138
|
const reason = error?.meta?.reason;
|
|
123
139
|
return reason === "aborted";
|
|
@@ -154,16 +170,50 @@ async function waitForTurn(params) {
|
|
|
154
170
|
await open.settled;
|
|
155
171
|
}
|
|
156
172
|
}
|
|
173
|
+
var ADMISSIONS = new WeakMap;
|
|
157
174
|
async function acquire(params) {
|
|
158
175
|
const { scope } = params;
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
176
|
+
assertNotPoisoned({ state: scope.state });
|
|
177
|
+
assertNotAborted({ state: scope.state });
|
|
178
|
+
const open = scope.state.open;
|
|
179
|
+
if (mayProceed({ scope, open }))
|
|
180
|
+
return pushNode({ scope, parent: open });
|
|
181
|
+
let blocker = open;
|
|
182
|
+
while (blocker.parent !== null && !mayProceed({ scope, open: blocker.parent })) {
|
|
183
|
+
blocker = blocker.parent;
|
|
184
|
+
}
|
|
185
|
+
return new Promise((resolve, reject) => {
|
|
186
|
+
const waiter = { scope, resolve, reject, next: null };
|
|
187
|
+
const queue = ADMISSIONS.get(blocker);
|
|
188
|
+
if (queue === undefined)
|
|
189
|
+
ADMISSIONS.set(blocker, { head: waiter, tail: waiter });
|
|
190
|
+
else {
|
|
191
|
+
queue.tail.next = waiter;
|
|
192
|
+
queue.tail = waiter;
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
function handOffAdmissions(params) {
|
|
197
|
+
const queue = ADMISSIONS.get(params.node);
|
|
198
|
+
if (queue === undefined)
|
|
199
|
+
return;
|
|
200
|
+
ADMISSIONS.delete(params.node);
|
|
201
|
+
const state = params.node.scope.state;
|
|
202
|
+
const refusal = state.poisoned ?? (state.aborted === null ? null : transactionAbortedError({ cause: state.aborted.cause }));
|
|
203
|
+
if (refusal !== null) {
|
|
204
|
+
let waiter = queue.head;
|
|
205
|
+
while (waiter !== null) {
|
|
206
|
+
waiter.reject(refusal);
|
|
207
|
+
waiter = waiter.next;
|
|
208
|
+
}
|
|
209
|
+
return;
|
|
166
210
|
}
|
|
211
|
+
const first = queue.head;
|
|
212
|
+
const successor = pushNode({ scope: first.scope, parent: state.open });
|
|
213
|
+
if (first.next !== null)
|
|
214
|
+
ADMISSIONS.set(successor, { head: first.next, tail: queue.tail });
|
|
215
|
+
first.next = null;
|
|
216
|
+
first.resolve(successor);
|
|
167
217
|
}
|
|
168
218
|
function pushNode(params) {
|
|
169
219
|
const { scope, parent } = params;
|
|
@@ -191,6 +241,7 @@ function closeNode(params) {
|
|
|
191
241
|
if (state.open === node)
|
|
192
242
|
state.open = node.parent;
|
|
193
243
|
node.settle();
|
|
244
|
+
handOffAdmissions({ node });
|
|
194
245
|
}
|
|
195
246
|
async function drainDescendants(params) {
|
|
196
247
|
const state = params.node.scope.state;
|
|
@@ -214,6 +265,8 @@ function refuseNestedTransactionOptions(params) {
|
|
|
214
265
|
passed.push("timeout");
|
|
215
266
|
if (options.deadline !== undefined)
|
|
216
267
|
passed.push("deadline");
|
|
268
|
+
if (options.accessMode !== undefined)
|
|
269
|
+
passed.push("accessMode");
|
|
217
270
|
if (passed.length === 0)
|
|
218
271
|
return;
|
|
219
272
|
const meta = { provider, nested: true };
|
|
@@ -223,12 +276,76 @@ function refuseNestedTransactionOptions(params) {
|
|
|
223
276
|
meta.timeout = options.timeout;
|
|
224
277
|
if (options.deadline !== undefined)
|
|
225
278
|
meta.deadline = options.deadline;
|
|
279
|
+
if (options.accessMode !== undefined)
|
|
280
|
+
meta.accessMode = options.accessMode;
|
|
226
281
|
throw new VibeError2({
|
|
227
282
|
code: "VIBE_VALIDATION",
|
|
228
283
|
message: `nested transactions run as savepoints and cannot honor ${passed.join(" or ")} \u2014 a savepoint cannot change the isolation level of the transaction it joins, a nested timeout is not enforceable, and a nested deadline would need its own session setting on a connection it does not own (it inherits the top-level one instead); pass options on the top-level $transaction`,
|
|
229
284
|
meta
|
|
230
285
|
});
|
|
231
286
|
}
|
|
287
|
+
function readOnlyRequested(params) {
|
|
288
|
+
const accessMode = params.options?.accessMode;
|
|
289
|
+
if (accessMode === undefined)
|
|
290
|
+
return false;
|
|
291
|
+
if (accessMode === "readOnly")
|
|
292
|
+
return true;
|
|
293
|
+
throw new VibeError2({
|
|
294
|
+
code: "VIBE_VALIDATION",
|
|
295
|
+
message: `transaction accessMode must be "readOnly" or omitted, received ${JSON.stringify(accessMode) ?? String(accessMode)}`,
|
|
296
|
+
meta: { provider: params.provider, accessMode }
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
// packages/runtime/src/adapter-kit/deferred-control.ts
|
|
300
|
+
var SAVEPOINT_TEXT = /^SAVEPOINT (\S+)$/;
|
|
301
|
+
var RELEASE_TEXT = /^RELEASE SAVEPOINT (\S+)$/;
|
|
302
|
+
var ROLLBACK_TO_TEXT = /^ROLLBACK TO SAVEPOINT (\S+)$/;
|
|
303
|
+
function createDeferredControl(params) {
|
|
304
|
+
let pending = [...params.opening];
|
|
305
|
+
let opened = params.opening.length === 0;
|
|
306
|
+
const elided = new Set;
|
|
307
|
+
const dropFrom = (name) => {
|
|
308
|
+
const index = pending.indexOf(`SAVEPOINT ${name}`);
|
|
309
|
+
if (index === -1)
|
|
310
|
+
return false;
|
|
311
|
+
pending = pending.slice(0, index);
|
|
312
|
+
return true;
|
|
313
|
+
};
|
|
314
|
+
return {
|
|
315
|
+
opened: () => opened,
|
|
316
|
+
hasPending: () => pending.length > 0,
|
|
317
|
+
take: () => {
|
|
318
|
+
const taken = pending;
|
|
319
|
+
pending = [];
|
|
320
|
+
if (taken.length > 0)
|
|
321
|
+
opened = true;
|
|
322
|
+
return taken;
|
|
323
|
+
},
|
|
324
|
+
routeSavepoint: ({ text }) => {
|
|
325
|
+
const savepoint = SAVEPOINT_TEXT.exec(text);
|
|
326
|
+
if (savepoint !== null) {
|
|
327
|
+
pending.push(text);
|
|
328
|
+
return "deferred";
|
|
329
|
+
}
|
|
330
|
+
const release = RELEASE_TEXT.exec(text);
|
|
331
|
+
if (release !== null) {
|
|
332
|
+
const name = release[1];
|
|
333
|
+
if (elided.delete(name))
|
|
334
|
+
return "elided";
|
|
335
|
+
return dropFrom(name) ? "elided" : "send";
|
|
336
|
+
}
|
|
337
|
+
const rollbackTo = ROLLBACK_TO_TEXT.exec(text);
|
|
338
|
+
if (rollbackTo !== null) {
|
|
339
|
+
const name = rollbackTo[1];
|
|
340
|
+
if (!dropFrom(name))
|
|
341
|
+
return "send";
|
|
342
|
+
elided.add(name);
|
|
343
|
+
return "elided";
|
|
344
|
+
}
|
|
345
|
+
return "send";
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
}
|
|
232
349
|
// packages/runtime/src/adapter-kit/transaction-budget.ts
|
|
233
350
|
import { VibeError as VibeError3 } from "@vibeorm/schema";
|
|
234
351
|
var DEFAULT_DEADLINE_CLOCK = () => Date.now();
|
|
@@ -313,7 +430,7 @@ function engineStatementBudgetMs(params) {
|
|
|
313
430
|
}
|
|
314
431
|
function transactionDeadlineError(params) {
|
|
315
432
|
const { provider, stage, totalMs, overdueMs } = params;
|
|
316
|
-
const what = stage === "commit" ? "
|
|
433
|
+
const what = stage === "commit" ? "COMMIT was never sent, so the transaction did not commit" : "the statement was never sent, and the transaction will not commit";
|
|
317
434
|
return new VibeError3({
|
|
318
435
|
code: "VIBE_TRANSACTION",
|
|
319
436
|
message: `transaction deadline of ${totalMs} ms expired ${Math.max(0, Math.round(overdueMs))} ms ago \u2014 ${what}. ` + "Nothing is retried automatically: work the callback did outside the database may already have happened.",
|
|
@@ -332,13 +449,13 @@ function transactionOutcomeUnknownError(params) {
|
|
|
332
449
|
const { provider, totalMs, cause } = params;
|
|
333
450
|
return new VibeError3({
|
|
334
451
|
code: "VIBE_TRANSACTION",
|
|
335
|
-
message: `transaction deadline of ${totalMs} ms expired and the
|
|
452
|
+
message: `transaction deadline of ${totalMs} ms expired while COMMIT was in flight and the client stopped waiting for its answer \u2014 ` + "the commit state of this transaction is UNKNOWN. It is not retried automatically; inspect the data " + "before deciding.",
|
|
336
453
|
meta: {
|
|
337
454
|
provider,
|
|
338
455
|
reason: "transaction-outcome-unknown",
|
|
339
456
|
outcome: "unknown",
|
|
340
|
-
|
|
341
|
-
|
|
457
|
+
stage: "commit",
|
|
458
|
+
totalMs
|
|
342
459
|
},
|
|
343
460
|
cause
|
|
344
461
|
});
|
|
@@ -347,15 +464,87 @@ function isTransactionDeadlineError(error) {
|
|
|
347
464
|
const reason = error?.meta?.reason;
|
|
348
465
|
return reason === "transaction-deadline";
|
|
349
466
|
}
|
|
467
|
+
// packages/runtime/src/adapter-kit/transaction-outcome.ts
|
|
468
|
+
var REPORT_VERSION = 1;
|
|
469
|
+
var REGISTRY_KEY = Symbol.for("vibeorm.adapter-kit.transaction-outcome");
|
|
470
|
+
function sharedRegistry() {
|
|
471
|
+
const existing = globalThis[REGISTRY_KEY];
|
|
472
|
+
if (existing instanceof WeakMap)
|
|
473
|
+
return existing;
|
|
474
|
+
const created = new WeakMap;
|
|
475
|
+
if (!Object.isExtensible(globalThis))
|
|
476
|
+
return created;
|
|
477
|
+
Object.defineProperty(globalThis, REGISTRY_KEY, { value: created, enumerable: false, configurable: false, writable: false });
|
|
478
|
+
return created;
|
|
479
|
+
}
|
|
480
|
+
var REPORTS = sharedRegistry();
|
|
481
|
+
function isReportable(value) {
|
|
482
|
+
return typeof value === "object" && value !== null || typeof value === "function";
|
|
483
|
+
}
|
|
484
|
+
function recordTransactionOutcome(params) {
|
|
485
|
+
const { error, report } = params;
|
|
486
|
+
if (!isReportable(error))
|
|
487
|
+
return;
|
|
488
|
+
REPORTS.set(error, Object.freeze({ version: REPORT_VERSION, report: Object.freeze({ ...report }) }));
|
|
489
|
+
}
|
|
490
|
+
function transactionOutcomeOf(params) {
|
|
491
|
+
const { error } = params;
|
|
492
|
+
if (!isReportable(error))
|
|
493
|
+
return;
|
|
494
|
+
const stored = REPORTS.get(error);
|
|
495
|
+
return stored?.version === REPORT_VERSION ? stored.report : undefined;
|
|
496
|
+
}
|
|
497
|
+
function failedCommitOutcome(params) {
|
|
498
|
+
const { commit, stateLost } = params;
|
|
499
|
+
if (commit === "sent" || commit === "unanswered")
|
|
500
|
+
return "unknown";
|
|
501
|
+
return stateLost ? "unknown" : "not-committed";
|
|
502
|
+
}
|
|
503
|
+
function closeFailedTransactionBudget(params) {
|
|
504
|
+
const { error, budget, scope, commit } = params;
|
|
505
|
+
const stateLost = isSavepointRollbackFailedError(error) || isSavepointRollbackFailedError(scope.state.poisoned);
|
|
506
|
+
const outcome = failedCommitOutcome({ commit, stateLost });
|
|
507
|
+
budget.close({ outcome });
|
|
508
|
+
return outcome;
|
|
509
|
+
}
|
|
510
|
+
function settleFailedTransaction(params) {
|
|
511
|
+
const { error, provider, budget, scope, commit, rollback, connection } = params;
|
|
512
|
+
const outcome = closeFailedTransactionBudget({ error, budget, scope, commit });
|
|
513
|
+
const abandoned = commit === "unanswered" && budget.totalMs !== null && isTransactionDeadlineError(error);
|
|
514
|
+
const thrown = abandoned ? transactionOutcomeUnknownError({ provider, totalMs: budget.totalMs, cause: error }) : error;
|
|
515
|
+
recordTransactionOutcome({
|
|
516
|
+
error: thrown,
|
|
517
|
+
report: { commit: outcome, commitSent: commit !== "not-sent", rollback, connection }
|
|
518
|
+
});
|
|
519
|
+
return thrown;
|
|
520
|
+
}
|
|
350
521
|
// packages/runtime/src/adapter-kit/row-changes.ts
|
|
351
522
|
function statementRowChanges(params) {
|
|
352
|
-
const { effect
|
|
523
|
+
const { effect } = params;
|
|
353
524
|
if (effect === "read")
|
|
354
525
|
return 0;
|
|
355
|
-
if (effect
|
|
526
|
+
if (effect === "writeTally")
|
|
527
|
+
return tallyOf({ rows: params.resultRows });
|
|
528
|
+
const count = effect === "write" ? params.count : effect === "writeRows" ? params.rows : undefined;
|
|
529
|
+
if (effect !== "write" && effect !== "writeRows")
|
|
356
530
|
return "unknown";
|
|
357
531
|
return typeof count === "number" && Number.isSafeInteger(count) && count >= 0 ? count : "unknown";
|
|
358
532
|
}
|
|
533
|
+
var ROW_CHANGES_COLUMN = "__vibe_row_changes";
|
|
534
|
+
function tallyOf(params) {
|
|
535
|
+
const { rows } = params;
|
|
536
|
+
if (rows === undefined || rows.length === 0)
|
|
537
|
+
return "unknown";
|
|
538
|
+
let total = 0;
|
|
539
|
+
for (const row of rows) {
|
|
540
|
+
const value = row[ROW_CHANGES_COLUMN];
|
|
541
|
+
const count = typeof value === "number" ? value : typeof value === "bigint" ? Number(value) : typeof value === "string" && /^\d+$/.test(value) ? Number(value) : Number.NaN;
|
|
542
|
+
if (!Number.isSafeInteger(count) || count < 0)
|
|
543
|
+
return "unknown";
|
|
544
|
+
total += count;
|
|
545
|
+
}
|
|
546
|
+
return Number.isSafeInteger(total) ? total : "unknown";
|
|
547
|
+
}
|
|
359
548
|
function observeRowChanges(params) {
|
|
360
549
|
const state = params.scope.state;
|
|
361
550
|
if (state.rowChanges === "unknown")
|
|
@@ -369,7 +558,7 @@ function observeRowChanges(params) {
|
|
|
369
558
|
}
|
|
370
559
|
function dispatchSynchronousRowChanges(params) {
|
|
371
560
|
const { scope } = params;
|
|
372
|
-
if (scope === undefined)
|
|
561
|
+
if (scope === undefined || scope.state.rowChanges === "unknown")
|
|
373
562
|
return params.run();
|
|
374
563
|
const before = scope.state.rowChanges;
|
|
375
564
|
if (params.effect !== "read")
|
|
@@ -448,12 +637,105 @@ function withCleanupCause(params) {
|
|
|
448
637
|
}
|
|
449
638
|
return cause;
|
|
450
639
|
}
|
|
451
|
-
// packages/runtime/src/adapter-kit/
|
|
640
|
+
// packages/runtime/src/adapter-kit/adapter-lifecycle.ts
|
|
641
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
452
642
|
import { VibeError as VibeError5 } from "@vibeorm/schema";
|
|
643
|
+
function adapterClosedError(params) {
|
|
644
|
+
const { driver, state } = params;
|
|
645
|
+
return new VibeError5({
|
|
646
|
+
code: "VIBE_ADAPTER_CLOSED",
|
|
647
|
+
message: `This ${driver} adapter was disconnected${state === "closing" ? " and is closing" : ""}; it accepts no new work. Create a new adapter to connect again.`,
|
|
648
|
+
meta: { driver, state }
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
function disconnectInActiveCallbackError(params) {
|
|
652
|
+
return new VibeError5({
|
|
653
|
+
code: "VIBE_TRANSACTION",
|
|
654
|
+
message: "disconnect() was called from inside this adapter's own running transaction or session callback; it would wait for that callback to finish. Return from the callback first, then disconnect.",
|
|
655
|
+
meta: { reason: "disconnect-in-active-callback", driver: params.driver }
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
function transactionLifecycleRefusal(params) {
|
|
659
|
+
const { method } = params;
|
|
660
|
+
return new VibeError5({
|
|
661
|
+
code: "VIBE_VALIDATION",
|
|
662
|
+
message: `${method}() is not available on a transaction client \u2014 the connection is owned by the open transaction; call it on the client that started the transaction`,
|
|
663
|
+
meta: { method, inTransaction: true }
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
function createAdapterLifecycleGate(params) {
|
|
667
|
+
const { driver, cleanup, isConnectionReentrant } = params;
|
|
668
|
+
const callbacks = new AsyncLocalStorage2;
|
|
669
|
+
let state = "open";
|
|
670
|
+
let active = 0;
|
|
671
|
+
let drained = null;
|
|
672
|
+
let completion = null;
|
|
673
|
+
const settleOne = () => {
|
|
674
|
+
active -= 1;
|
|
675
|
+
if (active === 0 && drained !== null) {
|
|
676
|
+
const resolve = drained;
|
|
677
|
+
drained = null;
|
|
678
|
+
resolve();
|
|
679
|
+
}
|
|
680
|
+
};
|
|
681
|
+
return {
|
|
682
|
+
admit(admitParams) {
|
|
683
|
+
if (state !== "open")
|
|
684
|
+
return Promise.reject(adapterClosedError({ driver, state }));
|
|
685
|
+
active += 1;
|
|
686
|
+
const result = new Promise((resolve) => {
|
|
687
|
+
resolve(admitParams.run());
|
|
688
|
+
});
|
|
689
|
+
result.then(settleOne, settleOne);
|
|
690
|
+
return result;
|
|
691
|
+
},
|
|
692
|
+
inCallback(callbackParams) {
|
|
693
|
+
const token = { active: true };
|
|
694
|
+
return callbacks.run(token, () => new Promise((resolve) => {
|
|
695
|
+
resolve(callbackParams.run());
|
|
696
|
+
})).finally(() => {
|
|
697
|
+
token.active = false;
|
|
698
|
+
});
|
|
699
|
+
},
|
|
700
|
+
disconnect() {
|
|
701
|
+
if (callbacks.getStore()?.active === true || isConnectionReentrant?.() === true) {
|
|
702
|
+
return Promise.reject(disconnectInActiveCallbackError({ driver }));
|
|
703
|
+
}
|
|
704
|
+
if (completion !== null)
|
|
705
|
+
return completion;
|
|
706
|
+
state = "closing";
|
|
707
|
+
const drain = active === 0 ? Promise.resolve() : new Promise((resolve) => {
|
|
708
|
+
drained = resolve;
|
|
709
|
+
});
|
|
710
|
+
completion = drain.then(() => cleanup()).then(() => {
|
|
711
|
+
state = "closed";
|
|
712
|
+
}, (error) => {
|
|
713
|
+
state = "closed";
|
|
714
|
+
throw error;
|
|
715
|
+
});
|
|
716
|
+
return completion;
|
|
717
|
+
}
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
function runShutdownCleanup(params) {
|
|
721
|
+
let failure;
|
|
722
|
+
let chain = Promise.resolve();
|
|
723
|
+
for (const step of params.steps) {
|
|
724
|
+
chain = chain.then(step).then(undefined, (error) => {
|
|
725
|
+
failure = failure === undefined ? { error } : { error: withCleanupCause({ cause: failure.error, cleanupCause: error }) };
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
return chain.then(() => {
|
|
729
|
+
if (failure !== undefined)
|
|
730
|
+
throw failure.error;
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
// packages/runtime/src/adapter-kit/sqlite-session.ts
|
|
734
|
+
import { VibeError as VibeError6 } from "@vibeorm/schema";
|
|
453
735
|
import { SQLITE_SESSION_SQL } from "@vibeorm/sql";
|
|
454
736
|
async function runSqliteSession(params) {
|
|
455
737
|
if (params.inTransaction())
|
|
456
|
-
throw new
|
|
738
|
+
throw new VibeError6({
|
|
457
739
|
code: "VIBE_TRANSACTION",
|
|
458
740
|
message: "A migration session cannot borrow a SQLite connection with an open transaction.",
|
|
459
741
|
meta: { reason: "session-in-transaction" }
|
|
@@ -461,7 +743,7 @@ async function runSqliteSession(params) {
|
|
|
461
743
|
const rows = await params.execute({ text: SQLITE_SESSION_SQL.lockingMode, values: [] });
|
|
462
744
|
const mode = rows[0]?.locking_mode;
|
|
463
745
|
if (mode !== "normal" && mode !== "exclusive")
|
|
464
|
-
throw new
|
|
746
|
+
throw new VibeError6({
|
|
465
747
|
code: "VIBE_ADAPTER",
|
|
466
748
|
message: "SQLite did not report its locking mode; no migration was started.",
|
|
467
749
|
meta: { reason: "session-lock-mode" }
|
|
@@ -500,11 +782,16 @@ async function runSqliteSession(params) {
|
|
|
500
782
|
}
|
|
501
783
|
export {
|
|
502
784
|
DEFAULT_DEADLINE_CLOCK,
|
|
785
|
+
ROW_CHANGES_COLUMN,
|
|
503
786
|
abortTransactionOnServerFailure,
|
|
787
|
+
closeFailedTransactionBudget,
|
|
788
|
+
createAdapterLifecycleGate,
|
|
789
|
+
createDeferredControl,
|
|
504
790
|
createSavepointCounter,
|
|
505
791
|
createSavepointScope,
|
|
506
792
|
dispatchSynchronousRowChanges,
|
|
507
793
|
engineStatementBudgetMs,
|
|
794
|
+
failedCommitOutcome,
|
|
508
795
|
isSavepointRollbackFailedError,
|
|
509
796
|
isTransactionAbortedError,
|
|
510
797
|
isTransactionDeadlineError,
|
|
@@ -512,21 +799,27 @@ export {
|
|
|
512
799
|
markTransactionAborted,
|
|
513
800
|
nextSavepointName,
|
|
514
801
|
observeRowChanges,
|
|
802
|
+
readOnlyRequested,
|
|
515
803
|
readRowChanges,
|
|
804
|
+
recordTransactionOutcome,
|
|
516
805
|
refuseNestedTransactionOptions,
|
|
517
806
|
runNestedSavepoint,
|
|
518
807
|
runPinnedSession,
|
|
519
808
|
runRootScope,
|
|
809
|
+
runShutdownCleanup,
|
|
520
810
|
runSqliteSession,
|
|
521
811
|
savepointRollbackFailedError,
|
|
522
812
|
scopeTurn,
|
|
813
|
+
settleFailedTransaction,
|
|
523
814
|
startTransactionBudget,
|
|
524
815
|
statementRowChanges,
|
|
525
816
|
transactionAbortedError,
|
|
526
817
|
transactionClosedError,
|
|
527
818
|
transactionDeadlineError,
|
|
819
|
+
transactionLifecycleRefusal,
|
|
820
|
+
transactionOutcomeOf,
|
|
528
821
|
transactionOutcomeUnknownError,
|
|
529
822
|
validateTransactionDeadline
|
|
530
823
|
};
|
|
531
824
|
|
|
532
|
-
//# debugId=
|
|
825
|
+
//# debugId=DA2DF3165F53603864756E2164756E21
|