@event-driven-io/dumbo 0.13.0-beta.46 → 0.13.0-beta.47
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/cloudflare.cjs +432 -69
- package/dist/cloudflare.cjs.map +1 -1
- package/dist/cloudflare.d.cts +2 -2
- package/dist/cloudflare.d.ts +2 -2
- package/dist/cloudflare.js +432 -69
- package/dist/cloudflare.js.map +1 -1
- package/dist/{index-B5krjjrh.d.ts → index-4hcCG4SA.d.ts} +66 -30
- package/dist/{index-BaLXbc2l.d.ts → index-B7366zWR.d.ts} +1 -1
- package/dist/{index-_dj3upBo.d.cts → index-BJ-dm7dG.d.cts} +66 -30
- package/dist/{index-kYttgYkC.d.cts → index-BkJ1pipM.d.cts} +1 -1
- package/dist/{index-C9B46a1u.d.ts → index-CQokD3za.d.cts} +2 -2
- package/dist/{index-BoLWBnxd.d.cts → index-DIJv-L6M.d.ts} +2 -2
- package/dist/index.cjs +523 -269
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +522 -270
- package/dist/index.js.map +1 -1
- package/dist/pg.cjs +168 -28
- package/dist/pg.cjs.map +1 -1
- package/dist/pg.d.cts +2 -2
- package/dist/pg.d.ts +2 -2
- package/dist/pg.js +168 -28
- package/dist/pg.js.map +1 -1
- package/dist/postgresql.cjs +4 -0
- package/dist/postgresql.cjs.map +1 -1
- package/dist/postgresql.d.cts +2 -2
- package/dist/postgresql.d.ts +2 -2
- package/dist/postgresql.js +4 -0
- package/dist/postgresql.js.map +1 -1
- package/dist/sqlite.cjs +429 -68
- package/dist/sqlite.cjs.map +1 -1
- package/dist/sqlite.d.cts +2 -2
- package/dist/sqlite.d.ts +2 -2
- package/dist/sqlite.js +429 -68
- package/dist/sqlite.js.map +1 -1
- package/dist/sqlite3.cjs +639 -343
- package/dist/sqlite3.cjs.map +1 -1
- package/dist/sqlite3.d.cts +10 -10
- package/dist/sqlite3.d.ts +10 -10
- package/dist/sqlite3.js +639 -343
- package/dist/sqlite3.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -212,6 +212,364 @@ var InvalidOperationError = class InvalidOperationError extends DumboError {
|
|
|
212
212
|
}
|
|
213
213
|
};
|
|
214
214
|
|
|
215
|
+
//#endregion
|
|
216
|
+
//#region src/core/taskProcessing/abort.ts
|
|
217
|
+
const never = { signal: new AbortController().signal };
|
|
218
|
+
const from = (options) => options?.abort ?? never;
|
|
219
|
+
const getSignal = (abort) => "signal" in abort ? abort.signal : abort;
|
|
220
|
+
const reason = (abort) => {
|
|
221
|
+
const signal = getSignal(abort);
|
|
222
|
+
return signal.reason instanceof Error ? signal.reason : new DumboError(typeof signal.reason === "string" ? signal.reason : "Operation aborted");
|
|
223
|
+
};
|
|
224
|
+
const scope = (parent, onAbort) => {
|
|
225
|
+
const controller = new AbortController();
|
|
226
|
+
return {
|
|
227
|
+
abort: (reason) => controller.abort(reason),
|
|
228
|
+
dispose: onAbortSignal(parent, (reason) => {
|
|
229
|
+
controller.abort(reason);
|
|
230
|
+
onAbort?.(reason);
|
|
231
|
+
}),
|
|
232
|
+
signal: controller.signal
|
|
233
|
+
};
|
|
234
|
+
};
|
|
235
|
+
const execute = (operation, options) => {
|
|
236
|
+
const abort = options?.abort;
|
|
237
|
+
if (!abort) return operation();
|
|
238
|
+
const signal = abort.signal;
|
|
239
|
+
if (signal.aborted) return Promise.reject(reason(abort));
|
|
240
|
+
return new Promise((resolve, reject) => {
|
|
241
|
+
let finished = false;
|
|
242
|
+
const rejectOnAbort = () => {
|
|
243
|
+
if (finished) return;
|
|
244
|
+
finished = true;
|
|
245
|
+
reject(reason(abort));
|
|
246
|
+
};
|
|
247
|
+
signal.addEventListener("abort", rejectOnAbort, { once: true });
|
|
248
|
+
let operationPromise;
|
|
249
|
+
try {
|
|
250
|
+
operationPromise = operation();
|
|
251
|
+
} catch (error) {
|
|
252
|
+
finished = true;
|
|
253
|
+
signal.removeEventListener("abort", rejectOnAbort);
|
|
254
|
+
reject(error);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
operationPromise.then((result) => {
|
|
258
|
+
if (finished) return;
|
|
259
|
+
finished = true;
|
|
260
|
+
signal.removeEventListener("abort", rejectOnAbort);
|
|
261
|
+
resolve(result);
|
|
262
|
+
}).catch((error) => {
|
|
263
|
+
if (finished) return;
|
|
264
|
+
finished = true;
|
|
265
|
+
signal.removeEventListener("abort", rejectOnAbort);
|
|
266
|
+
reject(error);
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
};
|
|
270
|
+
const throwIfAborted = (options) => {
|
|
271
|
+
const abort = options?.abort;
|
|
272
|
+
if (abort?.signal.aborted) throw reason(abort);
|
|
273
|
+
};
|
|
274
|
+
const rejectIfAborted = (options) => {
|
|
275
|
+
const abort = options?.abort;
|
|
276
|
+
return abort?.signal.aborted ? Promise.reject(reason(abort)) : void 0;
|
|
277
|
+
};
|
|
278
|
+
const onAbortSignal = (abort, handle) => {
|
|
279
|
+
if (!abort) return () => {};
|
|
280
|
+
const signal = abort.signal;
|
|
281
|
+
if (signal.aborted) {
|
|
282
|
+
handle(reason(abort));
|
|
283
|
+
return () => {};
|
|
284
|
+
}
|
|
285
|
+
const abortListener = () => handle(reason(abort));
|
|
286
|
+
signal.addEventListener("abort", abortListener, { once: true });
|
|
287
|
+
return () => signal.removeEventListener("abort", abortListener);
|
|
288
|
+
};
|
|
289
|
+
const Abort = {
|
|
290
|
+
execute,
|
|
291
|
+
from,
|
|
292
|
+
never,
|
|
293
|
+
onAbort: onAbortSignal,
|
|
294
|
+
reason,
|
|
295
|
+
rejectIfAborted,
|
|
296
|
+
scope,
|
|
297
|
+
throwIfAborted
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
//#endregion
|
|
301
|
+
//#region src/core/taskProcessing/taskProcessor.ts
|
|
302
|
+
var TaskProcessor = class {
|
|
303
|
+
queue = [];
|
|
304
|
+
isProcessing = false;
|
|
305
|
+
activeTasks = 0;
|
|
306
|
+
activeGroups = /* @__PURE__ */ new Set();
|
|
307
|
+
options;
|
|
308
|
+
stopped = false;
|
|
309
|
+
idleWaiters = [];
|
|
310
|
+
activeTaskAbortCallbacks = /* @__PURE__ */ new Set();
|
|
311
|
+
constructor(options) {
|
|
312
|
+
this.options = options;
|
|
313
|
+
}
|
|
314
|
+
enqueue(task, options) {
|
|
315
|
+
if (options?.abort?.signal.aborted) return Promise.reject(Abort.reason(options.abort.signal));
|
|
316
|
+
if (this.stopped) return Promise.reject(new DumboError("TaskProcessor has been stopped"));
|
|
317
|
+
if (this.queue.length >= this.options.maxQueueSize) return Promise.reject(new TransientDatabaseError("Too many pending connections. Please try again later."));
|
|
318
|
+
return this.schedule(task, options);
|
|
319
|
+
}
|
|
320
|
+
waitForEndOfProcessing() {
|
|
321
|
+
if (this.activeTasks === 0 && this.queue.length === 0) return Promise.resolve();
|
|
322
|
+
return new Promise((resolve) => {
|
|
323
|
+
this.idleWaiters.push(resolve);
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
async stop(options) {
|
|
327
|
+
if (this.stopped) return;
|
|
328
|
+
this.stopped = true;
|
|
329
|
+
const stoppedError = new DumboError("TaskProcessor has been stopped");
|
|
330
|
+
for (const item of this.queue.splice(0)) {
|
|
331
|
+
item.abort(stoppedError);
|
|
332
|
+
item.reject(stoppedError);
|
|
333
|
+
}
|
|
334
|
+
this.activeGroups.clear();
|
|
335
|
+
if (options?.force) for (const abort of this.activeTaskAbortCallbacks) abort(stoppedError);
|
|
336
|
+
if (options?.force) return;
|
|
337
|
+
if (options?.closeDeadline === void 0) {
|
|
338
|
+
await this.waitForEndOfProcessing();
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
if (!await waitForProcessingOrDeadline(this.waitForEndOfProcessing(), options.closeDeadline)) for (const abort of this.activeTaskAbortCallbacks) abort(stoppedError);
|
|
342
|
+
}
|
|
343
|
+
schedule(task, options) {
|
|
344
|
+
return new Promise((resolve, reject) => {
|
|
345
|
+
let didQueueTimeout = false;
|
|
346
|
+
let didAbortBeforeStart = false;
|
|
347
|
+
let didStart = false;
|
|
348
|
+
let queueWaitTimer = noopQueueWaitTimer;
|
|
349
|
+
const abortScope = Abort.scope(options?.abort, (reason) => {
|
|
350
|
+
queueWaitTimer.cancel();
|
|
351
|
+
didAbortBeforeStart = !didStart;
|
|
352
|
+
reject(reason);
|
|
353
|
+
});
|
|
354
|
+
queueWaitTimer = createQueueWaitTimer(this.options.maxTaskIdleTime, (reason) => {
|
|
355
|
+
didQueueTimeout = true;
|
|
356
|
+
abortScope.abort(reason);
|
|
357
|
+
abortScope.dispose();
|
|
358
|
+
reject(reason);
|
|
359
|
+
});
|
|
360
|
+
const taskWithContext = () => {
|
|
361
|
+
return new Promise((resolveTask) => {
|
|
362
|
+
if (didQueueTimeout || didAbortBeforeStart) {
|
|
363
|
+
resolveTask();
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
let taskPromise;
|
|
367
|
+
try {
|
|
368
|
+
taskPromise = task({
|
|
369
|
+
ack: resolveTask,
|
|
370
|
+
abort: abortScope
|
|
371
|
+
});
|
|
372
|
+
} catch (err) {
|
|
373
|
+
abortScope.dispose();
|
|
374
|
+
resolveTask();
|
|
375
|
+
reject(err);
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
taskPromise.then((result) => {
|
|
379
|
+
abortScope.dispose();
|
|
380
|
+
resolve(result);
|
|
381
|
+
}).catch((err) => {
|
|
382
|
+
abortScope.dispose();
|
|
383
|
+
resolveTask();
|
|
384
|
+
reject(err);
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
};
|
|
388
|
+
this.queue.push({
|
|
389
|
+
task: taskWithContext,
|
|
390
|
+
options,
|
|
391
|
+
reject: (reason) => {
|
|
392
|
+
queueWaitTimer.cancel();
|
|
393
|
+
abortScope.dispose();
|
|
394
|
+
reject(reason);
|
|
395
|
+
},
|
|
396
|
+
markStarted: () => {
|
|
397
|
+
didStart = true;
|
|
398
|
+
queueWaitTimer.cancel();
|
|
399
|
+
},
|
|
400
|
+
abort: (reason) => {
|
|
401
|
+
abortScope.dispose();
|
|
402
|
+
abortScope.abort(reason);
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
if (!this.isProcessing) this.ensureProcessing();
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
ensureProcessing() {
|
|
409
|
+
if (this.isProcessing) return;
|
|
410
|
+
this.isProcessing = true;
|
|
411
|
+
this.processQueue();
|
|
412
|
+
}
|
|
413
|
+
processQueue() {
|
|
414
|
+
try {
|
|
415
|
+
while (this.activeTasks < this.options.maxActiveTasks && this.queue.length > 0) {
|
|
416
|
+
const item = this.takeFirstAvailableItem();
|
|
417
|
+
if (item === null) return;
|
|
418
|
+
const groupId = item.options?.taskGroupId;
|
|
419
|
+
if (groupId) this.activeGroups.add(groupId);
|
|
420
|
+
this.activeTasks++;
|
|
421
|
+
this.executeItem(item);
|
|
422
|
+
}
|
|
423
|
+
} catch (error) {
|
|
424
|
+
console.error(error);
|
|
425
|
+
throw error;
|
|
426
|
+
} finally {
|
|
427
|
+
this.isProcessing = false;
|
|
428
|
+
if (this.hasItemsToProcess() && this.activeTasks < this.options.maxActiveTasks) this.ensureProcessing();
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
async executeItem({ task, options, markStarted, abort }) {
|
|
432
|
+
markStarted();
|
|
433
|
+
this.activeTaskAbortCallbacks.add(abort);
|
|
434
|
+
try {
|
|
435
|
+
await task();
|
|
436
|
+
} finally {
|
|
437
|
+
this.activeTaskAbortCallbacks.delete(abort);
|
|
438
|
+
this.activeTasks--;
|
|
439
|
+
if (options && options.taskGroupId) this.activeGroups.delete(options.taskGroupId);
|
|
440
|
+
this.resolveIdleWaiters();
|
|
441
|
+
this.ensureProcessing();
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
takeFirstAvailableItem = () => {
|
|
445
|
+
const taskIndex = this.queue.findIndex((item) => !item.options?.taskGroupId || !this.activeGroups.has(item.options.taskGroupId));
|
|
446
|
+
if (taskIndex === -1) return null;
|
|
447
|
+
const [item] = this.queue.splice(taskIndex, 1);
|
|
448
|
+
return item ?? null;
|
|
449
|
+
};
|
|
450
|
+
hasItemsToProcess = () => this.queue.findIndex((item) => !item.options?.taskGroupId || !this.activeGroups.has(item.options.taskGroupId)) !== -1;
|
|
451
|
+
resolveIdleWaiters = () => {
|
|
452
|
+
if (this.activeTasks > 0 || this.queue.length > 0) return;
|
|
453
|
+
const waiters = this.idleWaiters.splice(0);
|
|
454
|
+
for (const resolve of waiters) resolve();
|
|
455
|
+
};
|
|
456
|
+
};
|
|
457
|
+
const noopQueueWaitTimer = { cancel: () => {} };
|
|
458
|
+
const createQueueWaitTimer = (timeoutMs, reject) => {
|
|
459
|
+
if (timeoutMs === void 0) return noopQueueWaitTimer;
|
|
460
|
+
let timeoutId = setTimeout(() => {
|
|
461
|
+
reject(/* @__PURE__ */ new Error("Task was not started within the maximum waiting time"));
|
|
462
|
+
}, timeoutMs);
|
|
463
|
+
timeoutId.unref();
|
|
464
|
+
return { cancel: () => {
|
|
465
|
+
if (!timeoutId) return;
|
|
466
|
+
clearTimeout(timeoutId);
|
|
467
|
+
timeoutId = null;
|
|
468
|
+
} };
|
|
469
|
+
};
|
|
470
|
+
const waitForProcessingOrDeadline = async (processing, closeDeadline) => {
|
|
471
|
+
let timeoutId = null;
|
|
472
|
+
try {
|
|
473
|
+
return await Promise.race([processing.then(() => true), new Promise((resolve) => {
|
|
474
|
+
timeoutId = setTimeout(() => resolve(false), closeDeadline);
|
|
475
|
+
timeoutId.unref();
|
|
476
|
+
})]);
|
|
477
|
+
} finally {
|
|
478
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
//#endregion
|
|
483
|
+
//#region src/core/taskProcessing/executionGuards.ts
|
|
484
|
+
const guardConcurrentAccess = (options) => {
|
|
485
|
+
const taskProcessor = new TaskProcessor({
|
|
486
|
+
maxActiveTasks: options?.maxActiveTasks ?? Number.MAX_SAFE_INTEGER,
|
|
487
|
+
maxQueueSize: options?.maxQueueSize ?? Number.MAX_SAFE_INTEGER,
|
|
488
|
+
...options?.maxTaskIdleTime !== void 0 ? { maxTaskIdleTime: options.maxTaskIdleTime } : {}
|
|
489
|
+
});
|
|
490
|
+
return {
|
|
491
|
+
execute: (operation, options) => taskProcessor.enqueue(async (context) => {
|
|
492
|
+
try {
|
|
493
|
+
return await operation({ abort: context.abort });
|
|
494
|
+
} finally {
|
|
495
|
+
context.ack();
|
|
496
|
+
}
|
|
497
|
+
}, options),
|
|
498
|
+
waitForIdle: () => taskProcessor.waitForEndOfProcessing(),
|
|
499
|
+
stop: (options) => taskProcessor.stop(options)
|
|
500
|
+
};
|
|
501
|
+
};
|
|
502
|
+
const guardBoundedAccess = (getResource, options) => {
|
|
503
|
+
let isStopped = false;
|
|
504
|
+
const taskProcessor = new TaskProcessor({
|
|
505
|
+
maxActiveTasks: options.maxResources,
|
|
506
|
+
maxQueueSize: options.maxQueueSize ?? 1e3
|
|
507
|
+
});
|
|
508
|
+
const resourcePool = [];
|
|
509
|
+
const allResources = /* @__PURE__ */ new Set();
|
|
510
|
+
const activeResourceContexts = /* @__PURE__ */ new Map();
|
|
511
|
+
const acquireResource = async (taskContext) => {
|
|
512
|
+
try {
|
|
513
|
+
let resource;
|
|
514
|
+
if (options.reuseResources) resource = resourcePool.pop();
|
|
515
|
+
if (!resource) {
|
|
516
|
+
resource = await getResource({ abort: taskContext.abort });
|
|
517
|
+
allResources.add(resource);
|
|
518
|
+
}
|
|
519
|
+
activeResourceContexts.set(resource, {
|
|
520
|
+
ack: taskContext.ack,
|
|
521
|
+
taskContext
|
|
522
|
+
});
|
|
523
|
+
return resource;
|
|
524
|
+
} catch (e) {
|
|
525
|
+
taskContext.ack();
|
|
526
|
+
throw e;
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
const acquire = async (operationOptions) => taskProcessor.enqueue((taskContext) => acquireResource(taskContext), operationOptions);
|
|
530
|
+
const getActiveResourceContext = (resource) => {
|
|
531
|
+
const activeResourceContext = activeResourceContexts.get(resource);
|
|
532
|
+
if (!activeResourceContext) throw new Error("Acquired resource is not active");
|
|
533
|
+
return activeResourceContext;
|
|
534
|
+
};
|
|
535
|
+
const release = (resource) => {
|
|
536
|
+
const activeResourceContext = activeResourceContexts.get(resource);
|
|
537
|
+
if (activeResourceContext) {
|
|
538
|
+
activeResourceContexts.delete(resource);
|
|
539
|
+
if (options.reuseResources) resourcePool.push(resource);
|
|
540
|
+
activeResourceContext.ack();
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
const execute = async (operation, operationOptions) => {
|
|
544
|
+
return taskProcessor.enqueue(async (taskContext) => {
|
|
545
|
+
const resource = await acquireResource(taskContext);
|
|
546
|
+
const activeResourceContext = getActiveResourceContext(resource);
|
|
547
|
+
try {
|
|
548
|
+
return await operation(resource, { abort: activeResourceContext.taskContext.abort });
|
|
549
|
+
} finally {
|
|
550
|
+
release(resource);
|
|
551
|
+
}
|
|
552
|
+
}, operationOptions);
|
|
553
|
+
};
|
|
554
|
+
return {
|
|
555
|
+
acquire,
|
|
556
|
+
release,
|
|
557
|
+
execute,
|
|
558
|
+
waitForIdle: () => taskProcessor.waitForEndOfProcessing(),
|
|
559
|
+
stop: async (stopOptions) => {
|
|
560
|
+
if (isStopped) return;
|
|
561
|
+
isStopped = true;
|
|
562
|
+
await taskProcessor.stop(stopOptions);
|
|
563
|
+
if (options?.closeResource) {
|
|
564
|
+
const resources = [...allResources];
|
|
565
|
+
allResources.clear();
|
|
566
|
+
resourcePool.length = 0;
|
|
567
|
+
await Promise.all(resources.map(async (resource) => await options.closeResource(resource)));
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
};
|
|
572
|
+
|
|
215
573
|
//#endregion
|
|
216
574
|
//#region src/core/execute/execute.ts
|
|
217
575
|
const mapColumnToJSON = (column, serializer, options) => ({ [column]: (value) => {
|
|
@@ -250,26 +608,63 @@ var BatchCommandNoChangesError = class BatchCommandNoChangesError extends DumboE
|
|
|
250
608
|
}
|
|
251
609
|
};
|
|
252
610
|
const sqlExecutor = (sqlExecutor, options) => ({
|
|
253
|
-
query: (sql, queryOptions) => executeInNewDbClient((client) => sqlExecutor.query(client, sql, queryOptions),
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
611
|
+
query: (sql, queryOptions) => executeInNewDbClient((client) => sqlExecutor.query(client, sql, queryOptions), {
|
|
612
|
+
...options,
|
|
613
|
+
...queryOptions
|
|
614
|
+
}),
|
|
615
|
+
batchQuery: (sqls, queryOptions) => executeInNewDbClient((client) => sqlExecutor.batchQuery(client, sqls, queryOptions), {
|
|
616
|
+
...options,
|
|
617
|
+
...queryOptions
|
|
618
|
+
}),
|
|
619
|
+
command: (sql, commandOptions) => executeInNewDbClient((client) => sqlExecutor.command(client, sql, commandOptions), {
|
|
620
|
+
...options,
|
|
621
|
+
...commandOptions
|
|
622
|
+
}),
|
|
623
|
+
batchCommand: (sqls, commandOptions) => executeInNewDbClient((client) => sqlExecutor.batchCommand(client, sqls, commandOptions), {
|
|
624
|
+
...options,
|
|
625
|
+
...commandOptions
|
|
626
|
+
})
|
|
257
627
|
});
|
|
258
628
|
const sqlExecutorInNewConnection = (options) => ({
|
|
259
|
-
query: (sql, queryOptions) => executeInNewConnection((connection) => connection.execute.query(sql, queryOptions),
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
629
|
+
query: (sql, queryOptions) => executeInNewConnection((connection) => connection.execute.query(sql, queryOptions), {
|
|
630
|
+
...options,
|
|
631
|
+
...queryOptions
|
|
632
|
+
}),
|
|
633
|
+
batchQuery: (sqls, queryOptions) => executeInNewConnection((connection) => connection.execute.batchQuery(sqls, queryOptions), {
|
|
634
|
+
...options,
|
|
635
|
+
...queryOptions
|
|
636
|
+
}),
|
|
637
|
+
command: (sql, commandOptions) => executeInNewConnection((connection) => connection.execute.command(sql, commandOptions), {
|
|
638
|
+
...options,
|
|
639
|
+
...commandOptions
|
|
640
|
+
}),
|
|
641
|
+
batchCommand: (sqls, commandOptions) => executeInNewConnection((connection) => connection.execute.batchCommand(sqls, commandOptions), {
|
|
642
|
+
...options,
|
|
643
|
+
...commandOptions
|
|
644
|
+
})
|
|
263
645
|
});
|
|
264
646
|
const sqlExecutorInAmbientConnection = (options) => ({
|
|
265
|
-
query: (sql, queryOptions) => executeInAmbientConnection((connection) => connection.execute.query(sql, queryOptions),
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
647
|
+
query: (sql, queryOptions) => executeInAmbientConnection((connection) => connection.execute.query(sql, queryOptions), {
|
|
648
|
+
...options,
|
|
649
|
+
...queryOptions
|
|
650
|
+
}),
|
|
651
|
+
batchQuery: (sqls, queryOptions) => executeInAmbientConnection((connection) => connection.execute.batchQuery(sqls, queryOptions), {
|
|
652
|
+
...options,
|
|
653
|
+
...queryOptions
|
|
654
|
+
}),
|
|
655
|
+
command: (sql, commandOptions) => executeInAmbientConnection((connection) => connection.execute.command(sql, commandOptions), {
|
|
656
|
+
...options,
|
|
657
|
+
...commandOptions
|
|
658
|
+
}),
|
|
659
|
+
batchCommand: (sqls, commandOptions) => executeInAmbientConnection((connection) => connection.execute.batchCommand(sqls, commandOptions), {
|
|
660
|
+
...options,
|
|
661
|
+
...commandOptions
|
|
662
|
+
})
|
|
269
663
|
});
|
|
270
664
|
const executeInNewDbClient = async (handle, options) => {
|
|
665
|
+
Abort.throwIfAborted(options);
|
|
271
666
|
const { connect, close } = options;
|
|
272
|
-
const client = await connect();
|
|
667
|
+
const client = await connect({ abort: Abort.from(options) });
|
|
273
668
|
try {
|
|
274
669
|
return await handle(client);
|
|
275
670
|
} catch (error) {
|
|
@@ -278,7 +673,8 @@ const executeInNewDbClient = async (handle, options) => {
|
|
|
278
673
|
}
|
|
279
674
|
};
|
|
280
675
|
const executeInNewConnection = async (handle, options) => {
|
|
281
|
-
|
|
676
|
+
Abort.throwIfAborted(options);
|
|
677
|
+
const connection = await options.connection({ abort: Abort.from(options) });
|
|
282
678
|
try {
|
|
283
679
|
return await handle(connection);
|
|
284
680
|
} finally {
|
|
@@ -286,10 +682,8 @@ const executeInNewConnection = async (handle, options) => {
|
|
|
286
682
|
}
|
|
287
683
|
};
|
|
288
684
|
const executeInAmbientConnection = async (handle, options) => {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
return await handle(connection);
|
|
292
|
-
} finally {}
|
|
685
|
+
Abort.throwIfAborted(options);
|
|
686
|
+
return handle(await options.connection({ abort: Abort.from(options) }));
|
|
293
687
|
};
|
|
294
688
|
|
|
295
689
|
//#endregion
|
|
@@ -357,10 +751,10 @@ const toTransactionResult = (transactionResult) => transactionResult !== void 0
|
|
|
357
751
|
success: true,
|
|
358
752
|
result: transactionResult
|
|
359
753
|
};
|
|
360
|
-
const executeInTransaction = async (transaction, handle) => {
|
|
754
|
+
const executeInTransaction = async (transaction, handle, context = { abort: Abort.never }) => {
|
|
361
755
|
await transaction.begin();
|
|
362
756
|
try {
|
|
363
|
-
const { success, result } = toTransactionResult(await handle(transaction));
|
|
757
|
+
const { success, result } = toTransactionResult(await handle(transaction, context));
|
|
364
758
|
if (success) await transaction.commit();
|
|
365
759
|
else await transaction.rollback();
|
|
366
760
|
return result;
|
|
@@ -369,18 +763,32 @@ const executeInTransaction = async (transaction, handle) => {
|
|
|
369
763
|
throw e;
|
|
370
764
|
}
|
|
371
765
|
};
|
|
766
|
+
const executeInNestedTransaction = async (transaction, handle, options, context) => {
|
|
767
|
+
Abort.throwIfAborted(options);
|
|
768
|
+
if (!(options?.allowNestedTransactions ?? transaction._transactionOptions.allowNestedTransactions ?? false)) throw new InvalidOperationError("Cannot start a nested transaction: allowNestedTransactions is false. Set transactionOptions: { allowNestedTransactions: true } on your pool or connection.");
|
|
769
|
+
return executeInTransaction(transaction, handle, context);
|
|
770
|
+
};
|
|
372
771
|
const transactionFactoryWithDbClient = (connect, initTransaction) => {
|
|
373
772
|
let currentTransaction = void 0;
|
|
374
|
-
const getOrInitCurrentTransaction = (options) =>
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
773
|
+
const getOrInitCurrentTransaction = (options) => {
|
|
774
|
+
Abort.throwIfAborted(options);
|
|
775
|
+
if (currentTransaction) return currentTransaction;
|
|
776
|
+
currentTransaction = initTransaction(connect({ abort: Abort.from(options) }), {
|
|
777
|
+
close: () => {
|
|
778
|
+
currentTransaction = void 0;
|
|
779
|
+
return Promise.resolve();
|
|
780
|
+
},
|
|
781
|
+
...options ?? {}
|
|
782
|
+
});
|
|
783
|
+
return currentTransaction;
|
|
784
|
+
};
|
|
381
785
|
return {
|
|
382
786
|
transaction: getOrInitCurrentTransaction,
|
|
383
|
-
withTransaction: (handle, options) =>
|
|
787
|
+
withTransaction: (handle, options) => {
|
|
788
|
+
const abortRejection = Abort.rejectIfAborted(options);
|
|
789
|
+
if (abortRejection) return abortRejection;
|
|
790
|
+
return executeInTransaction(getOrInitCurrentTransaction(options), handle, { abort: Abort.from(options) });
|
|
791
|
+
}
|
|
384
792
|
};
|
|
385
793
|
};
|
|
386
794
|
const wrapInConnectionClosure = async (connection, handle) => {
|
|
@@ -392,7 +800,8 @@ const wrapInConnectionClosure = async (connection, handle) => {
|
|
|
392
800
|
};
|
|
393
801
|
const transactionFactoryWithNewConnection = (connect) => ({
|
|
394
802
|
transaction: (options) => {
|
|
395
|
-
|
|
803
|
+
Abort.throwIfAborted(options);
|
|
804
|
+
const connection = connect({ abort: Abort.from(options) });
|
|
396
805
|
const transaction = connection.transaction(options);
|
|
397
806
|
return {
|
|
398
807
|
...transaction,
|
|
@@ -401,14 +810,17 @@ const transactionFactoryWithNewConnection = (connect) => ({
|
|
|
401
810
|
};
|
|
402
811
|
},
|
|
403
812
|
withTransaction: (handle, options) => {
|
|
404
|
-
const
|
|
813
|
+
const abortRejection = Abort.rejectIfAborted(options);
|
|
814
|
+
if (abortRejection) return abortRejection;
|
|
815
|
+
const connection = connect({ abort: Abort.from(options) });
|
|
405
816
|
const withTx = connection.withTransaction;
|
|
406
817
|
return wrapInConnectionClosure(connection, () => withTx(handle, options));
|
|
407
818
|
}
|
|
408
819
|
});
|
|
409
820
|
const transactionFactoryWithAmbientConnection = (connect) => ({
|
|
410
821
|
transaction: (options) => {
|
|
411
|
-
|
|
822
|
+
Abort.throwIfAborted(options);
|
|
823
|
+
const transaction = connect({ abort: Abort.from(options) }).transaction(options);
|
|
412
824
|
return {
|
|
413
825
|
...transaction,
|
|
414
826
|
commit: () => transaction.commit(),
|
|
@@ -416,7 +828,9 @@ const transactionFactoryWithAmbientConnection = (connect) => ({
|
|
|
416
828
|
};
|
|
417
829
|
},
|
|
418
830
|
withTransaction: (handle, options) => {
|
|
419
|
-
const
|
|
831
|
+
const abortRejection = Abort.rejectIfAborted(options);
|
|
832
|
+
if (abortRejection) return abortRejection;
|
|
833
|
+
const withTx = connect({ abort: Abort.from(options) }).withTransaction;
|
|
420
834
|
return withTx(handle, options);
|
|
421
835
|
}
|
|
422
836
|
});
|
|
@@ -424,19 +838,21 @@ const transactionFactoryWithAsyncAmbientConnection = (driverType, connect, close
|
|
|
424
838
|
close ??= () => Promise.resolve();
|
|
425
839
|
return {
|
|
426
840
|
transaction: (options) => {
|
|
841
|
+
Abort.throwIfAborted(options);
|
|
427
842
|
let conn = null;
|
|
428
843
|
let innerTx = null;
|
|
429
844
|
let connectingPromise = null;
|
|
430
845
|
const ensureConnection = async () => {
|
|
431
846
|
if (conn) return innerTx;
|
|
432
847
|
if (!connectingPromise) connectingPromise = (async () => {
|
|
433
|
-
|
|
848
|
+
Abort.throwIfAborted(options);
|
|
849
|
+
conn = await connect({ abort: Abort.from(options) });
|
|
434
850
|
innerTx = conn.transaction(options);
|
|
435
851
|
})();
|
|
436
852
|
await connectingPromise;
|
|
437
853
|
return innerTx;
|
|
438
854
|
};
|
|
439
|
-
|
|
855
|
+
const tx = {
|
|
440
856
|
driverType,
|
|
441
857
|
get connection() {
|
|
442
858
|
if (!conn) throw new Error("Transaction not started - call begin() first");
|
|
@@ -478,11 +894,14 @@ const transactionFactoryWithAsyncAmbientConnection = (driverType, connect, close
|
|
|
478
894
|
if (conn) await close(conn);
|
|
479
895
|
}
|
|
480
896
|
},
|
|
481
|
-
|
|
897
|
+
withTransaction: (handle, options) => executeInNestedTransaction(tx, handle, options, { abort: Abort.from(options) }),
|
|
898
|
+
_transactionOptions: options ?? {}
|
|
482
899
|
};
|
|
900
|
+
return tx;
|
|
483
901
|
},
|
|
484
902
|
withTransaction: async (handle, options) => {
|
|
485
|
-
|
|
903
|
+
Abort.throwIfAborted(options);
|
|
904
|
+
const conn = await connect({ abort: Abort.from(options) });
|
|
486
905
|
try {
|
|
487
906
|
const withTx = conn.withTransaction;
|
|
488
907
|
return await withTx(handle, options);
|
|
@@ -499,7 +918,10 @@ const createAmbientConnection = (options) => {
|
|
|
499
918
|
const { driverType, client, executor, initTransaction, serializer } = options;
|
|
500
919
|
const clientPromise = Promise.resolve(client);
|
|
501
920
|
const closePromise = Promise.resolve();
|
|
502
|
-
const open = () =>
|
|
921
|
+
const open = (context) => {
|
|
922
|
+
Abort.throwIfAborted(context);
|
|
923
|
+
return clientPromise;
|
|
924
|
+
};
|
|
503
925
|
const close = () => closePromise;
|
|
504
926
|
const typedConnection = {
|
|
505
927
|
driverType,
|
|
@@ -515,9 +937,10 @@ const createSingletonConnection = (options) => {
|
|
|
515
937
|
const { driverType, connect, close, initTransaction, executor, serializer } = options;
|
|
516
938
|
let client = null;
|
|
517
939
|
let connectPromise = null;
|
|
518
|
-
const getClient = async () => {
|
|
940
|
+
const getClient = async (context) => {
|
|
941
|
+
Abort.throwIfAborted(context);
|
|
519
942
|
if (client) return client;
|
|
520
|
-
if (!connectPromise) connectPromise = connect().then((c) => {
|
|
943
|
+
if (!connectPromise) connectPromise = connect(context ?? { abort: Abort.never }).then((c) => {
|
|
521
944
|
client = c;
|
|
522
945
|
return c;
|
|
523
946
|
});
|
|
@@ -535,12 +958,16 @@ const createSingletonConnection = (options) => {
|
|
|
535
958
|
};
|
|
536
959
|
const createTransientConnection = (options) => {
|
|
537
960
|
const { driverType, open, close, initTransaction, executor, serializer } = options;
|
|
961
|
+
const openIfNotAborted = (context) => {
|
|
962
|
+
Abort.throwIfAborted(context);
|
|
963
|
+
return open(context);
|
|
964
|
+
};
|
|
538
965
|
const typedConnection = {
|
|
539
966
|
driverType,
|
|
540
|
-
open,
|
|
967
|
+
open: openIfNotAborted,
|
|
541
968
|
close,
|
|
542
|
-
...transactionFactoryWithDbClient(
|
|
543
|
-
execute: sqlExecutor(executor({ serializer }), { connect:
|
|
969
|
+
...transactionFactoryWithDbClient(openIfNotAborted, initTransaction(() => typedConnection)),
|
|
970
|
+
execute: sqlExecutor(executor({ serializer }), { connect: openIfNotAborted }),
|
|
544
971
|
_transactionType: void 0
|
|
545
972
|
};
|
|
546
973
|
return typedConnection;
|
|
@@ -549,9 +976,10 @@ const createConnection = (options) => {
|
|
|
549
976
|
const { driverType, connect, close, initTransaction, executor, serializer } = options;
|
|
550
977
|
let client = null;
|
|
551
978
|
let connectPromise = null;
|
|
552
|
-
const getClient = async () => {
|
|
979
|
+
const getClient = async (context) => {
|
|
980
|
+
Abort.throwIfAborted(context);
|
|
553
981
|
if (client) return client;
|
|
554
|
-
if (!connectPromise) connectPromise = connect().then((c) => {
|
|
982
|
+
if (!connectPromise) connectPromise = connect(context ?? { abort: Abort.never }).then((c) => {
|
|
555
983
|
client = c;
|
|
556
984
|
return c;
|
|
557
985
|
});
|
|
@@ -568,174 +996,6 @@ const createConnection = (options) => {
|
|
|
568
996
|
return typedConnection;
|
|
569
997
|
};
|
|
570
998
|
|
|
571
|
-
//#endregion
|
|
572
|
-
//#region src/core/taskProcessing/taskProcessor.ts
|
|
573
|
-
var TaskProcessor = class {
|
|
574
|
-
queue = [];
|
|
575
|
-
isProcessing = false;
|
|
576
|
-
activeTasks = 0;
|
|
577
|
-
activeGroups = /* @__PURE__ */ new Set();
|
|
578
|
-
options;
|
|
579
|
-
stopped = false;
|
|
580
|
-
constructor(options) {
|
|
581
|
-
this.options = options;
|
|
582
|
-
}
|
|
583
|
-
enqueue(task, options) {
|
|
584
|
-
if (this.stopped) return Promise.reject(new DumboError("TaskProcessor has been stopped"));
|
|
585
|
-
if (this.queue.length >= this.options.maxQueueSize) return Promise.reject(new TransientDatabaseError("Too many pending connections. Please try again later."));
|
|
586
|
-
return this.schedule(task, options);
|
|
587
|
-
}
|
|
588
|
-
waitForEndOfProcessing() {
|
|
589
|
-
return this.schedule(({ ack }) => Promise.resolve(ack()));
|
|
590
|
-
}
|
|
591
|
-
async stop(options) {
|
|
592
|
-
if (this.stopped) return;
|
|
593
|
-
this.stopped = true;
|
|
594
|
-
this.queue.length = 0;
|
|
595
|
-
this.activeGroups.clear();
|
|
596
|
-
if (!options?.force) await this.waitForEndOfProcessing();
|
|
597
|
-
}
|
|
598
|
-
schedule(task, options) {
|
|
599
|
-
return promiseWithDeadline((resolve, reject) => {
|
|
600
|
-
const taskWithContext = () => {
|
|
601
|
-
return new Promise((resolveTask, failTask) => {
|
|
602
|
-
task({ ack: resolveTask }).then(resolve).catch((err) => {
|
|
603
|
-
failTask(err);
|
|
604
|
-
reject(err);
|
|
605
|
-
});
|
|
606
|
-
});
|
|
607
|
-
};
|
|
608
|
-
this.queue.push({
|
|
609
|
-
task: taskWithContext,
|
|
610
|
-
options
|
|
611
|
-
});
|
|
612
|
-
if (!this.isProcessing) this.ensureProcessing();
|
|
613
|
-
}, { deadline: this.options.maxTaskIdleTime });
|
|
614
|
-
}
|
|
615
|
-
ensureProcessing() {
|
|
616
|
-
if (this.isProcessing) return;
|
|
617
|
-
this.isProcessing = true;
|
|
618
|
-
this.processQueue();
|
|
619
|
-
}
|
|
620
|
-
processQueue() {
|
|
621
|
-
try {
|
|
622
|
-
while (this.activeTasks < this.options.maxActiveTasks && this.queue.length > 0) {
|
|
623
|
-
const item = this.takeFirstAvailableItem();
|
|
624
|
-
if (item === null) return;
|
|
625
|
-
const groupId = item.options?.taskGroupId;
|
|
626
|
-
if (groupId) this.activeGroups.add(groupId);
|
|
627
|
-
this.activeTasks++;
|
|
628
|
-
this.executeItem(item);
|
|
629
|
-
}
|
|
630
|
-
} catch (error) {
|
|
631
|
-
console.error(error);
|
|
632
|
-
throw error;
|
|
633
|
-
} finally {
|
|
634
|
-
this.isProcessing = false;
|
|
635
|
-
if (this.hasItemsToProcess() && this.activeTasks < this.options.maxActiveTasks) this.ensureProcessing();
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
async executeItem({ task, options }) {
|
|
639
|
-
try {
|
|
640
|
-
await task();
|
|
641
|
-
} finally {
|
|
642
|
-
this.activeTasks--;
|
|
643
|
-
if (options && options.taskGroupId) this.activeGroups.delete(options.taskGroupId);
|
|
644
|
-
this.ensureProcessing();
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
takeFirstAvailableItem = () => {
|
|
648
|
-
const taskIndex = this.queue.findIndex((item) => !item.options?.taskGroupId || !this.activeGroups.has(item.options.taskGroupId));
|
|
649
|
-
if (taskIndex === -1) return null;
|
|
650
|
-
const [item] = this.queue.splice(taskIndex, 1);
|
|
651
|
-
return item ?? null;
|
|
652
|
-
};
|
|
653
|
-
hasItemsToProcess = () => this.queue.findIndex((item) => !item.options?.taskGroupId || !this.activeGroups.has(item.options.taskGroupId)) !== -1;
|
|
654
|
-
};
|
|
655
|
-
const DEFAULT_PROMISE_DEADLINE = 2147483647;
|
|
656
|
-
const promiseWithDeadline = (executor, options) => {
|
|
657
|
-
return new Promise((resolve, reject) => {
|
|
658
|
-
let taskStarted = false;
|
|
659
|
-
let timeoutId = null;
|
|
660
|
-
const deadline = options.deadline ?? DEFAULT_PROMISE_DEADLINE;
|
|
661
|
-
timeoutId = setTimeout(() => {
|
|
662
|
-
if (!taskStarted) reject(/* @__PURE__ */ new Error("Task was not started within the maximum waiting time"));
|
|
663
|
-
}, deadline);
|
|
664
|
-
timeoutId.unref();
|
|
665
|
-
executor((value) => {
|
|
666
|
-
taskStarted = true;
|
|
667
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
668
|
-
timeoutId = null;
|
|
669
|
-
resolve(value);
|
|
670
|
-
}, (reason) => {
|
|
671
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
672
|
-
timeoutId = null;
|
|
673
|
-
reject(reason);
|
|
674
|
-
});
|
|
675
|
-
});
|
|
676
|
-
};
|
|
677
|
-
|
|
678
|
-
//#endregion
|
|
679
|
-
//#region src/core/taskProcessing/executionGuards.ts
|
|
680
|
-
const guardBoundedAccess = (getResource, options) => {
|
|
681
|
-
let isStopped = false;
|
|
682
|
-
const taskProcessor = new TaskProcessor({
|
|
683
|
-
maxActiveTasks: options.maxResources,
|
|
684
|
-
maxQueueSize: options.maxQueueSize ?? 1e3
|
|
685
|
-
});
|
|
686
|
-
const resourcePool = [];
|
|
687
|
-
const allResources = /* @__PURE__ */ new Set();
|
|
688
|
-
const ackCallbacks = /* @__PURE__ */ new Map();
|
|
689
|
-
const acquire = async () => taskProcessor.enqueue(async ({ ack }) => {
|
|
690
|
-
try {
|
|
691
|
-
let resource;
|
|
692
|
-
if (options.reuseResources) resource = resourcePool.pop();
|
|
693
|
-
if (!resource) {
|
|
694
|
-
resource = await getResource();
|
|
695
|
-
allResources.add(resource);
|
|
696
|
-
}
|
|
697
|
-
ackCallbacks.set(resource, ack);
|
|
698
|
-
return resource;
|
|
699
|
-
} catch (e) {
|
|
700
|
-
ack();
|
|
701
|
-
throw e;
|
|
702
|
-
}
|
|
703
|
-
});
|
|
704
|
-
const release = (resource) => {
|
|
705
|
-
const ack = ackCallbacks.get(resource);
|
|
706
|
-
if (ack) {
|
|
707
|
-
ackCallbacks.delete(resource);
|
|
708
|
-
if (options.reuseResources) resourcePool.push(resource);
|
|
709
|
-
ack();
|
|
710
|
-
}
|
|
711
|
-
};
|
|
712
|
-
const execute = async (operation) => {
|
|
713
|
-
const resource = await acquire();
|
|
714
|
-
try {
|
|
715
|
-
return await operation(resource);
|
|
716
|
-
} finally {
|
|
717
|
-
release(resource);
|
|
718
|
-
}
|
|
719
|
-
};
|
|
720
|
-
return {
|
|
721
|
-
acquire,
|
|
722
|
-
release,
|
|
723
|
-
execute,
|
|
724
|
-
waitForIdle: () => taskProcessor.waitForEndOfProcessing(),
|
|
725
|
-
stop: async (stopOptions) => {
|
|
726
|
-
if (isStopped) return;
|
|
727
|
-
isStopped = true;
|
|
728
|
-
if (options?.closeResource) {
|
|
729
|
-
const resources = [...allResources];
|
|
730
|
-
allResources.clear();
|
|
731
|
-
resourcePool.length = 0;
|
|
732
|
-
await Promise.all(resources.map(async (resource) => await options.closeResource(resource)));
|
|
733
|
-
}
|
|
734
|
-
await taskProcessor.stop(stopOptions);
|
|
735
|
-
}
|
|
736
|
-
};
|
|
737
|
-
};
|
|
738
|
-
|
|
739
999
|
//#endregion
|
|
740
1000
|
//#region src/core/connections/pool.ts
|
|
741
1001
|
const wrapPooledConnection = (conn, onClose) => ({
|
|
@@ -749,7 +1009,10 @@ const createAmbientConnectionPool = (options) => {
|
|
|
749
1009
|
getConnection: () => connection,
|
|
750
1010
|
execute: connection.execute,
|
|
751
1011
|
transaction: (options) => connection.transaction(options),
|
|
752
|
-
withConnection: (handle,
|
|
1012
|
+
withConnection: (handle, options) => {
|
|
1013
|
+
Abort.throwIfAborted(options);
|
|
1014
|
+
return handle(connection, { abort: Abort.from(options) });
|
|
1015
|
+
},
|
|
753
1016
|
withTransaction: (handle, options) => {
|
|
754
1017
|
const withTx = connection.withTransaction;
|
|
755
1018
|
return withTx(handle, options);
|
|
@@ -760,48 +1023,45 @@ const createSingletonConnectionPool = (options) => {
|
|
|
760
1023
|
const { driverType, getConnection } = options;
|
|
761
1024
|
let connectionPromise = null;
|
|
762
1025
|
let closed = false;
|
|
763
|
-
const
|
|
1026
|
+
const operationGuard = guardConcurrentAccess();
|
|
764
1027
|
const closedError = () => /* @__PURE__ */ new Error("Singleton connection pool has been closed");
|
|
765
|
-
const
|
|
1028
|
+
const executeIfOpen = async (operation, operationOptions) => {
|
|
766
1029
|
if (closed) throw closedError();
|
|
767
|
-
|
|
768
|
-
activeOperations.add(activeOperation);
|
|
769
|
-
try {
|
|
770
|
-
return await activeOperation;
|
|
771
|
-
} finally {
|
|
772
|
-
activeOperations.delete(activeOperation);
|
|
773
|
-
}
|
|
1030
|
+
return operationGuard.execute(operation, operationOptions);
|
|
774
1031
|
};
|
|
775
|
-
const getExistingOrNewConnection = () => {
|
|
776
|
-
if (!connectionPromise) connectionPromise ??= Promise.resolve(getConnection());
|
|
1032
|
+
const getExistingOrNewConnection = (context) => {
|
|
1033
|
+
if (!connectionPromise) connectionPromise ??= Promise.resolve(getConnection(context));
|
|
777
1034
|
return connectionPromise;
|
|
778
1035
|
};
|
|
779
1036
|
const innerTransactionFactory = transactionFactoryWithAsyncAmbientConnection(options.driverType, getExistingOrNewConnection, options.closeConnection);
|
|
780
1037
|
return {
|
|
781
1038
|
driverType,
|
|
782
|
-
connection: () =>
|
|
1039
|
+
connection: (connectionOptions) => executeIfOpen((context) => getExistingOrNewConnection(context).then((conn) => wrapPooledConnection(conn, () => Promise.resolve())), connectionOptions),
|
|
783
1040
|
execute: (() => {
|
|
784
1041
|
const ambientExecutor = sqlExecutorInAmbientConnection({
|
|
785
1042
|
driverType,
|
|
786
1043
|
connection: getExistingOrNewConnection
|
|
787
1044
|
});
|
|
788
1045
|
return {
|
|
789
|
-
query: (sql, opts) =>
|
|
790
|
-
batchQuery: (sqls, opts) =>
|
|
791
|
-
command: (sql, opts) =>
|
|
792
|
-
batchCommand: (sqls, opts) =>
|
|
1046
|
+
query: (sql, opts) => executeIfOpen(() => ambientExecutor.query(sql, opts), opts),
|
|
1047
|
+
batchQuery: (sqls, opts) => executeIfOpen(() => ambientExecutor.batchQuery(sqls, opts), opts),
|
|
1048
|
+
command: (sql, opts) => executeIfOpen(() => ambientExecutor.command(sql, opts), opts),
|
|
1049
|
+
batchCommand: (sqls, opts) => executeIfOpen(() => ambientExecutor.batchCommand(sqls, opts), opts)
|
|
793
1050
|
};
|
|
794
1051
|
})(),
|
|
795
|
-
withConnection: (handle,
|
|
1052
|
+
withConnection: (handle, options) => executeIfOpen((context) => executeInAmbientConnection((connection) => handle(connection, context), {
|
|
1053
|
+
connection: getExistingOrNewConnection,
|
|
1054
|
+
...options
|
|
1055
|
+
}), options),
|
|
796
1056
|
transaction: (transactionOptions) => {
|
|
797
1057
|
if (closed) throw closedError();
|
|
798
1058
|
return innerTransactionFactory.transaction(transactionOptions);
|
|
799
1059
|
},
|
|
800
|
-
withTransaction: (handle, transactionOptions) =>
|
|
1060
|
+
withTransaction: (handle, transactionOptions) => executeIfOpen((context) => innerTransactionFactory.withTransaction((tx) => handle(tx, context), transactionOptions), transactionOptions),
|
|
801
1061
|
close: async (closeOptions) => {
|
|
802
1062
|
if (closed) return;
|
|
803
1063
|
closed = true;
|
|
804
|
-
|
|
1064
|
+
await operationGuard.stop(closeOptions);
|
|
805
1065
|
if (!connectionPromise) return;
|
|
806
1066
|
const connection = await connectionPromise;
|
|
807
1067
|
connectionPromise = null;
|
|
@@ -811,63 +1071,49 @@ const createSingletonConnectionPool = (options) => {
|
|
|
811
1071
|
};
|
|
812
1072
|
const createBoundedConnectionPool = (options) => {
|
|
813
1073
|
const { driverType, maxConnections } = options;
|
|
814
|
-
const
|
|
815
|
-
const getTrackedConnection = async () => {
|
|
816
|
-
const connection = await options.getConnection();
|
|
817
|
-
allConnections.add(connection);
|
|
818
|
-
return connection;
|
|
819
|
-
};
|
|
820
|
-
const guardMaxConnections = guardBoundedAccess(getTrackedConnection, {
|
|
1074
|
+
const guardMaxConnections = guardBoundedAccess(options.getConnection, {
|
|
821
1075
|
maxResources: maxConnections,
|
|
822
|
-
reuseResources: true
|
|
1076
|
+
reuseResources: true,
|
|
1077
|
+
closeResource: (connection) => connection.close()
|
|
823
1078
|
});
|
|
824
1079
|
let closed = false;
|
|
825
1080
|
const closedError = () => /* @__PURE__ */ new Error("Bounded connection pool has been closed");
|
|
826
1081
|
const ensureOpen = () => {
|
|
827
1082
|
if (closed) throw closedError();
|
|
828
1083
|
};
|
|
829
|
-
const
|
|
830
|
-
const connections = [...allConnections];
|
|
831
|
-
allConnections.clear();
|
|
832
|
-
await Promise.all(connections.map((conn) => conn.close()));
|
|
833
|
-
};
|
|
834
|
-
const executeWithPooling = async (operation) => {
|
|
1084
|
+
const executeWithPooledConnection = async (operation, operationOptions) => {
|
|
835
1085
|
ensureOpen();
|
|
836
|
-
|
|
837
|
-
try {
|
|
838
|
-
return await operation(conn);
|
|
839
|
-
} finally {
|
|
840
|
-
guardMaxConnections.release(conn);
|
|
841
|
-
}
|
|
1086
|
+
return guardMaxConnections.execute(operation, operationOptions);
|
|
842
1087
|
};
|
|
843
1088
|
return {
|
|
844
1089
|
driverType,
|
|
845
|
-
connection: async () => {
|
|
1090
|
+
connection: async (connectionOptions) => {
|
|
846
1091
|
ensureOpen();
|
|
847
|
-
const conn = await guardMaxConnections.acquire();
|
|
1092
|
+
const conn = await guardMaxConnections.acquire(connectionOptions);
|
|
848
1093
|
return wrapPooledConnection(conn, () => Promise.resolve(guardMaxConnections.release(conn)));
|
|
849
1094
|
},
|
|
850
1095
|
execute: {
|
|
851
|
-
query: (sql, opts) =>
|
|
852
|
-
batchQuery: (sqls, opts) =>
|
|
853
|
-
command: (sql, opts) =>
|
|
854
|
-
batchCommand: (sqls, opts) =>
|
|
1096
|
+
query: (sql, opts) => executeWithPooledConnection((c) => c.execute.query(sql, opts), opts),
|
|
1097
|
+
batchQuery: (sqls, opts) => executeWithPooledConnection((c) => c.execute.batchQuery(sqls, opts), opts),
|
|
1098
|
+
command: (sql, opts) => executeWithPooledConnection((c) => c.execute.command(sql, opts), opts),
|
|
1099
|
+
batchCommand: (sqls, opts) => executeWithPooledConnection((c) => c.execute.batchCommand(sqls, opts), opts)
|
|
855
1100
|
},
|
|
856
|
-
withConnection:
|
|
1101
|
+
withConnection: executeWithPooledConnection,
|
|
857
1102
|
transaction: (transactionOptions) => {
|
|
858
1103
|
ensureOpen();
|
|
859
|
-
return transactionFactoryWithAsyncAmbientConnection(driverType, guardMaxConnections.acquire
|
|
1104
|
+
return transactionFactoryWithAsyncAmbientConnection(driverType, (context) => guardMaxConnections.acquire({
|
|
1105
|
+
...transactionOptions,
|
|
1106
|
+
abort: context.abort
|
|
1107
|
+
}), guardMaxConnections.release).transaction(transactionOptions);
|
|
860
1108
|
},
|
|
861
|
-
withTransaction: (handle, transactionOptions) =>
|
|
1109
|
+
withTransaction: (handle, transactionOptions) => executeWithPooledConnection((conn, context) => {
|
|
862
1110
|
const withTx = conn.withTransaction;
|
|
863
|
-
return withTx(handle, transactionOptions);
|
|
864
|
-
}),
|
|
1111
|
+
return withTx((tx) => handle(tx, context), transactionOptions);
|
|
1112
|
+
}, transactionOptions),
|
|
865
1113
|
close: async (closeOptions) => {
|
|
866
1114
|
if (closed) return;
|
|
867
1115
|
closed = true;
|
|
868
|
-
|
|
869
|
-
await guardMaxConnections.stop({ force: true });
|
|
870
|
-
await closeAllConnections();
|
|
1116
|
+
await guardMaxConnections.stop(closeOptions);
|
|
871
1117
|
}
|
|
872
1118
|
};
|
|
873
1119
|
};
|
|
@@ -882,16 +1128,22 @@ const createAlwaysNewConnectionPool = (options) => {
|
|
|
882
1128
|
const { driverType, getConnection, connectionOptions } = options;
|
|
883
1129
|
return createConnectionPool({
|
|
884
1130
|
driverType,
|
|
885
|
-
getConnection: () => connectionOptions ? getConnection(connectionOptions) : getConnection()
|
|
1131
|
+
getConnection: (context) => connectionOptions ? getConnection(connectionOptions, context) : getConnection(context)
|
|
886
1132
|
});
|
|
887
1133
|
};
|
|
888
1134
|
const createConnectionPool = (pool) => {
|
|
889
1135
|
const { driverType, getConnection } = pool;
|
|
890
|
-
const connection = "connection" in pool ? pool.connection : () =>
|
|
1136
|
+
const connection = "connection" in pool ? pool.connection : (options) => {
|
|
1137
|
+
Abort.throwIfAborted(options);
|
|
1138
|
+
return Promise.resolve(getConnection({ abort: Abort.from(options) }));
|
|
1139
|
+
};
|
|
891
1140
|
return {
|
|
892
1141
|
driverType,
|
|
893
1142
|
connection,
|
|
894
|
-
withConnection: "withConnection" in pool ? pool.withConnection : (handle,
|
|
1143
|
+
withConnection: "withConnection" in pool ? pool.withConnection : (handle, options) => executeInNewConnection((connection) => handle(connection, { abort: Abort.from(options) }), {
|
|
1144
|
+
connection,
|
|
1145
|
+
...options
|
|
1146
|
+
}),
|
|
895
1147
|
close: "close" in pool ? pool.close : () => Promise.resolve(),
|
|
896
1148
|
execute: "execute" in pool ? pool.execute : sqlExecutorInNewConnection({
|
|
897
1149
|
driverType,
|
|
@@ -2498,5 +2750,5 @@ function dumbo(options) {
|
|
|
2498
2750
|
}
|
|
2499
2751
|
|
|
2500
2752
|
//#endregion
|
|
2501
|
-
export { ANSISQLIdentifierQuote, ANSISQLParamPlaceholder, AdminShutdownError, AutoIncrementSQLColumnToken, BatchCommandNoChangesError, BigIntegerToken, BigSerialToken, CheckViolationError, ColumnTypeToken, ColumnURN, ColumnURNType, ConcurrencyError, ConnectionError, DataError, DatabaseSchemaURN, DatabaseSchemaURNType, DatabaseURN, DatabaseURNType, DeadlockError, DefaultMapSQLParamValueOptions, DumboDatabaseDriverRegistry, DumboDatabaseMetadataRegistry, DumboError, ExclusionViolationError, ExpandArrayProcessor, ExpandSQLInProcessor, ForeignKeyViolationError, FormatIdentifierProcessor, IndexURN, IndexURNType, InsufficientResourcesError, IntegerToken, IntegrityConstraintViolationError, InvalidOperationError, JSONBToken, JSONCodec, JSONParam, JSONReplacer, JSONReplacers, JSONReviver, JSONRevivers, JSONSerializer, LockNotAvailableError, LogLevel, LogStyle, MIGRATIONS_LOCK_ID, MapLiteralProcessor, NoDatabaseLock, NotNullViolationError, ParametrizedSQLBuilder, QueryCanceledError, RawSQL, SQL, SQLArray, SQLColumnToken, SQLColumnTypeTokens, SQLColumnTypeTokensFactory, SQLFormatter, SQLIdentifier, SQLIn, SQLLiteral, SQLPlain, SQLProcessor, SQLProcessorsRegistry, SQLToken, SQLValueMapper, SchemaComponentMigrator, SerialToken, SerializationError, SystemError, TableURN, TableURNType, TimestampToken, TimestamptzToken, TokenizedSQL, TransientDatabaseError, UniqueConstraintError, VarcharToken, ansiSqlReservedMap, canHandleDriverWithConnectionString, color, columnSchemaComponent, combineMigrations, composeJSONReplacers, composeJSONRevivers, count, createAlwaysNewConnectionPool, createAmbientConnection, createAmbientConnectionPool, createBoundedConnectionPool, createConnection, createConnectionPool, createSingletonClientConnectionPool, createSingletonConnection, createSingletonConnectionPool, createTransientConnection, databaseSchemaComponent, databaseSchemaSchemaComponent, databaseTransaction, defaultDatabaseLockOptions, defaultProcessorsRegistry, describeSQL, dumbo, dumboDatabaseDriverRegistry, dumboDatabaseMetadataRegistry$1 as dumboDatabaseMetadataRegistry, dumboSchema, executeInAmbientConnection, executeInNewConnection, executeInNewDbClient, executeInTransaction, exists, filterSchemaComponentsOfType, findSchemaComponentsOfType, first, firstOrNull, formatSQL, fromDatabaseDriverType, getDatabaseDriverName, getDatabaseMetadata, getDatabaseType, getDefaultDatabase, getDefaultDatabaseAsync, getDefaultMigratorOptionsFromRegistry, getFormatter, indexSchemaComponent, isSQL, isSchemaComponentOfType, isTokenizedSQL, jsonSerializer, mapANSISQLParamPlaceholder, mapColumnToBigint, mapColumnToDate, mapColumnToJSON, mapDefaultSQLColumnProcessors, mapRows, mapSQLIdentifier, mapSQLParamValue, mapSQLQueryResult, mapSchemaComponentsOfType, mapToCamelCase, migrationTableSchemaComponent, parseConnectionString, prettyJson, registerDefaultMigratorOptions, registerFormatter, relationship, resolveDatabaseMetadata, runSQLMigrations, schemaComponent, schemaComponentURN, single, singleOrNull, sqlExecutor, sqlExecutorInAmbientConnection, sqlExecutorInNewConnection, sqlMigration, tableSchemaComponent, toCamelCase, toDatabaseDriverType, tracer, transactionFactoryWithAmbientConnection, transactionFactoryWithAsyncAmbientConnection, transactionFactoryWithDbClient, transactionFactoryWithNewConnection, transactionNestingCounter };
|
|
2753
|
+
export { ANSISQLIdentifierQuote, ANSISQLParamPlaceholder, Abort, AdminShutdownError, AutoIncrementSQLColumnToken, BatchCommandNoChangesError, BigIntegerToken, BigSerialToken, CheckViolationError, ColumnTypeToken, ColumnURN, ColumnURNType, ConcurrencyError, ConnectionError, DataError, DatabaseSchemaURN, DatabaseSchemaURNType, DatabaseURN, DatabaseURNType, DeadlockError, DefaultMapSQLParamValueOptions, DumboDatabaseDriverRegistry, DumboDatabaseMetadataRegistry, DumboError, ExclusionViolationError, ExpandArrayProcessor, ExpandSQLInProcessor, ForeignKeyViolationError, FormatIdentifierProcessor, IndexURN, IndexURNType, InsufficientResourcesError, IntegerToken, IntegrityConstraintViolationError, InvalidOperationError, JSONBToken, JSONCodec, JSONParam, JSONReplacer, JSONReplacers, JSONReviver, JSONRevivers, JSONSerializer, LockNotAvailableError, LogLevel, LogStyle, MIGRATIONS_LOCK_ID, MapLiteralProcessor, NoDatabaseLock, NotNullViolationError, ParametrizedSQLBuilder, QueryCanceledError, RawSQL, SQL, SQLArray, SQLColumnToken, SQLColumnTypeTokens, SQLColumnTypeTokensFactory, SQLFormatter, SQLIdentifier, SQLIn, SQLLiteral, SQLPlain, SQLProcessor, SQLProcessorsRegistry, SQLToken, SQLValueMapper, SchemaComponentMigrator, SerialToken, SerializationError, SystemError, TableURN, TableURNType, TimestampToken, TimestamptzToken, TokenizedSQL, TransientDatabaseError, UniqueConstraintError, VarcharToken, ansiSqlReservedMap, canHandleDriverWithConnectionString, color, columnSchemaComponent, combineMigrations, composeJSONReplacers, composeJSONRevivers, count, createAlwaysNewConnectionPool, createAmbientConnection, createAmbientConnectionPool, createBoundedConnectionPool, createConnection, createConnectionPool, createSingletonClientConnectionPool, createSingletonConnection, createSingletonConnectionPool, createTransientConnection, databaseSchemaComponent, databaseSchemaSchemaComponent, databaseTransaction, defaultDatabaseLockOptions, defaultProcessorsRegistry, describeSQL, dumbo, dumboDatabaseDriverRegistry, dumboDatabaseMetadataRegistry$1 as dumboDatabaseMetadataRegistry, dumboSchema, executeInAmbientConnection, executeInNestedTransaction, executeInNewConnection, executeInNewDbClient, executeInTransaction, exists, filterSchemaComponentsOfType, findSchemaComponentsOfType, first, firstOrNull, formatSQL, fromDatabaseDriverType, getDatabaseDriverName, getDatabaseMetadata, getDatabaseType, getDefaultDatabase, getDefaultDatabaseAsync, getDefaultMigratorOptionsFromRegistry, getFormatter, indexSchemaComponent, isSQL, isSchemaComponentOfType, isTokenizedSQL, jsonSerializer, mapANSISQLParamPlaceholder, mapColumnToBigint, mapColumnToDate, mapColumnToJSON, mapDefaultSQLColumnProcessors, mapRows, mapSQLIdentifier, mapSQLParamValue, mapSQLQueryResult, mapSchemaComponentsOfType, mapToCamelCase, migrationTableSchemaComponent, parseConnectionString, prettyJson, registerDefaultMigratorOptions, registerFormatter, relationship, resolveDatabaseMetadata, runSQLMigrations, schemaComponent, schemaComponentURN, single, singleOrNull, sqlExecutor, sqlExecutorInAmbientConnection, sqlExecutorInNewConnection, sqlMigration, tableSchemaComponent, toCamelCase, toDatabaseDriverType, tracer, transactionFactoryWithAmbientConnection, transactionFactoryWithAsyncAmbientConnection, transactionFactoryWithDbClient, transactionFactoryWithNewConnection, transactionNestingCounter };
|
|
2502
2754
|
//# sourceMappingURL=index.js.map
|