@vibeorm/adapter-bun 1.3.0 → 2.0.0-alpha.10
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 +62 -49
- package/dist/connection-url.d.ts +37 -0
- package/dist/connection-url.d.ts.map +1 -0
- package/dist/errors.d.ts +38 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +909 -0
- package/dist/index.js.map +18 -0
- package/dist/params.d.ts +59 -0
- package/dist/params.d.ts.map +1 -0
- package/dist/savepoint-gate.d.ts +86 -0
- package/dist/savepoint-gate.d.ts.map +1 -0
- package/dist/savepoints.d.ts +22 -0
- package/dist/savepoints.d.ts.map +1 -0
- package/dist/template-cache.d.ts +76 -0
- package/dist/template-cache.d.ts.map +1 -0
- package/dist/transaction-budget.d.ts +144 -0
- package/dist/transaction-budget.d.ts.map +1 -0
- package/dist/transaction-sql.d.ts +62 -0
- package/dist/transaction-sql.d.ts.map +1 -0
- package/package.json +29 -19
- package/src/index.ts +0 -621
package/dist/index.js
ADDED
|
@@ -0,0 +1,909 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/adapter-bun/src/index.ts
|
|
3
|
+
var {SQL } = globalThis.Bun;
|
|
4
|
+
import { postgresDialect, renderDiagnostic } from "@vibeorm/sql";
|
|
5
|
+
|
|
6
|
+
// packages/adapter-bun/src/connection-url.ts
|
|
7
|
+
import { VibeError } from "@vibeorm/schema";
|
|
8
|
+
function buildStartupOptions(params) {
|
|
9
|
+
const { planCacheMode, statementTimeout } = params;
|
|
10
|
+
const parts = [];
|
|
11
|
+
if (planCacheMode !== "auto")
|
|
12
|
+
parts.push(`-c plan_cache_mode=${planCacheMode}`);
|
|
13
|
+
if (statementTimeout !== undefined) {
|
|
14
|
+
if (!Number.isInteger(statementTimeout) || statementTimeout < 0) {
|
|
15
|
+
throw new VibeError({
|
|
16
|
+
code: "VIBE_VALIDATION",
|
|
17
|
+
message: `statementTimeout must be a non-negative integer of milliseconds, received ${String(statementTimeout)}`,
|
|
18
|
+
meta: { statementTimeout }
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
parts.push(`-c statement_timeout=${statementTimeout}`);
|
|
22
|
+
}
|
|
23
|
+
return parts.length === 0 ? undefined : parts.join(" ");
|
|
24
|
+
}
|
|
25
|
+
function applyStartupOptions(params) {
|
|
26
|
+
const { url, startupOptions } = params;
|
|
27
|
+
const separator = url.includes("?") ? "&" : "?";
|
|
28
|
+
return `${url}${separator}options=${encodeURIComponent(startupOptions)}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// packages/adapter-bun/src/errors.ts
|
|
32
|
+
import { VibeError as VibeError2 } from "@vibeorm/schema";
|
|
33
|
+
var BUN_SQLSTATE_ERROR_CODES = Object.freeze({
|
|
34
|
+
"23505": "VIBE_UNIQUE_VIOLATION",
|
|
35
|
+
"23503": "VIBE_FK_VIOLATION",
|
|
36
|
+
"23502": "VIBE_VALIDATION",
|
|
37
|
+
"23514": "VIBE_VALIDATION",
|
|
38
|
+
"22P02": "VIBE_VALIDATION",
|
|
39
|
+
"42501": "VIBE_PERMISSION_DENIED",
|
|
40
|
+
"40001": "VIBE_TRANSACTION",
|
|
41
|
+
"40P01": "VIBE_TRANSACTION",
|
|
42
|
+
"57014": "VIBE_TRANSACTION"
|
|
43
|
+
});
|
|
44
|
+
var BUN_SQLSTATE_REASONS = Object.freeze({
|
|
45
|
+
"57014": "timeout"
|
|
46
|
+
});
|
|
47
|
+
var SQLSTATE_PATTERN = /^[0-9A-Z]{5}$/;
|
|
48
|
+
function readStringField(params) {
|
|
49
|
+
const value = params.source[params.key];
|
|
50
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
51
|
+
}
|
|
52
|
+
function bunErrorSqlstate(params) {
|
|
53
|
+
const { error } = params;
|
|
54
|
+
if (error === null || typeof error !== "object")
|
|
55
|
+
return;
|
|
56
|
+
const source = error;
|
|
57
|
+
for (const key of ["code", "errno"]) {
|
|
58
|
+
const value = readStringField({ source, key });
|
|
59
|
+
if (value !== undefined && SQLSTATE_PATTERN.test(value))
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
function mapBunDriverError(params) {
|
|
65
|
+
const { error } = params;
|
|
66
|
+
if (error instanceof VibeError2)
|
|
67
|
+
return error;
|
|
68
|
+
const source = error !== null && typeof error === "object" ? error : {};
|
|
69
|
+
const sqlstate = bunErrorSqlstate({ error });
|
|
70
|
+
const code = (sqlstate === undefined ? undefined : BUN_SQLSTATE_ERROR_CODES[sqlstate]) ?? "VIBE_ADAPTER";
|
|
71
|
+
const meta = {};
|
|
72
|
+
if (sqlstate !== undefined)
|
|
73
|
+
meta.sqlstate = sqlstate;
|
|
74
|
+
const constraint = readStringField({ source, key: "constraint" });
|
|
75
|
+
if (constraint !== undefined)
|
|
76
|
+
meta.constraint = constraint;
|
|
77
|
+
const table = readStringField({ source, key: "table" });
|
|
78
|
+
if (table !== undefined)
|
|
79
|
+
meta.table = table;
|
|
80
|
+
const column = readStringField({ source, key: "column" });
|
|
81
|
+
if (column !== undefined)
|
|
82
|
+
meta.column = column;
|
|
83
|
+
const reason = sqlstate === undefined ? undefined : BUN_SQLSTATE_REASONS[sqlstate];
|
|
84
|
+
if (reason !== undefined)
|
|
85
|
+
meta.reason = reason;
|
|
86
|
+
const driverCode = readStringField({ source, key: "code" });
|
|
87
|
+
if (driverCode !== undefined && driverCode !== sqlstate)
|
|
88
|
+
meta.driverCode = driverCode;
|
|
89
|
+
const message = readStringField({ source, key: "message" }) ?? (typeof error === "string" ? error : "unknown bun:sql driver error");
|
|
90
|
+
return new VibeError2({ code, message, meta, cause: error });
|
|
91
|
+
}
|
|
92
|
+
async function runMapped(fn) {
|
|
93
|
+
try {
|
|
94
|
+
return await fn();
|
|
95
|
+
} catch (error) {
|
|
96
|
+
throw mapBunDriverError({ error });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// packages/adapter-bun/src/params.ts
|
|
101
|
+
import { VibeError as VibeError3 } from "@vibeorm/schema";
|
|
102
|
+
function quoteElement(value) {
|
|
103
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
104
|
+
}
|
|
105
|
+
function toPgArrayLiteral(values) {
|
|
106
|
+
const elements = values.map((value) => {
|
|
107
|
+
if (value === null || value === undefined)
|
|
108
|
+
return "NULL";
|
|
109
|
+
if (typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") {
|
|
110
|
+
return String(value);
|
|
111
|
+
}
|
|
112
|
+
if (value instanceof Date)
|
|
113
|
+
return quoteElement(value.toISOString());
|
|
114
|
+
if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
|
|
115
|
+
throw new VibeError3({
|
|
116
|
+
code: "VIBE_VALIDATION",
|
|
117
|
+
message: "binary values are not supported inside a postgres array literal",
|
|
118
|
+
meta: { driver: "bun:sql" }
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
if (typeof value === "string")
|
|
122
|
+
return quoteElement(value);
|
|
123
|
+
if (typeof value === "object")
|
|
124
|
+
return quoteElement(JSON.stringify(value));
|
|
125
|
+
return quoteElement(String(value));
|
|
126
|
+
});
|
|
127
|
+
return `{${elements.join(",")}}`;
|
|
128
|
+
}
|
|
129
|
+
function serializeParams(params) {
|
|
130
|
+
return params.values.slice();
|
|
131
|
+
}
|
|
132
|
+
function serializeParamsRaw(params) {
|
|
133
|
+
return params.values.map((value) => Array.isArray(value) ? toPgArrayLiteral(value) : value);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// packages/adapter-bun/src/transaction-budget.ts
|
|
137
|
+
import { VibeError as VibeError4 } from "@vibeorm/schema";
|
|
138
|
+
var DEFAULT_DEADLINE_CLOCK = () => Date.now();
|
|
139
|
+
function validateTransactionDeadline(params) {
|
|
140
|
+
const { options, support, provider } = params;
|
|
141
|
+
const deadline = options?.deadline;
|
|
142
|
+
if (deadline === undefined)
|
|
143
|
+
return;
|
|
144
|
+
if (support === "unsupported") {
|
|
145
|
+
throw new VibeError4({
|
|
146
|
+
code: "VIBE_UNSUPPORTED_CAPABILITY",
|
|
147
|
+
message: `${provider} cannot enforce a transaction deadline \u2014 remove the \`deadline\` option`,
|
|
148
|
+
meta: { provider, feature: "transactionDeadline", supported: support }
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
if (!Number.isInteger(deadline.totalMs) || deadline.totalMs <= 0) {
|
|
152
|
+
throw new VibeError4({
|
|
153
|
+
code: "VIBE_VALIDATION",
|
|
154
|
+
message: `transaction deadline \`totalMs\` must be a positive integer of milliseconds, received ${String(deadline.totalMs)}`,
|
|
155
|
+
meta: { provider, feature: "transactionDeadline", totalMs: deadline.totalMs }
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
const requested = deadline.enforcement ?? "between-statements";
|
|
159
|
+
if (requested === "cancel-running-statements" && support !== "cancel-running-statements") {
|
|
160
|
+
throw new VibeError4({
|
|
161
|
+
code: "VIBE_UNSUPPORTED_CAPABILITY",
|
|
162
|
+
message: `${provider} cannot cancel a statement that is already running, so the requested ` + "`cancel-running-statements` deadline guarantee is refused rather than silently downgraded \u2014 " + 'ask for "between-statements" if a budget checked between statements is enough',
|
|
163
|
+
meta: { provider, feature: "transactionDeadline", requested, supported: support }
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function startTransactionBudget(params) {
|
|
168
|
+
const { options, provider } = params;
|
|
169
|
+
const clock = params.clock ?? DEFAULT_DEADLINE_CLOCK;
|
|
170
|
+
const deadline = options?.deadline;
|
|
171
|
+
const totalMs = deadline === undefined ? null : deadline.totalMs;
|
|
172
|
+
const enforcement = deadline === undefined ? null : deadline.enforcement ?? "between-statements";
|
|
173
|
+
const expiresAt = totalMs === null ? null : clock() + totalMs;
|
|
174
|
+
let outcome = null;
|
|
175
|
+
const budget = {
|
|
176
|
+
enforcement,
|
|
177
|
+
totalMs,
|
|
178
|
+
statementTimeoutMs: options?.timeout ?? null,
|
|
179
|
+
remainingMs() {
|
|
180
|
+
return expiresAt === null ? null : Math.max(0, expiresAt - clock());
|
|
181
|
+
},
|
|
182
|
+
expired() {
|
|
183
|
+
return expiresAt !== null && clock() >= expiresAt;
|
|
184
|
+
},
|
|
185
|
+
assertUsable(assertParams) {
|
|
186
|
+
if (outcome !== null) {
|
|
187
|
+
throw transactionClosedError({ provider, outcome, stage: assertParams.stage });
|
|
188
|
+
}
|
|
189
|
+
if (expiresAt !== null && clock() >= expiresAt) {
|
|
190
|
+
throw transactionDeadlineError({
|
|
191
|
+
provider,
|
|
192
|
+
stage: assertParams.stage,
|
|
193
|
+
totalMs,
|
|
194
|
+
overdueMs: clock() - expiresAt
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
close(closeParams) {
|
|
199
|
+
if (outcome === null)
|
|
200
|
+
outcome = closeParams.outcome;
|
|
201
|
+
},
|
|
202
|
+
get outcome() {
|
|
203
|
+
return outcome;
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
return budget;
|
|
207
|
+
}
|
|
208
|
+
function engineStatementBudgetMs(params) {
|
|
209
|
+
const { budget } = params;
|
|
210
|
+
if (budget.enforcement !== "cancel-running-statements")
|
|
211
|
+
return null;
|
|
212
|
+
const remaining = budget.remainingMs();
|
|
213
|
+
if (remaining === null)
|
|
214
|
+
return null;
|
|
215
|
+
const totalBound = Math.max(1, Math.ceil(remaining));
|
|
216
|
+
return budget.statementTimeoutMs !== null && budget.statementTimeoutMs > 0 ? Math.min(totalBound, budget.statementTimeoutMs) : totalBound;
|
|
217
|
+
}
|
|
218
|
+
function transactionDeadlineError(params) {
|
|
219
|
+
const { provider, stage, totalMs, overdueMs } = params;
|
|
220
|
+
const what = stage === "commit" ? "the transaction was rolled back instead of committed" : "the statement was never sent and the transaction is being rolled back";
|
|
221
|
+
return new VibeError4({
|
|
222
|
+
code: "VIBE_TRANSACTION",
|
|
223
|
+
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.",
|
|
224
|
+
meta: { provider, reason: "transaction-deadline", stage, totalMs, overdueMs: Math.max(0, Math.round(overdueMs)) }
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
function transactionClosedError(params) {
|
|
228
|
+
const { provider, outcome, stage } = params;
|
|
229
|
+
return new VibeError4({
|
|
230
|
+
code: "VIBE_TRANSACTION",
|
|
231
|
+
message: `this transaction has already finished (${outcome}), so its client can no longer be used \u2014 ` + "a handle kept past the end of `$transaction` would run outside the transaction, on a connection " + "that now belongs to someone else",
|
|
232
|
+
meta: { provider, reason: "transaction-closed", outcome, stage }
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
function transactionOutcomeUnknownError(params) {
|
|
236
|
+
const { provider, totalMs, cause } = params;
|
|
237
|
+
return new VibeError4({
|
|
238
|
+
code: "VIBE_TRANSACTION",
|
|
239
|
+
message: `transaction deadline of ${totalMs} ms expired and the rollback that should have cleaned up failed \u2014 ` + "the commit state of this transaction is UNKNOWN. It is not retried automatically; inspect the data " + "before deciding.",
|
|
240
|
+
meta: {
|
|
241
|
+
provider,
|
|
242
|
+
reason: "transaction-outcome-unknown",
|
|
243
|
+
outcome: "unknown",
|
|
244
|
+
totalMs,
|
|
245
|
+
rollbackFailed: true
|
|
246
|
+
},
|
|
247
|
+
cause
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
function isTransactionDeadlineError(error) {
|
|
251
|
+
const reason = error?.meta?.reason;
|
|
252
|
+
return reason === "transaction-deadline";
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// packages/adapter-bun/src/savepoint-gate.ts
|
|
256
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
257
|
+
|
|
258
|
+
// packages/adapter-bun/src/savepoints.ts
|
|
259
|
+
function createSavepointCounter() {
|
|
260
|
+
return { n: 0 };
|
|
261
|
+
}
|
|
262
|
+
function nextSavepointName(params) {
|
|
263
|
+
return `vibeorm_sp_${params.counter.n++}`;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// packages/adapter-bun/src/savepoint-gate.ts
|
|
267
|
+
var CURRENT = new AsyncLocalStorage;
|
|
268
|
+
function createSavepointScope() {
|
|
269
|
+
return { depth: 0, state: { counter: createSavepointCounter(), open: null } };
|
|
270
|
+
}
|
|
271
|
+
function runRootScope(params) {
|
|
272
|
+
return CURRENT.run(params.scope, params.body);
|
|
273
|
+
}
|
|
274
|
+
function scopeTurn(params) {
|
|
275
|
+
const open = params.scope.state.open;
|
|
276
|
+
if (mayProceed({ scope: params.scope, open }))
|
|
277
|
+
return;
|
|
278
|
+
return waitForTurn({ scope: params.scope });
|
|
279
|
+
}
|
|
280
|
+
async function runNestedSavepoint(params) {
|
|
281
|
+
const { scope, execute, body } = params;
|
|
282
|
+
const node = await acquire({ scope });
|
|
283
|
+
try {
|
|
284
|
+
if (execute !== undefined)
|
|
285
|
+
await execute(`SAVEPOINT ${node.name}`);
|
|
286
|
+
let result;
|
|
287
|
+
try {
|
|
288
|
+
result = await CURRENT.run(node.scope, () => body(node.scope));
|
|
289
|
+
} catch (error) {
|
|
290
|
+
await drainDescendants({ node });
|
|
291
|
+
if (execute !== undefined) {
|
|
292
|
+
try {
|
|
293
|
+
await execute(`ROLLBACK TO SAVEPOINT ${node.name}`);
|
|
294
|
+
} catch {}
|
|
295
|
+
}
|
|
296
|
+
throw error;
|
|
297
|
+
}
|
|
298
|
+
await drainDescendants({ node });
|
|
299
|
+
if (execute !== undefined)
|
|
300
|
+
await execute(`RELEASE SAVEPOINT ${node.name}`);
|
|
301
|
+
return result;
|
|
302
|
+
} finally {
|
|
303
|
+
closeNode({ node });
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
function mayProceed(params) {
|
|
307
|
+
const { scope, open } = params;
|
|
308
|
+
if (open === null)
|
|
309
|
+
return true;
|
|
310
|
+
if (open.scope === scope)
|
|
311
|
+
return true;
|
|
312
|
+
if (open.scope.depth < scope.depth)
|
|
313
|
+
return true;
|
|
314
|
+
return CURRENT.getStore() === open.scope;
|
|
315
|
+
}
|
|
316
|
+
async function waitForTurn(params) {
|
|
317
|
+
for (;; ) {
|
|
318
|
+
const open = params.scope.state.open;
|
|
319
|
+
if (open === null || mayProceed({ scope: params.scope, open }))
|
|
320
|
+
return;
|
|
321
|
+
await open.settled;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
async function acquire(params) {
|
|
325
|
+
const { scope } = params;
|
|
326
|
+
for (;; ) {
|
|
327
|
+
const open = scope.state.open;
|
|
328
|
+
if (mayProceed({ scope, open }))
|
|
329
|
+
return pushNode({ scope, parent: open });
|
|
330
|
+
await open.settled;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
function pushNode(params) {
|
|
334
|
+
const { scope, parent } = params;
|
|
335
|
+
const state = scope.state;
|
|
336
|
+
let settle = () => {
|
|
337
|
+
return;
|
|
338
|
+
};
|
|
339
|
+
const settled = new Promise((resolve) => {
|
|
340
|
+
settle = () => resolve();
|
|
341
|
+
});
|
|
342
|
+
const node = {
|
|
343
|
+
scope: { depth: (parent === null ? 0 : parent.scope.depth) + 1, state },
|
|
344
|
+
name: nextSavepointName({ counter: state.counter }),
|
|
345
|
+
parent,
|
|
346
|
+
settled,
|
|
347
|
+
settle
|
|
348
|
+
};
|
|
349
|
+
state.open = node;
|
|
350
|
+
return node;
|
|
351
|
+
}
|
|
352
|
+
function closeNode(params) {
|
|
353
|
+
const { node } = params;
|
|
354
|
+
const state = node.scope.state;
|
|
355
|
+
if (state.open === node)
|
|
356
|
+
state.open = node.parent;
|
|
357
|
+
node.settle();
|
|
358
|
+
}
|
|
359
|
+
async function drainDescendants(params) {
|
|
360
|
+
const state = params.node.scope.state;
|
|
361
|
+
for (;; ) {
|
|
362
|
+
const open = state.open;
|
|
363
|
+
if (open === null || open === params.node || open.scope.depth <= params.node.scope.depth)
|
|
364
|
+
return;
|
|
365
|
+
await open.settled;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// packages/adapter-bun/src/template-cache.ts
|
|
370
|
+
import { VibeError as VibeError5 } from "@vibeorm/schema";
|
|
371
|
+
function isIdentChar(char) {
|
|
372
|
+
if (char === undefined)
|
|
373
|
+
return false;
|
|
374
|
+
return /[A-Za-z0-9_]/.test(char);
|
|
375
|
+
}
|
|
376
|
+
function skipQuoted(text, start, quote) {
|
|
377
|
+
const escaping = quote === "'" && (text[start - 1] === "e" || text[start - 1] === "E") && !isIdentChar(text[start - 2]);
|
|
378
|
+
let index = start + 1;
|
|
379
|
+
while (index < text.length) {
|
|
380
|
+
const char = text[index];
|
|
381
|
+
if (escaping && char === "\\") {
|
|
382
|
+
index += 2;
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
if (char === quote) {
|
|
386
|
+
if (text[index + 1] === quote) {
|
|
387
|
+
index += 2;
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
return index + 1;
|
|
391
|
+
}
|
|
392
|
+
index += 1;
|
|
393
|
+
}
|
|
394
|
+
return text.length;
|
|
395
|
+
}
|
|
396
|
+
function skipBlockComment(text, start) {
|
|
397
|
+
let depth = 0;
|
|
398
|
+
let index = start;
|
|
399
|
+
while (index < text.length) {
|
|
400
|
+
if (text[index] === "/" && text[index + 1] === "*") {
|
|
401
|
+
depth += 1;
|
|
402
|
+
index += 2;
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
if (text[index] === "*" && text[index + 1] === "/") {
|
|
406
|
+
depth -= 1;
|
|
407
|
+
index += 2;
|
|
408
|
+
if (depth === 0)
|
|
409
|
+
return index;
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
index += 1;
|
|
413
|
+
}
|
|
414
|
+
return text.length;
|
|
415
|
+
}
|
|
416
|
+
function skipDollarQuoted(text, start) {
|
|
417
|
+
const opener = /^\$(?:[A-Za-z_][A-Za-z0-9_]*)?\$/.exec(text.slice(start));
|
|
418
|
+
if (opener === null)
|
|
419
|
+
return -1;
|
|
420
|
+
const tag = opener[0];
|
|
421
|
+
const close = text.indexOf(tag, start + tag.length);
|
|
422
|
+
return close === -1 ? text.length : close + tag.length;
|
|
423
|
+
}
|
|
424
|
+
function scanPlaceholders(params) {
|
|
425
|
+
const { text } = params;
|
|
426
|
+
const chunks = [];
|
|
427
|
+
const indices = [];
|
|
428
|
+
let chunkStart = 0;
|
|
429
|
+
let index = 0;
|
|
430
|
+
while (index < text.length) {
|
|
431
|
+
const char = text[index];
|
|
432
|
+
if (char === "'" || char === '"') {
|
|
433
|
+
index = skipQuoted(text, index, char);
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
if (char === "-" && text[index + 1] === "-") {
|
|
437
|
+
const newline = text.indexOf(`
|
|
438
|
+
`, index);
|
|
439
|
+
index = newline === -1 ? text.length : newline + 1;
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
if (char === "/" && text[index + 1] === "*") {
|
|
443
|
+
index = skipBlockComment(text, index);
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
if (char === "$") {
|
|
447
|
+
const dollarEnd = skipDollarQuoted(text, index);
|
|
448
|
+
if (dollarEnd !== -1) {
|
|
449
|
+
index = dollarEnd;
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
let digits = index + 1;
|
|
453
|
+
while (digits < text.length && text[digits] !== undefined && /[0-9]/.test(text[digits]))
|
|
454
|
+
digits += 1;
|
|
455
|
+
if (digits > index + 1) {
|
|
456
|
+
chunks.push(text.slice(chunkStart, index));
|
|
457
|
+
indices.push(Number(text.slice(index + 1, digits)));
|
|
458
|
+
chunkStart = digits;
|
|
459
|
+
index = digits;
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
index += 1;
|
|
464
|
+
}
|
|
465
|
+
chunks.push(text.slice(chunkStart));
|
|
466
|
+
const template = Object.assign(chunks, { raw: chunks });
|
|
467
|
+
return { template, indices };
|
|
468
|
+
}
|
|
469
|
+
function templateChunks(params) {
|
|
470
|
+
return [...scanPlaceholders(params).template];
|
|
471
|
+
}
|
|
472
|
+
function bindTemplateValues(params) {
|
|
473
|
+
const { text, indices, values } = params;
|
|
474
|
+
return indices.map((placeholder) => {
|
|
475
|
+
if (placeholder < 1 || placeholder > values.length) {
|
|
476
|
+
throw new VibeError5({
|
|
477
|
+
code: "VIBE_VALIDATION",
|
|
478
|
+
message: `bun:sql prepared statement references $${placeholder} but only ${values.length} parameter(s) were given`,
|
|
479
|
+
meta: { text, placeholder, provided: values.length }
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
return values[placeholder - 1];
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
function createTemplateCache(params) {
|
|
486
|
+
const { max } = params;
|
|
487
|
+
const templates = new Map;
|
|
488
|
+
return {
|
|
489
|
+
getTemplate(templateParams) {
|
|
490
|
+
const { text } = templateParams;
|
|
491
|
+
const existing = templates.get(text);
|
|
492
|
+
if (existing !== undefined) {
|
|
493
|
+
templates.delete(text);
|
|
494
|
+
templates.set(text, existing);
|
|
495
|
+
return existing;
|
|
496
|
+
}
|
|
497
|
+
const prepared = scanPlaceholders({ text });
|
|
498
|
+
if (templates.size >= max) {
|
|
499
|
+
const oldest = templates.keys().next().value;
|
|
500
|
+
if (oldest !== undefined)
|
|
501
|
+
templates.delete(oldest);
|
|
502
|
+
}
|
|
503
|
+
templates.set(text, prepared);
|
|
504
|
+
return prepared;
|
|
505
|
+
},
|
|
506
|
+
size() {
|
|
507
|
+
return templates.size;
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// packages/adapter-bun/src/transaction-sql.ts
|
|
513
|
+
import { VibeError as VibeError6 } from "@vibeorm/schema";
|
|
514
|
+
var ISOLATION_LEVEL_SQL = Object.freeze({
|
|
515
|
+
ReadCommitted: "READ COMMITTED",
|
|
516
|
+
RepeatableRead: "REPEATABLE READ",
|
|
517
|
+
Serializable: "SERIALIZABLE"
|
|
518
|
+
});
|
|
519
|
+
function beginStatement(params) {
|
|
520
|
+
const { isolationLevel } = params;
|
|
521
|
+
return isolationLevel === undefined ? "BEGIN" : `BEGIN ISOLATION LEVEL ${ISOLATION_LEVEL_SQL[isolationLevel]}`;
|
|
522
|
+
}
|
|
523
|
+
function statementTimeoutStatement(params) {
|
|
524
|
+
const { timeout } = params;
|
|
525
|
+
if (!Number.isInteger(timeout) || timeout < 0) {
|
|
526
|
+
throw new VibeError6({
|
|
527
|
+
code: "VIBE_VALIDATION",
|
|
528
|
+
message: `transaction timeout must be a non-negative integer of milliseconds, received ${String(timeout)}`,
|
|
529
|
+
meta: { timeout }
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
return `SET LOCAL statement_timeout = ${timeout}`;
|
|
533
|
+
}
|
|
534
|
+
var RAW_OPEN_PATTERN = /^\s*(?:begin|start\s+transaction)\b[^;]*;?\s*$/i;
|
|
535
|
+
var RAW_CLOSE_PATTERN = /^\s*(?:commit|end|rollback|abort)(?:\s+(?:transaction|work))?\s*;?\s*$/i;
|
|
536
|
+
function classifyRawTransactionControl(params) {
|
|
537
|
+
if (RAW_OPEN_PATTERN.test(params.text))
|
|
538
|
+
return "open";
|
|
539
|
+
if (RAW_CLOSE_PATTERN.test(params.text))
|
|
540
|
+
return "close";
|
|
541
|
+
return null;
|
|
542
|
+
}
|
|
543
|
+
function refuseNestedTransactionOptions(params) {
|
|
544
|
+
const { options, provider } = params;
|
|
545
|
+
if (options === undefined)
|
|
546
|
+
return;
|
|
547
|
+
const passed = [];
|
|
548
|
+
if (options.isolationLevel !== undefined)
|
|
549
|
+
passed.push("isolationLevel");
|
|
550
|
+
if (options.timeout !== undefined)
|
|
551
|
+
passed.push("timeout");
|
|
552
|
+
if (options.deadline !== undefined)
|
|
553
|
+
passed.push("deadline");
|
|
554
|
+
if (passed.length === 0)
|
|
555
|
+
return;
|
|
556
|
+
const meta = { provider, nested: true };
|
|
557
|
+
if (options.isolationLevel !== undefined)
|
|
558
|
+
meta.isolationLevel = options.isolationLevel;
|
|
559
|
+
if (options.timeout !== undefined)
|
|
560
|
+
meta.timeout = options.timeout;
|
|
561
|
+
if (options.deadline !== undefined)
|
|
562
|
+
meta.deadline = options.deadline;
|
|
563
|
+
throw new VibeError6({
|
|
564
|
+
code: "VIBE_VALIDATION",
|
|
565
|
+
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`,
|
|
566
|
+
meta
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// packages/adapter-bun/src/index.ts
|
|
571
|
+
class CallbackError extends Error {
|
|
572
|
+
inner;
|
|
573
|
+
constructor(inner) {
|
|
574
|
+
super("vibeorm: transaction callback failed");
|
|
575
|
+
this.name = "CallbackError";
|
|
576
|
+
this.inner = inner;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
var DIALECT = "postgres";
|
|
580
|
+
var PROVIDER = "postgresql";
|
|
581
|
+
var BUDGETS = Object.freeze({
|
|
582
|
+
acquireTimeout: true,
|
|
583
|
+
statementTimeout: "all-statements",
|
|
584
|
+
transactionDeadline: "cancel-running-statements"
|
|
585
|
+
});
|
|
586
|
+
var WIRE_TEXT = Object.freeze({ dateTime: "native", json: "text", numbers: "native" });
|
|
587
|
+
var WIRE_PARSED = Object.freeze({ dateTime: "native", json: "parsed", numbers: "native" });
|
|
588
|
+
function bunAdapter(options) {
|
|
589
|
+
const usePrepared = options?.preparedStatements ?? false;
|
|
590
|
+
const templates = createTemplateCache({ max: options?.stmtCacheMax ?? 1000 });
|
|
591
|
+
let activeWire = WIRE_TEXT;
|
|
592
|
+
let wireSettled = false;
|
|
593
|
+
let wireProbe = null;
|
|
594
|
+
let instance = null;
|
|
595
|
+
let rawSession = null;
|
|
596
|
+
function getSql() {
|
|
597
|
+
if (instance !== null)
|
|
598
|
+
return instance;
|
|
599
|
+
const sqlOptions = { max: options?.max ?? 10 };
|
|
600
|
+
if (options?.connectionTimeout !== undefined) {
|
|
601
|
+
sqlOptions.connectionTimeout = Math.max(1, Math.ceil(options.connectionTimeout / 1000));
|
|
602
|
+
}
|
|
603
|
+
const startupOptions = buildStartupOptions({
|
|
604
|
+
planCacheMode: options?.planCacheMode ?? "force_custom_plan",
|
|
605
|
+
statementTimeout: options?.statementTimeout
|
|
606
|
+
});
|
|
607
|
+
const baseUrl = options?.url ?? process.env.DATABASE_URL;
|
|
608
|
+
const url = baseUrl === undefined || startupOptions === undefined ? baseUrl : applyStartupOptions({ url: baseUrl, startupOptions });
|
|
609
|
+
instance = url === undefined ? new SQL(sqlOptions) : new SQL(url, sqlOptions);
|
|
610
|
+
return instance;
|
|
611
|
+
}
|
|
612
|
+
async function probeJsonWire(source) {
|
|
613
|
+
const probe = renderDiagnostic({ dialect: postgresDialect, query: "postgresJsonWire" });
|
|
614
|
+
try {
|
|
615
|
+
const rows = usePrepared ? await source(templates.getTemplate({ text: probe.text }).template) : await source.unsafe(probe.text, []);
|
|
616
|
+
const probed = rows[0]?.probe;
|
|
617
|
+
if (typeof probed === "object" && probed !== null)
|
|
618
|
+
activeWire = WIRE_PARSED;
|
|
619
|
+
} catch {} finally {
|
|
620
|
+
wireSettled = true;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
async function runExecute(params) {
|
|
624
|
+
if (!wireSettled) {
|
|
625
|
+
wireProbe ??= probeJsonWire(params.source);
|
|
626
|
+
await wireProbe;
|
|
627
|
+
}
|
|
628
|
+
const values = serializeParams({ values: params.values });
|
|
629
|
+
if (usePrepared) {
|
|
630
|
+
const prepared = templates.getTemplate({ text: params.text });
|
|
631
|
+
const bound = bindTemplateValues({ text: params.text, indices: prepared.indices, values });
|
|
632
|
+
return runMapped(() => params.source(prepared.template, ...bound));
|
|
633
|
+
}
|
|
634
|
+
return runMapped(() => params.source.unsafe(params.text, values));
|
|
635
|
+
}
|
|
636
|
+
async function runExecuteUnsafe(params) {
|
|
637
|
+
const values = params.values === undefined ? undefined : serializeParamsRaw({ values: params.values });
|
|
638
|
+
const rows = await runMapped(() => params.source.unsafe(params.text, values));
|
|
639
|
+
return { rows, affectedRows: readAffectedRows({ rows }) };
|
|
640
|
+
}
|
|
641
|
+
function createAdapter(params) {
|
|
642
|
+
const { source, parentMode, scope, budget } = params;
|
|
643
|
+
async function applyEngineBudget() {
|
|
644
|
+
if (budget === undefined)
|
|
645
|
+
return;
|
|
646
|
+
const ms = engineStatementBudgetMs({ budget });
|
|
647
|
+
if (ms === null)
|
|
648
|
+
return;
|
|
649
|
+
await runMapped(() => source.unsafe(statementTimeoutStatement({ timeout: ms })));
|
|
650
|
+
}
|
|
651
|
+
async function transactionViaSavepoint(fn, nestedOptions) {
|
|
652
|
+
refuseNestedTransactionOptions({ options: nestedOptions, provider: PROVIDER });
|
|
653
|
+
budget?.assertUsable({ stage: "nested" });
|
|
654
|
+
const transactional = source;
|
|
655
|
+
const driverSavepoint = transactional.savepoint?.bind(transactional);
|
|
656
|
+
if (driverSavepoint !== undefined) {
|
|
657
|
+
return runNestedSavepoint({
|
|
658
|
+
scope,
|
|
659
|
+
body: async (child) => {
|
|
660
|
+
try {
|
|
661
|
+
return await driverSavepoint(async (savepointSql) => {
|
|
662
|
+
const nested = createAdapter({
|
|
663
|
+
source: savepointSql,
|
|
664
|
+
parentMode: "tx",
|
|
665
|
+
scope: child
|
|
666
|
+
});
|
|
667
|
+
try {
|
|
668
|
+
return await fn(nested);
|
|
669
|
+
} catch (error) {
|
|
670
|
+
throw new CallbackError(error);
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
} catch (error) {
|
|
674
|
+
if (error instanceof CallbackError)
|
|
675
|
+
throw error.inner;
|
|
676
|
+
throw mapBunDriverError({ error });
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
return runNestedSavepoint({
|
|
682
|
+
scope,
|
|
683
|
+
execute: (statement) => runMapped(() => transactional.unsafe(statement)),
|
|
684
|
+
body: (child) => fn(createAdapter({ source: transactional, parentMode: "tx", scope: child, budget }))
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
async function transactionViaPool(fn, transactionOptions) {
|
|
688
|
+
const pool = source;
|
|
689
|
+
validateTransactionDeadline({
|
|
690
|
+
options: transactionOptions,
|
|
691
|
+
support: BUDGETS.transactionDeadline,
|
|
692
|
+
provider: PROVIDER
|
|
693
|
+
});
|
|
694
|
+
if (transactionOptions?.isolationLevel === undefined && transactionOptions?.timeout === undefined && transactionOptions?.deadline === undefined) {
|
|
695
|
+
const budget3 = startTransactionBudget({ provider: PROVIDER });
|
|
696
|
+
try {
|
|
697
|
+
const result = await pool.begin(async (txSql) => {
|
|
698
|
+
const txScope = createSavepointScope();
|
|
699
|
+
const txAdapter = createAdapter({
|
|
700
|
+
source: txSql,
|
|
701
|
+
parentMode: "tx",
|
|
702
|
+
scope: txScope,
|
|
703
|
+
budget: budget3
|
|
704
|
+
});
|
|
705
|
+
try {
|
|
706
|
+
return await runRootScope({ scope: txScope, body: () => fn(txAdapter) });
|
|
707
|
+
} catch (error) {
|
|
708
|
+
throw new CallbackError(error);
|
|
709
|
+
}
|
|
710
|
+
});
|
|
711
|
+
budget3.close({ outcome: "committed" });
|
|
712
|
+
return result;
|
|
713
|
+
} catch (error) {
|
|
714
|
+
budget3.close({ outcome: "rolled-back" });
|
|
715
|
+
if (error instanceof CallbackError)
|
|
716
|
+
throw error.inner;
|
|
717
|
+
throw mapBunDriverError({ error });
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
const timeoutText = transactionOptions.timeout === undefined ? undefined : statementTimeoutStatement({ timeout: transactionOptions.timeout });
|
|
721
|
+
const reserved = await runMapped(() => pool.reserve());
|
|
722
|
+
const budget2 = startTransactionBudget({ options: transactionOptions, provider: PROVIDER });
|
|
723
|
+
try {
|
|
724
|
+
await runMapped(() => reserved.unsafe(beginStatement({ isolationLevel: transactionOptions.isolationLevel })));
|
|
725
|
+
if (timeoutText !== undefined)
|
|
726
|
+
await runMapped(() => reserved.unsafe(timeoutText));
|
|
727
|
+
const txScope = createSavepointScope();
|
|
728
|
+
const txAdapter = createAdapter({
|
|
729
|
+
source: reserved,
|
|
730
|
+
parentMode: "tx",
|
|
731
|
+
scope: txScope,
|
|
732
|
+
budget: budget2
|
|
733
|
+
});
|
|
734
|
+
const result = await runRootScope({ scope: txScope, body: () => fn(txAdapter) });
|
|
735
|
+
budget2.assertUsable({ stage: "commit" });
|
|
736
|
+
await runMapped(() => reserved.unsafe("COMMIT"));
|
|
737
|
+
budget2.close({ outcome: "committed" });
|
|
738
|
+
return result;
|
|
739
|
+
} catch (error) {
|
|
740
|
+
try {
|
|
741
|
+
await reserved.unsafe("ROLLBACK");
|
|
742
|
+
budget2.close({ outcome: "rolled-back" });
|
|
743
|
+
} catch {
|
|
744
|
+
budget2.close({ outcome: "unknown" });
|
|
745
|
+
if (budget2.totalMs !== null && isTransactionDeadlineError(error)) {
|
|
746
|
+
throw transactionOutcomeUnknownError({
|
|
747
|
+
provider: PROVIDER,
|
|
748
|
+
totalMs: budget2.totalMs,
|
|
749
|
+
cause: error
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
throw error;
|
|
754
|
+
} finally {
|
|
755
|
+
reserved.release();
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
return {
|
|
759
|
+
dialect: DIALECT,
|
|
760
|
+
provider: PROVIDER,
|
|
761
|
+
budgets: BUDGETS,
|
|
762
|
+
get wire() {
|
|
763
|
+
return activeWire;
|
|
764
|
+
},
|
|
765
|
+
async execute(execParams) {
|
|
766
|
+
const turn = scopeTurn({ scope });
|
|
767
|
+
if (turn !== undefined)
|
|
768
|
+
await turn;
|
|
769
|
+
budget?.assertUsable({ stage: "statement" });
|
|
770
|
+
await applyEngineBudget();
|
|
771
|
+
return runExecute({ source, ...execParams });
|
|
772
|
+
},
|
|
773
|
+
async executeUnsafe(execParams) {
|
|
774
|
+
const turn = scopeTurn({ scope });
|
|
775
|
+
if (turn !== undefined)
|
|
776
|
+
await turn;
|
|
777
|
+
budget?.assertUsable({ stage: "statement" });
|
|
778
|
+
await applyEngineBudget();
|
|
779
|
+
return runExecuteUnsafe({ source, ...execParams });
|
|
780
|
+
},
|
|
781
|
+
async transaction(fn, transactionOptions) {
|
|
782
|
+
return parentMode === "pool" ? transactionViaPool(fn, transactionOptions) : transactionViaSavepoint(fn, transactionOptions);
|
|
783
|
+
},
|
|
784
|
+
async connect() {
|
|
785
|
+
if (parentMode !== "pool")
|
|
786
|
+
return;
|
|
787
|
+
const reserved = await runMapped(() => source.reserve());
|
|
788
|
+
reserved.release();
|
|
789
|
+
},
|
|
790
|
+
async disconnect() {
|
|
791
|
+
if (parentMode !== "pool")
|
|
792
|
+
return;
|
|
793
|
+
await runMapped(() => source.close());
|
|
794
|
+
instance = null;
|
|
795
|
+
},
|
|
796
|
+
formatArrayParam(values) {
|
|
797
|
+
return toPgArrayLiteral(values);
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
function poolAdapter() {
|
|
802
|
+
return createAdapter({
|
|
803
|
+
source: getSql(),
|
|
804
|
+
parentMode: "pool",
|
|
805
|
+
scope: createSavepointScope()
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
return {
|
|
809
|
+
dialect: DIALECT,
|
|
810
|
+
provider: PROVIDER,
|
|
811
|
+
budgets: BUDGETS,
|
|
812
|
+
get wire() {
|
|
813
|
+
return activeWire;
|
|
814
|
+
},
|
|
815
|
+
async execute(params) {
|
|
816
|
+
return poolAdapter().execute(params);
|
|
817
|
+
},
|
|
818
|
+
async executeUnsafe(params) {
|
|
819
|
+
const control = classifyRawTransactionControl({ text: params.text });
|
|
820
|
+
if (rawSession !== null) {
|
|
821
|
+
if (control === "close") {
|
|
822
|
+
const session = rawSession;
|
|
823
|
+
rawSession = null;
|
|
824
|
+
try {
|
|
825
|
+
return await runExecuteUnsafe({ source: session, ...params });
|
|
826
|
+
} finally {
|
|
827
|
+
session.release();
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
return runExecuteUnsafe({ source: rawSession, ...params });
|
|
831
|
+
}
|
|
832
|
+
if (control === "open") {
|
|
833
|
+
const reserved = await runMapped(() => getSql().reserve());
|
|
834
|
+
try {
|
|
835
|
+
const result = await runExecuteUnsafe({ source: reserved, ...params });
|
|
836
|
+
rawSession = reserved;
|
|
837
|
+
return result;
|
|
838
|
+
} catch (error) {
|
|
839
|
+
reserved.release();
|
|
840
|
+
throw error;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
return poolAdapter().executeUnsafe(params);
|
|
844
|
+
},
|
|
845
|
+
async transaction(fn, transactionOptions) {
|
|
846
|
+
return poolAdapter().transaction(fn, transactionOptions);
|
|
847
|
+
},
|
|
848
|
+
async connect() {
|
|
849
|
+
return poolAdapter().connect();
|
|
850
|
+
},
|
|
851
|
+
async disconnect() {
|
|
852
|
+
if (rawSession !== null) {
|
|
853
|
+
const session = rawSession;
|
|
854
|
+
rawSession = null;
|
|
855
|
+
try {
|
|
856
|
+
await session.unsafe("ROLLBACK");
|
|
857
|
+
} catch {}
|
|
858
|
+
session.release();
|
|
859
|
+
}
|
|
860
|
+
if (instance === null)
|
|
861
|
+
return;
|
|
862
|
+
const closing = instance;
|
|
863
|
+
instance = null;
|
|
864
|
+
await runMapped(() => closing.close());
|
|
865
|
+
},
|
|
866
|
+
formatArrayParam(values) {
|
|
867
|
+
return toPgArrayLiteral(values);
|
|
868
|
+
}
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
function readAffectedRows(params) {
|
|
872
|
+
const { rows } = params;
|
|
873
|
+
if (typeof rows.count === "number")
|
|
874
|
+
return rows.count;
|
|
875
|
+
if (typeof rows.affectedRows === "number")
|
|
876
|
+
return rows.affectedRows;
|
|
877
|
+
return rows.length;
|
|
878
|
+
}
|
|
879
|
+
export {
|
|
880
|
+
validateTransactionDeadline,
|
|
881
|
+
transactionOutcomeUnknownError,
|
|
882
|
+
transactionDeadlineError,
|
|
883
|
+
transactionClosedError,
|
|
884
|
+
toPgArrayLiteral,
|
|
885
|
+
templateChunks,
|
|
886
|
+
statementTimeoutStatement,
|
|
887
|
+
startTransactionBudget,
|
|
888
|
+
serializeParamsRaw,
|
|
889
|
+
serializeParams,
|
|
890
|
+
refuseNestedTransactionOptions,
|
|
891
|
+
nextSavepointName,
|
|
892
|
+
mapBunDriverError,
|
|
893
|
+
isTransactionDeadlineError,
|
|
894
|
+
engineStatementBudgetMs,
|
|
895
|
+
createTemplateCache,
|
|
896
|
+
createSavepointCounter,
|
|
897
|
+
classifyRawTransactionControl,
|
|
898
|
+
bunErrorSqlstate,
|
|
899
|
+
bunAdapter,
|
|
900
|
+
buildStartupOptions,
|
|
901
|
+
beginStatement,
|
|
902
|
+
applyStartupOptions,
|
|
903
|
+
ISOLATION_LEVEL_SQL,
|
|
904
|
+
DEFAULT_DEADLINE_CLOCK,
|
|
905
|
+
BUN_SQLSTATE_REASONS,
|
|
906
|
+
BUN_SQLSTATE_ERROR_CODES
|
|
907
|
+
};
|
|
908
|
+
|
|
909
|
+
//# debugId=81824F43B962EC8264756E2164756E21
|