@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.cjs
CHANGED
|
@@ -241,6 +241,364 @@ var InvalidOperationError = class InvalidOperationError extends DumboError {
|
|
|
241
241
|
}
|
|
242
242
|
};
|
|
243
243
|
|
|
244
|
+
//#endregion
|
|
245
|
+
//#region src/core/taskProcessing/abort.ts
|
|
246
|
+
const never = { signal: new AbortController().signal };
|
|
247
|
+
const from = (options) => options?.abort ?? never;
|
|
248
|
+
const getSignal = (abort) => "signal" in abort ? abort.signal : abort;
|
|
249
|
+
const reason = (abort) => {
|
|
250
|
+
const signal = getSignal(abort);
|
|
251
|
+
return signal.reason instanceof Error ? signal.reason : new DumboError(typeof signal.reason === "string" ? signal.reason : "Operation aborted");
|
|
252
|
+
};
|
|
253
|
+
const scope = (parent, onAbort) => {
|
|
254
|
+
const controller = new AbortController();
|
|
255
|
+
return {
|
|
256
|
+
abort: (reason) => controller.abort(reason),
|
|
257
|
+
dispose: onAbortSignal(parent, (reason) => {
|
|
258
|
+
controller.abort(reason);
|
|
259
|
+
onAbort?.(reason);
|
|
260
|
+
}),
|
|
261
|
+
signal: controller.signal
|
|
262
|
+
};
|
|
263
|
+
};
|
|
264
|
+
const execute = (operation, options) => {
|
|
265
|
+
const abort = options?.abort;
|
|
266
|
+
if (!abort) return operation();
|
|
267
|
+
const signal = abort.signal;
|
|
268
|
+
if (signal.aborted) return Promise.reject(reason(abort));
|
|
269
|
+
return new Promise((resolve, reject) => {
|
|
270
|
+
let finished = false;
|
|
271
|
+
const rejectOnAbort = () => {
|
|
272
|
+
if (finished) return;
|
|
273
|
+
finished = true;
|
|
274
|
+
reject(reason(abort));
|
|
275
|
+
};
|
|
276
|
+
signal.addEventListener("abort", rejectOnAbort, { once: true });
|
|
277
|
+
let operationPromise;
|
|
278
|
+
try {
|
|
279
|
+
operationPromise = operation();
|
|
280
|
+
} catch (error) {
|
|
281
|
+
finished = true;
|
|
282
|
+
signal.removeEventListener("abort", rejectOnAbort);
|
|
283
|
+
reject(error);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
operationPromise.then((result) => {
|
|
287
|
+
if (finished) return;
|
|
288
|
+
finished = true;
|
|
289
|
+
signal.removeEventListener("abort", rejectOnAbort);
|
|
290
|
+
resolve(result);
|
|
291
|
+
}).catch((error) => {
|
|
292
|
+
if (finished) return;
|
|
293
|
+
finished = true;
|
|
294
|
+
signal.removeEventListener("abort", rejectOnAbort);
|
|
295
|
+
reject(error);
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
};
|
|
299
|
+
const throwIfAborted = (options) => {
|
|
300
|
+
const abort = options?.abort;
|
|
301
|
+
if (abort?.signal.aborted) throw reason(abort);
|
|
302
|
+
};
|
|
303
|
+
const rejectIfAborted = (options) => {
|
|
304
|
+
const abort = options?.abort;
|
|
305
|
+
return abort?.signal.aborted ? Promise.reject(reason(abort)) : void 0;
|
|
306
|
+
};
|
|
307
|
+
const onAbortSignal = (abort, handle) => {
|
|
308
|
+
if (!abort) return () => {};
|
|
309
|
+
const signal = abort.signal;
|
|
310
|
+
if (signal.aborted) {
|
|
311
|
+
handle(reason(abort));
|
|
312
|
+
return () => {};
|
|
313
|
+
}
|
|
314
|
+
const abortListener = () => handle(reason(abort));
|
|
315
|
+
signal.addEventListener("abort", abortListener, { once: true });
|
|
316
|
+
return () => signal.removeEventListener("abort", abortListener);
|
|
317
|
+
};
|
|
318
|
+
const Abort = {
|
|
319
|
+
execute,
|
|
320
|
+
from,
|
|
321
|
+
never,
|
|
322
|
+
onAbort: onAbortSignal,
|
|
323
|
+
reason,
|
|
324
|
+
rejectIfAborted,
|
|
325
|
+
scope,
|
|
326
|
+
throwIfAborted
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
//#endregion
|
|
330
|
+
//#region src/core/taskProcessing/taskProcessor.ts
|
|
331
|
+
var TaskProcessor = class {
|
|
332
|
+
queue = [];
|
|
333
|
+
isProcessing = false;
|
|
334
|
+
activeTasks = 0;
|
|
335
|
+
activeGroups = /* @__PURE__ */ new Set();
|
|
336
|
+
options;
|
|
337
|
+
stopped = false;
|
|
338
|
+
idleWaiters = [];
|
|
339
|
+
activeTaskAbortCallbacks = /* @__PURE__ */ new Set();
|
|
340
|
+
constructor(options) {
|
|
341
|
+
this.options = options;
|
|
342
|
+
}
|
|
343
|
+
enqueue(task, options) {
|
|
344
|
+
if (options?.abort?.signal.aborted) return Promise.reject(Abort.reason(options.abort.signal));
|
|
345
|
+
if (this.stopped) return Promise.reject(new DumboError("TaskProcessor has been stopped"));
|
|
346
|
+
if (this.queue.length >= this.options.maxQueueSize) return Promise.reject(new TransientDatabaseError("Too many pending connections. Please try again later."));
|
|
347
|
+
return this.schedule(task, options);
|
|
348
|
+
}
|
|
349
|
+
waitForEndOfProcessing() {
|
|
350
|
+
if (this.activeTasks === 0 && this.queue.length === 0) return Promise.resolve();
|
|
351
|
+
return new Promise((resolve) => {
|
|
352
|
+
this.idleWaiters.push(resolve);
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
async stop(options) {
|
|
356
|
+
if (this.stopped) return;
|
|
357
|
+
this.stopped = true;
|
|
358
|
+
const stoppedError = new DumboError("TaskProcessor has been stopped");
|
|
359
|
+
for (const item of this.queue.splice(0)) {
|
|
360
|
+
item.abort(stoppedError);
|
|
361
|
+
item.reject(stoppedError);
|
|
362
|
+
}
|
|
363
|
+
this.activeGroups.clear();
|
|
364
|
+
if (options?.force) for (const abort of this.activeTaskAbortCallbacks) abort(stoppedError);
|
|
365
|
+
if (options?.force) return;
|
|
366
|
+
if (options?.closeDeadline === void 0) {
|
|
367
|
+
await this.waitForEndOfProcessing();
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
if (!await waitForProcessingOrDeadline(this.waitForEndOfProcessing(), options.closeDeadline)) for (const abort of this.activeTaskAbortCallbacks) abort(stoppedError);
|
|
371
|
+
}
|
|
372
|
+
schedule(task, options) {
|
|
373
|
+
return new Promise((resolve, reject) => {
|
|
374
|
+
let didQueueTimeout = false;
|
|
375
|
+
let didAbortBeforeStart = false;
|
|
376
|
+
let didStart = false;
|
|
377
|
+
let queueWaitTimer = noopQueueWaitTimer;
|
|
378
|
+
const abortScope = Abort.scope(options?.abort, (reason) => {
|
|
379
|
+
queueWaitTimer.cancel();
|
|
380
|
+
didAbortBeforeStart = !didStart;
|
|
381
|
+
reject(reason);
|
|
382
|
+
});
|
|
383
|
+
queueWaitTimer = createQueueWaitTimer(this.options.maxTaskIdleTime, (reason) => {
|
|
384
|
+
didQueueTimeout = true;
|
|
385
|
+
abortScope.abort(reason);
|
|
386
|
+
abortScope.dispose();
|
|
387
|
+
reject(reason);
|
|
388
|
+
});
|
|
389
|
+
const taskWithContext = () => {
|
|
390
|
+
return new Promise((resolveTask) => {
|
|
391
|
+
if (didQueueTimeout || didAbortBeforeStart) {
|
|
392
|
+
resolveTask();
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
let taskPromise;
|
|
396
|
+
try {
|
|
397
|
+
taskPromise = task({
|
|
398
|
+
ack: resolveTask,
|
|
399
|
+
abort: abortScope
|
|
400
|
+
});
|
|
401
|
+
} catch (err) {
|
|
402
|
+
abortScope.dispose();
|
|
403
|
+
resolveTask();
|
|
404
|
+
reject(err);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
taskPromise.then((result) => {
|
|
408
|
+
abortScope.dispose();
|
|
409
|
+
resolve(result);
|
|
410
|
+
}).catch((err) => {
|
|
411
|
+
abortScope.dispose();
|
|
412
|
+
resolveTask();
|
|
413
|
+
reject(err);
|
|
414
|
+
});
|
|
415
|
+
});
|
|
416
|
+
};
|
|
417
|
+
this.queue.push({
|
|
418
|
+
task: taskWithContext,
|
|
419
|
+
options,
|
|
420
|
+
reject: (reason) => {
|
|
421
|
+
queueWaitTimer.cancel();
|
|
422
|
+
abortScope.dispose();
|
|
423
|
+
reject(reason);
|
|
424
|
+
},
|
|
425
|
+
markStarted: () => {
|
|
426
|
+
didStart = true;
|
|
427
|
+
queueWaitTimer.cancel();
|
|
428
|
+
},
|
|
429
|
+
abort: (reason) => {
|
|
430
|
+
abortScope.dispose();
|
|
431
|
+
abortScope.abort(reason);
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
if (!this.isProcessing) this.ensureProcessing();
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
ensureProcessing() {
|
|
438
|
+
if (this.isProcessing) return;
|
|
439
|
+
this.isProcessing = true;
|
|
440
|
+
this.processQueue();
|
|
441
|
+
}
|
|
442
|
+
processQueue() {
|
|
443
|
+
try {
|
|
444
|
+
while (this.activeTasks < this.options.maxActiveTasks && this.queue.length > 0) {
|
|
445
|
+
const item = this.takeFirstAvailableItem();
|
|
446
|
+
if (item === null) return;
|
|
447
|
+
const groupId = item.options?.taskGroupId;
|
|
448
|
+
if (groupId) this.activeGroups.add(groupId);
|
|
449
|
+
this.activeTasks++;
|
|
450
|
+
this.executeItem(item);
|
|
451
|
+
}
|
|
452
|
+
} catch (error) {
|
|
453
|
+
console.error(error);
|
|
454
|
+
throw error;
|
|
455
|
+
} finally {
|
|
456
|
+
this.isProcessing = false;
|
|
457
|
+
if (this.hasItemsToProcess() && this.activeTasks < this.options.maxActiveTasks) this.ensureProcessing();
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
async executeItem({ task, options, markStarted, abort }) {
|
|
461
|
+
markStarted();
|
|
462
|
+
this.activeTaskAbortCallbacks.add(abort);
|
|
463
|
+
try {
|
|
464
|
+
await task();
|
|
465
|
+
} finally {
|
|
466
|
+
this.activeTaskAbortCallbacks.delete(abort);
|
|
467
|
+
this.activeTasks--;
|
|
468
|
+
if (options && options.taskGroupId) this.activeGroups.delete(options.taskGroupId);
|
|
469
|
+
this.resolveIdleWaiters();
|
|
470
|
+
this.ensureProcessing();
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
takeFirstAvailableItem = () => {
|
|
474
|
+
const taskIndex = this.queue.findIndex((item) => !item.options?.taskGroupId || !this.activeGroups.has(item.options.taskGroupId));
|
|
475
|
+
if (taskIndex === -1) return null;
|
|
476
|
+
const [item] = this.queue.splice(taskIndex, 1);
|
|
477
|
+
return item ?? null;
|
|
478
|
+
};
|
|
479
|
+
hasItemsToProcess = () => this.queue.findIndex((item) => !item.options?.taskGroupId || !this.activeGroups.has(item.options.taskGroupId)) !== -1;
|
|
480
|
+
resolveIdleWaiters = () => {
|
|
481
|
+
if (this.activeTasks > 0 || this.queue.length > 0) return;
|
|
482
|
+
const waiters = this.idleWaiters.splice(0);
|
|
483
|
+
for (const resolve of waiters) resolve();
|
|
484
|
+
};
|
|
485
|
+
};
|
|
486
|
+
const noopQueueWaitTimer = { cancel: () => {} };
|
|
487
|
+
const createQueueWaitTimer = (timeoutMs, reject) => {
|
|
488
|
+
if (timeoutMs === void 0) return noopQueueWaitTimer;
|
|
489
|
+
let timeoutId = setTimeout(() => {
|
|
490
|
+
reject(/* @__PURE__ */ new Error("Task was not started within the maximum waiting time"));
|
|
491
|
+
}, timeoutMs);
|
|
492
|
+
timeoutId.unref();
|
|
493
|
+
return { cancel: () => {
|
|
494
|
+
if (!timeoutId) return;
|
|
495
|
+
clearTimeout(timeoutId);
|
|
496
|
+
timeoutId = null;
|
|
497
|
+
} };
|
|
498
|
+
};
|
|
499
|
+
const waitForProcessingOrDeadline = async (processing, closeDeadline) => {
|
|
500
|
+
let timeoutId = null;
|
|
501
|
+
try {
|
|
502
|
+
return await Promise.race([processing.then(() => true), new Promise((resolve) => {
|
|
503
|
+
timeoutId = setTimeout(() => resolve(false), closeDeadline);
|
|
504
|
+
timeoutId.unref();
|
|
505
|
+
})]);
|
|
506
|
+
} finally {
|
|
507
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
//#endregion
|
|
512
|
+
//#region src/core/taskProcessing/executionGuards.ts
|
|
513
|
+
const guardConcurrentAccess = (options) => {
|
|
514
|
+
const taskProcessor = new TaskProcessor({
|
|
515
|
+
maxActiveTasks: options?.maxActiveTasks ?? Number.MAX_SAFE_INTEGER,
|
|
516
|
+
maxQueueSize: options?.maxQueueSize ?? Number.MAX_SAFE_INTEGER,
|
|
517
|
+
...options?.maxTaskIdleTime !== void 0 ? { maxTaskIdleTime: options.maxTaskIdleTime } : {}
|
|
518
|
+
});
|
|
519
|
+
return {
|
|
520
|
+
execute: (operation, options) => taskProcessor.enqueue(async (context) => {
|
|
521
|
+
try {
|
|
522
|
+
return await operation({ abort: context.abort });
|
|
523
|
+
} finally {
|
|
524
|
+
context.ack();
|
|
525
|
+
}
|
|
526
|
+
}, options),
|
|
527
|
+
waitForIdle: () => taskProcessor.waitForEndOfProcessing(),
|
|
528
|
+
stop: (options) => taskProcessor.stop(options)
|
|
529
|
+
};
|
|
530
|
+
};
|
|
531
|
+
const guardBoundedAccess = (getResource, options) => {
|
|
532
|
+
let isStopped = false;
|
|
533
|
+
const taskProcessor = new TaskProcessor({
|
|
534
|
+
maxActiveTasks: options.maxResources,
|
|
535
|
+
maxQueueSize: options.maxQueueSize ?? 1e3
|
|
536
|
+
});
|
|
537
|
+
const resourcePool = [];
|
|
538
|
+
const allResources = /* @__PURE__ */ new Set();
|
|
539
|
+
const activeResourceContexts = /* @__PURE__ */ new Map();
|
|
540
|
+
const acquireResource = async (taskContext) => {
|
|
541
|
+
try {
|
|
542
|
+
let resource;
|
|
543
|
+
if (options.reuseResources) resource = resourcePool.pop();
|
|
544
|
+
if (!resource) {
|
|
545
|
+
resource = await getResource({ abort: taskContext.abort });
|
|
546
|
+
allResources.add(resource);
|
|
547
|
+
}
|
|
548
|
+
activeResourceContexts.set(resource, {
|
|
549
|
+
ack: taskContext.ack,
|
|
550
|
+
taskContext
|
|
551
|
+
});
|
|
552
|
+
return resource;
|
|
553
|
+
} catch (e) {
|
|
554
|
+
taskContext.ack();
|
|
555
|
+
throw e;
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
const acquire = async (operationOptions) => taskProcessor.enqueue((taskContext) => acquireResource(taskContext), operationOptions);
|
|
559
|
+
const getActiveResourceContext = (resource) => {
|
|
560
|
+
const activeResourceContext = activeResourceContexts.get(resource);
|
|
561
|
+
if (!activeResourceContext) throw new Error("Acquired resource is not active");
|
|
562
|
+
return activeResourceContext;
|
|
563
|
+
};
|
|
564
|
+
const release = (resource) => {
|
|
565
|
+
const activeResourceContext = activeResourceContexts.get(resource);
|
|
566
|
+
if (activeResourceContext) {
|
|
567
|
+
activeResourceContexts.delete(resource);
|
|
568
|
+
if (options.reuseResources) resourcePool.push(resource);
|
|
569
|
+
activeResourceContext.ack();
|
|
570
|
+
}
|
|
571
|
+
};
|
|
572
|
+
const execute = async (operation, operationOptions) => {
|
|
573
|
+
return taskProcessor.enqueue(async (taskContext) => {
|
|
574
|
+
const resource = await acquireResource(taskContext);
|
|
575
|
+
const activeResourceContext = getActiveResourceContext(resource);
|
|
576
|
+
try {
|
|
577
|
+
return await operation(resource, { abort: activeResourceContext.taskContext.abort });
|
|
578
|
+
} finally {
|
|
579
|
+
release(resource);
|
|
580
|
+
}
|
|
581
|
+
}, operationOptions);
|
|
582
|
+
};
|
|
583
|
+
return {
|
|
584
|
+
acquire,
|
|
585
|
+
release,
|
|
586
|
+
execute,
|
|
587
|
+
waitForIdle: () => taskProcessor.waitForEndOfProcessing(),
|
|
588
|
+
stop: async (stopOptions) => {
|
|
589
|
+
if (isStopped) return;
|
|
590
|
+
isStopped = true;
|
|
591
|
+
await taskProcessor.stop(stopOptions);
|
|
592
|
+
if (options?.closeResource) {
|
|
593
|
+
const resources = [...allResources];
|
|
594
|
+
allResources.clear();
|
|
595
|
+
resourcePool.length = 0;
|
|
596
|
+
await Promise.all(resources.map(async (resource) => await options.closeResource(resource)));
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
};
|
|
601
|
+
|
|
244
602
|
//#endregion
|
|
245
603
|
//#region src/core/execute/execute.ts
|
|
246
604
|
const mapColumnToJSON = (column, serializer, options) => ({ [column]: (value) => {
|
|
@@ -279,26 +637,63 @@ var BatchCommandNoChangesError = class BatchCommandNoChangesError extends DumboE
|
|
|
279
637
|
}
|
|
280
638
|
};
|
|
281
639
|
const sqlExecutor = (sqlExecutor, options) => ({
|
|
282
|
-
query: (sql, queryOptions) => executeInNewDbClient((client) => sqlExecutor.query(client, sql, queryOptions),
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
640
|
+
query: (sql, queryOptions) => executeInNewDbClient((client) => sqlExecutor.query(client, sql, queryOptions), {
|
|
641
|
+
...options,
|
|
642
|
+
...queryOptions
|
|
643
|
+
}),
|
|
644
|
+
batchQuery: (sqls, queryOptions) => executeInNewDbClient((client) => sqlExecutor.batchQuery(client, sqls, queryOptions), {
|
|
645
|
+
...options,
|
|
646
|
+
...queryOptions
|
|
647
|
+
}),
|
|
648
|
+
command: (sql, commandOptions) => executeInNewDbClient((client) => sqlExecutor.command(client, sql, commandOptions), {
|
|
649
|
+
...options,
|
|
650
|
+
...commandOptions
|
|
651
|
+
}),
|
|
652
|
+
batchCommand: (sqls, commandOptions) => executeInNewDbClient((client) => sqlExecutor.batchCommand(client, sqls, commandOptions), {
|
|
653
|
+
...options,
|
|
654
|
+
...commandOptions
|
|
655
|
+
})
|
|
286
656
|
});
|
|
287
657
|
const sqlExecutorInNewConnection = (options) => ({
|
|
288
|
-
query: (sql, queryOptions) => executeInNewConnection((connection) => connection.execute.query(sql, queryOptions),
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
658
|
+
query: (sql, queryOptions) => executeInNewConnection((connection) => connection.execute.query(sql, queryOptions), {
|
|
659
|
+
...options,
|
|
660
|
+
...queryOptions
|
|
661
|
+
}),
|
|
662
|
+
batchQuery: (sqls, queryOptions) => executeInNewConnection((connection) => connection.execute.batchQuery(sqls, queryOptions), {
|
|
663
|
+
...options,
|
|
664
|
+
...queryOptions
|
|
665
|
+
}),
|
|
666
|
+
command: (sql, commandOptions) => executeInNewConnection((connection) => connection.execute.command(sql, commandOptions), {
|
|
667
|
+
...options,
|
|
668
|
+
...commandOptions
|
|
669
|
+
}),
|
|
670
|
+
batchCommand: (sqls, commandOptions) => executeInNewConnection((connection) => connection.execute.batchCommand(sqls, commandOptions), {
|
|
671
|
+
...options,
|
|
672
|
+
...commandOptions
|
|
673
|
+
})
|
|
292
674
|
});
|
|
293
675
|
const sqlExecutorInAmbientConnection = (options) => ({
|
|
294
|
-
query: (sql, queryOptions) => executeInAmbientConnection((connection) => connection.execute.query(sql, queryOptions),
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
676
|
+
query: (sql, queryOptions) => executeInAmbientConnection((connection) => connection.execute.query(sql, queryOptions), {
|
|
677
|
+
...options,
|
|
678
|
+
...queryOptions
|
|
679
|
+
}),
|
|
680
|
+
batchQuery: (sqls, queryOptions) => executeInAmbientConnection((connection) => connection.execute.batchQuery(sqls, queryOptions), {
|
|
681
|
+
...options,
|
|
682
|
+
...queryOptions
|
|
683
|
+
}),
|
|
684
|
+
command: (sql, commandOptions) => executeInAmbientConnection((connection) => connection.execute.command(sql, commandOptions), {
|
|
685
|
+
...options,
|
|
686
|
+
...commandOptions
|
|
687
|
+
}),
|
|
688
|
+
batchCommand: (sqls, commandOptions) => executeInAmbientConnection((connection) => connection.execute.batchCommand(sqls, commandOptions), {
|
|
689
|
+
...options,
|
|
690
|
+
...commandOptions
|
|
691
|
+
})
|
|
298
692
|
});
|
|
299
693
|
const executeInNewDbClient = async (handle, options) => {
|
|
694
|
+
Abort.throwIfAborted(options);
|
|
300
695
|
const { connect, close } = options;
|
|
301
|
-
const client = await connect();
|
|
696
|
+
const client = await connect({ abort: Abort.from(options) });
|
|
302
697
|
try {
|
|
303
698
|
return await handle(client);
|
|
304
699
|
} catch (error) {
|
|
@@ -307,7 +702,8 @@ const executeInNewDbClient = async (handle, options) => {
|
|
|
307
702
|
}
|
|
308
703
|
};
|
|
309
704
|
const executeInNewConnection = async (handle, options) => {
|
|
310
|
-
|
|
705
|
+
Abort.throwIfAborted(options);
|
|
706
|
+
const connection = await options.connection({ abort: Abort.from(options) });
|
|
311
707
|
try {
|
|
312
708
|
return await handle(connection);
|
|
313
709
|
} finally {
|
|
@@ -315,10 +711,8 @@ const executeInNewConnection = async (handle, options) => {
|
|
|
315
711
|
}
|
|
316
712
|
};
|
|
317
713
|
const executeInAmbientConnection = async (handle, options) => {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
return await handle(connection);
|
|
321
|
-
} finally {}
|
|
714
|
+
Abort.throwIfAborted(options);
|
|
715
|
+
return handle(await options.connection({ abort: Abort.from(options) }));
|
|
322
716
|
};
|
|
323
717
|
|
|
324
718
|
//#endregion
|
|
@@ -386,10 +780,10 @@ const toTransactionResult = (transactionResult) => transactionResult !== void 0
|
|
|
386
780
|
success: true,
|
|
387
781
|
result: transactionResult
|
|
388
782
|
};
|
|
389
|
-
const executeInTransaction = async (transaction, handle) => {
|
|
783
|
+
const executeInTransaction = async (transaction, handle, context = { abort: Abort.never }) => {
|
|
390
784
|
await transaction.begin();
|
|
391
785
|
try {
|
|
392
|
-
const { success, result } = toTransactionResult(await handle(transaction));
|
|
786
|
+
const { success, result } = toTransactionResult(await handle(transaction, context));
|
|
393
787
|
if (success) await transaction.commit();
|
|
394
788
|
else await transaction.rollback();
|
|
395
789
|
return result;
|
|
@@ -398,18 +792,32 @@ const executeInTransaction = async (transaction, handle) => {
|
|
|
398
792
|
throw e;
|
|
399
793
|
}
|
|
400
794
|
};
|
|
795
|
+
const executeInNestedTransaction = async (transaction, handle, options, context) => {
|
|
796
|
+
Abort.throwIfAborted(options);
|
|
797
|
+
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.");
|
|
798
|
+
return executeInTransaction(transaction, handle, context);
|
|
799
|
+
};
|
|
401
800
|
const transactionFactoryWithDbClient = (connect, initTransaction) => {
|
|
402
801
|
let currentTransaction = void 0;
|
|
403
|
-
const getOrInitCurrentTransaction = (options) =>
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
802
|
+
const getOrInitCurrentTransaction = (options) => {
|
|
803
|
+
Abort.throwIfAborted(options);
|
|
804
|
+
if (currentTransaction) return currentTransaction;
|
|
805
|
+
currentTransaction = initTransaction(connect({ abort: Abort.from(options) }), {
|
|
806
|
+
close: () => {
|
|
807
|
+
currentTransaction = void 0;
|
|
808
|
+
return Promise.resolve();
|
|
809
|
+
},
|
|
810
|
+
...options ?? {}
|
|
811
|
+
});
|
|
812
|
+
return currentTransaction;
|
|
813
|
+
};
|
|
410
814
|
return {
|
|
411
815
|
transaction: getOrInitCurrentTransaction,
|
|
412
|
-
withTransaction: (handle, options) =>
|
|
816
|
+
withTransaction: (handle, options) => {
|
|
817
|
+
const abortRejection = Abort.rejectIfAborted(options);
|
|
818
|
+
if (abortRejection) return abortRejection;
|
|
819
|
+
return executeInTransaction(getOrInitCurrentTransaction(options), handle, { abort: Abort.from(options) });
|
|
820
|
+
}
|
|
413
821
|
};
|
|
414
822
|
};
|
|
415
823
|
const wrapInConnectionClosure = async (connection, handle) => {
|
|
@@ -421,7 +829,8 @@ const wrapInConnectionClosure = async (connection, handle) => {
|
|
|
421
829
|
};
|
|
422
830
|
const transactionFactoryWithNewConnection = (connect) => ({
|
|
423
831
|
transaction: (options) => {
|
|
424
|
-
|
|
832
|
+
Abort.throwIfAborted(options);
|
|
833
|
+
const connection = connect({ abort: Abort.from(options) });
|
|
425
834
|
const transaction = connection.transaction(options);
|
|
426
835
|
return {
|
|
427
836
|
...transaction,
|
|
@@ -430,14 +839,17 @@ const transactionFactoryWithNewConnection = (connect) => ({
|
|
|
430
839
|
};
|
|
431
840
|
},
|
|
432
841
|
withTransaction: (handle, options) => {
|
|
433
|
-
const
|
|
842
|
+
const abortRejection = Abort.rejectIfAborted(options);
|
|
843
|
+
if (abortRejection) return abortRejection;
|
|
844
|
+
const connection = connect({ abort: Abort.from(options) });
|
|
434
845
|
const withTx = connection.withTransaction;
|
|
435
846
|
return wrapInConnectionClosure(connection, () => withTx(handle, options));
|
|
436
847
|
}
|
|
437
848
|
});
|
|
438
849
|
const transactionFactoryWithAmbientConnection = (connect) => ({
|
|
439
850
|
transaction: (options) => {
|
|
440
|
-
|
|
851
|
+
Abort.throwIfAborted(options);
|
|
852
|
+
const transaction = connect({ abort: Abort.from(options) }).transaction(options);
|
|
441
853
|
return {
|
|
442
854
|
...transaction,
|
|
443
855
|
commit: () => transaction.commit(),
|
|
@@ -445,7 +857,9 @@ const transactionFactoryWithAmbientConnection = (connect) => ({
|
|
|
445
857
|
};
|
|
446
858
|
},
|
|
447
859
|
withTransaction: (handle, options) => {
|
|
448
|
-
const
|
|
860
|
+
const abortRejection = Abort.rejectIfAborted(options);
|
|
861
|
+
if (abortRejection) return abortRejection;
|
|
862
|
+
const withTx = connect({ abort: Abort.from(options) }).withTransaction;
|
|
449
863
|
return withTx(handle, options);
|
|
450
864
|
}
|
|
451
865
|
});
|
|
@@ -453,19 +867,21 @@ const transactionFactoryWithAsyncAmbientConnection = (driverType, connect, close
|
|
|
453
867
|
close ??= () => Promise.resolve();
|
|
454
868
|
return {
|
|
455
869
|
transaction: (options) => {
|
|
870
|
+
Abort.throwIfAborted(options);
|
|
456
871
|
let conn = null;
|
|
457
872
|
let innerTx = null;
|
|
458
873
|
let connectingPromise = null;
|
|
459
874
|
const ensureConnection = async () => {
|
|
460
875
|
if (conn) return innerTx;
|
|
461
876
|
if (!connectingPromise) connectingPromise = (async () => {
|
|
462
|
-
|
|
877
|
+
Abort.throwIfAborted(options);
|
|
878
|
+
conn = await connect({ abort: Abort.from(options) });
|
|
463
879
|
innerTx = conn.transaction(options);
|
|
464
880
|
})();
|
|
465
881
|
await connectingPromise;
|
|
466
882
|
return innerTx;
|
|
467
883
|
};
|
|
468
|
-
|
|
884
|
+
const tx = {
|
|
469
885
|
driverType,
|
|
470
886
|
get connection() {
|
|
471
887
|
if (!conn) throw new Error("Transaction not started - call begin() first");
|
|
@@ -507,11 +923,14 @@ const transactionFactoryWithAsyncAmbientConnection = (driverType, connect, close
|
|
|
507
923
|
if (conn) await close(conn);
|
|
508
924
|
}
|
|
509
925
|
},
|
|
510
|
-
|
|
926
|
+
withTransaction: (handle, options) => executeInNestedTransaction(tx, handle, options, { abort: Abort.from(options) }),
|
|
927
|
+
_transactionOptions: options ?? {}
|
|
511
928
|
};
|
|
929
|
+
return tx;
|
|
512
930
|
},
|
|
513
931
|
withTransaction: async (handle, options) => {
|
|
514
|
-
|
|
932
|
+
Abort.throwIfAborted(options);
|
|
933
|
+
const conn = await connect({ abort: Abort.from(options) });
|
|
515
934
|
try {
|
|
516
935
|
const withTx = conn.withTransaction;
|
|
517
936
|
return await withTx(handle, options);
|
|
@@ -528,7 +947,10 @@ const createAmbientConnection = (options) => {
|
|
|
528
947
|
const { driverType, client, executor, initTransaction, serializer } = options;
|
|
529
948
|
const clientPromise = Promise.resolve(client);
|
|
530
949
|
const closePromise = Promise.resolve();
|
|
531
|
-
const open = () =>
|
|
950
|
+
const open = (context) => {
|
|
951
|
+
Abort.throwIfAborted(context);
|
|
952
|
+
return clientPromise;
|
|
953
|
+
};
|
|
532
954
|
const close = () => closePromise;
|
|
533
955
|
const typedConnection = {
|
|
534
956
|
driverType,
|
|
@@ -544,9 +966,10 @@ const createSingletonConnection = (options) => {
|
|
|
544
966
|
const { driverType, connect, close, initTransaction, executor, serializer } = options;
|
|
545
967
|
let client = null;
|
|
546
968
|
let connectPromise = null;
|
|
547
|
-
const getClient = async () => {
|
|
969
|
+
const getClient = async (context) => {
|
|
970
|
+
Abort.throwIfAborted(context);
|
|
548
971
|
if (client) return client;
|
|
549
|
-
if (!connectPromise) connectPromise = connect().then((c) => {
|
|
972
|
+
if (!connectPromise) connectPromise = connect(context ?? { abort: Abort.never }).then((c) => {
|
|
550
973
|
client = c;
|
|
551
974
|
return c;
|
|
552
975
|
});
|
|
@@ -564,12 +987,16 @@ const createSingletonConnection = (options) => {
|
|
|
564
987
|
};
|
|
565
988
|
const createTransientConnection = (options) => {
|
|
566
989
|
const { driverType, open, close, initTransaction, executor, serializer } = options;
|
|
990
|
+
const openIfNotAborted = (context) => {
|
|
991
|
+
Abort.throwIfAborted(context);
|
|
992
|
+
return open(context);
|
|
993
|
+
};
|
|
567
994
|
const typedConnection = {
|
|
568
995
|
driverType,
|
|
569
|
-
open,
|
|
996
|
+
open: openIfNotAborted,
|
|
570
997
|
close,
|
|
571
|
-
...transactionFactoryWithDbClient(
|
|
572
|
-
execute: sqlExecutor(executor({ serializer }), { connect:
|
|
998
|
+
...transactionFactoryWithDbClient(openIfNotAborted, initTransaction(() => typedConnection)),
|
|
999
|
+
execute: sqlExecutor(executor({ serializer }), { connect: openIfNotAborted }),
|
|
573
1000
|
_transactionType: void 0
|
|
574
1001
|
};
|
|
575
1002
|
return typedConnection;
|
|
@@ -578,9 +1005,10 @@ const createConnection = (options) => {
|
|
|
578
1005
|
const { driverType, connect, close, initTransaction, executor, serializer } = options;
|
|
579
1006
|
let client = null;
|
|
580
1007
|
let connectPromise = null;
|
|
581
|
-
const getClient = async () => {
|
|
1008
|
+
const getClient = async (context) => {
|
|
1009
|
+
Abort.throwIfAborted(context);
|
|
582
1010
|
if (client) return client;
|
|
583
|
-
if (!connectPromise) connectPromise = connect().then((c) => {
|
|
1011
|
+
if (!connectPromise) connectPromise = connect(context ?? { abort: Abort.never }).then((c) => {
|
|
584
1012
|
client = c;
|
|
585
1013
|
return c;
|
|
586
1014
|
});
|
|
@@ -597,174 +1025,6 @@ const createConnection = (options) => {
|
|
|
597
1025
|
return typedConnection;
|
|
598
1026
|
};
|
|
599
1027
|
|
|
600
|
-
//#endregion
|
|
601
|
-
//#region src/core/taskProcessing/taskProcessor.ts
|
|
602
|
-
var TaskProcessor = class {
|
|
603
|
-
queue = [];
|
|
604
|
-
isProcessing = false;
|
|
605
|
-
activeTasks = 0;
|
|
606
|
-
activeGroups = /* @__PURE__ */ new Set();
|
|
607
|
-
options;
|
|
608
|
-
stopped = false;
|
|
609
|
-
constructor(options) {
|
|
610
|
-
this.options = options;
|
|
611
|
-
}
|
|
612
|
-
enqueue(task, options) {
|
|
613
|
-
if (this.stopped) return Promise.reject(new DumboError("TaskProcessor has been stopped"));
|
|
614
|
-
if (this.queue.length >= this.options.maxQueueSize) return Promise.reject(new TransientDatabaseError("Too many pending connections. Please try again later."));
|
|
615
|
-
return this.schedule(task, options);
|
|
616
|
-
}
|
|
617
|
-
waitForEndOfProcessing() {
|
|
618
|
-
return this.schedule(({ ack }) => Promise.resolve(ack()));
|
|
619
|
-
}
|
|
620
|
-
async stop(options) {
|
|
621
|
-
if (this.stopped) return;
|
|
622
|
-
this.stopped = true;
|
|
623
|
-
this.queue.length = 0;
|
|
624
|
-
this.activeGroups.clear();
|
|
625
|
-
if (!options?.force) await this.waitForEndOfProcessing();
|
|
626
|
-
}
|
|
627
|
-
schedule(task, options) {
|
|
628
|
-
return promiseWithDeadline((resolve, reject) => {
|
|
629
|
-
const taskWithContext = () => {
|
|
630
|
-
return new Promise((resolveTask, failTask) => {
|
|
631
|
-
task({ ack: resolveTask }).then(resolve).catch((err) => {
|
|
632
|
-
failTask(err);
|
|
633
|
-
reject(err);
|
|
634
|
-
});
|
|
635
|
-
});
|
|
636
|
-
};
|
|
637
|
-
this.queue.push({
|
|
638
|
-
task: taskWithContext,
|
|
639
|
-
options
|
|
640
|
-
});
|
|
641
|
-
if (!this.isProcessing) this.ensureProcessing();
|
|
642
|
-
}, { deadline: this.options.maxTaskIdleTime });
|
|
643
|
-
}
|
|
644
|
-
ensureProcessing() {
|
|
645
|
-
if (this.isProcessing) return;
|
|
646
|
-
this.isProcessing = true;
|
|
647
|
-
this.processQueue();
|
|
648
|
-
}
|
|
649
|
-
processQueue() {
|
|
650
|
-
try {
|
|
651
|
-
while (this.activeTasks < this.options.maxActiveTasks && this.queue.length > 0) {
|
|
652
|
-
const item = this.takeFirstAvailableItem();
|
|
653
|
-
if (item === null) return;
|
|
654
|
-
const groupId = item.options?.taskGroupId;
|
|
655
|
-
if (groupId) this.activeGroups.add(groupId);
|
|
656
|
-
this.activeTasks++;
|
|
657
|
-
this.executeItem(item);
|
|
658
|
-
}
|
|
659
|
-
} catch (error) {
|
|
660
|
-
console.error(error);
|
|
661
|
-
throw error;
|
|
662
|
-
} finally {
|
|
663
|
-
this.isProcessing = false;
|
|
664
|
-
if (this.hasItemsToProcess() && this.activeTasks < this.options.maxActiveTasks) this.ensureProcessing();
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
async executeItem({ task, options }) {
|
|
668
|
-
try {
|
|
669
|
-
await task();
|
|
670
|
-
} finally {
|
|
671
|
-
this.activeTasks--;
|
|
672
|
-
if (options && options.taskGroupId) this.activeGroups.delete(options.taskGroupId);
|
|
673
|
-
this.ensureProcessing();
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
takeFirstAvailableItem = () => {
|
|
677
|
-
const taskIndex = this.queue.findIndex((item) => !item.options?.taskGroupId || !this.activeGroups.has(item.options.taskGroupId));
|
|
678
|
-
if (taskIndex === -1) return null;
|
|
679
|
-
const [item] = this.queue.splice(taskIndex, 1);
|
|
680
|
-
return item ?? null;
|
|
681
|
-
};
|
|
682
|
-
hasItemsToProcess = () => this.queue.findIndex((item) => !item.options?.taskGroupId || !this.activeGroups.has(item.options.taskGroupId)) !== -1;
|
|
683
|
-
};
|
|
684
|
-
const DEFAULT_PROMISE_DEADLINE = 2147483647;
|
|
685
|
-
const promiseWithDeadline = (executor, options) => {
|
|
686
|
-
return new Promise((resolve, reject) => {
|
|
687
|
-
let taskStarted = false;
|
|
688
|
-
let timeoutId = null;
|
|
689
|
-
const deadline = options.deadline ?? DEFAULT_PROMISE_DEADLINE;
|
|
690
|
-
timeoutId = setTimeout(() => {
|
|
691
|
-
if (!taskStarted) reject(/* @__PURE__ */ new Error("Task was not started within the maximum waiting time"));
|
|
692
|
-
}, deadline);
|
|
693
|
-
timeoutId.unref();
|
|
694
|
-
executor((value) => {
|
|
695
|
-
taskStarted = true;
|
|
696
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
697
|
-
timeoutId = null;
|
|
698
|
-
resolve(value);
|
|
699
|
-
}, (reason) => {
|
|
700
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
701
|
-
timeoutId = null;
|
|
702
|
-
reject(reason);
|
|
703
|
-
});
|
|
704
|
-
});
|
|
705
|
-
};
|
|
706
|
-
|
|
707
|
-
//#endregion
|
|
708
|
-
//#region src/core/taskProcessing/executionGuards.ts
|
|
709
|
-
const guardBoundedAccess = (getResource, options) => {
|
|
710
|
-
let isStopped = false;
|
|
711
|
-
const taskProcessor = new TaskProcessor({
|
|
712
|
-
maxActiveTasks: options.maxResources,
|
|
713
|
-
maxQueueSize: options.maxQueueSize ?? 1e3
|
|
714
|
-
});
|
|
715
|
-
const resourcePool = [];
|
|
716
|
-
const allResources = /* @__PURE__ */ new Set();
|
|
717
|
-
const ackCallbacks = /* @__PURE__ */ new Map();
|
|
718
|
-
const acquire = async () => taskProcessor.enqueue(async ({ ack }) => {
|
|
719
|
-
try {
|
|
720
|
-
let resource;
|
|
721
|
-
if (options.reuseResources) resource = resourcePool.pop();
|
|
722
|
-
if (!resource) {
|
|
723
|
-
resource = await getResource();
|
|
724
|
-
allResources.add(resource);
|
|
725
|
-
}
|
|
726
|
-
ackCallbacks.set(resource, ack);
|
|
727
|
-
return resource;
|
|
728
|
-
} catch (e) {
|
|
729
|
-
ack();
|
|
730
|
-
throw e;
|
|
731
|
-
}
|
|
732
|
-
});
|
|
733
|
-
const release = (resource) => {
|
|
734
|
-
const ack = ackCallbacks.get(resource);
|
|
735
|
-
if (ack) {
|
|
736
|
-
ackCallbacks.delete(resource);
|
|
737
|
-
if (options.reuseResources) resourcePool.push(resource);
|
|
738
|
-
ack();
|
|
739
|
-
}
|
|
740
|
-
};
|
|
741
|
-
const execute = async (operation) => {
|
|
742
|
-
const resource = await acquire();
|
|
743
|
-
try {
|
|
744
|
-
return await operation(resource);
|
|
745
|
-
} finally {
|
|
746
|
-
release(resource);
|
|
747
|
-
}
|
|
748
|
-
};
|
|
749
|
-
return {
|
|
750
|
-
acquire,
|
|
751
|
-
release,
|
|
752
|
-
execute,
|
|
753
|
-
waitForIdle: () => taskProcessor.waitForEndOfProcessing(),
|
|
754
|
-
stop: async (stopOptions) => {
|
|
755
|
-
if (isStopped) return;
|
|
756
|
-
isStopped = true;
|
|
757
|
-
if (options?.closeResource) {
|
|
758
|
-
const resources = [...allResources];
|
|
759
|
-
allResources.clear();
|
|
760
|
-
resourcePool.length = 0;
|
|
761
|
-
await Promise.all(resources.map(async (resource) => await options.closeResource(resource)));
|
|
762
|
-
}
|
|
763
|
-
await taskProcessor.stop(stopOptions);
|
|
764
|
-
}
|
|
765
|
-
};
|
|
766
|
-
};
|
|
767
|
-
|
|
768
1028
|
//#endregion
|
|
769
1029
|
//#region src/core/connections/pool.ts
|
|
770
1030
|
const wrapPooledConnection = (conn, onClose) => ({
|
|
@@ -778,7 +1038,10 @@ const createAmbientConnectionPool = (options) => {
|
|
|
778
1038
|
getConnection: () => connection,
|
|
779
1039
|
execute: connection.execute,
|
|
780
1040
|
transaction: (options) => connection.transaction(options),
|
|
781
|
-
withConnection: (handle,
|
|
1041
|
+
withConnection: (handle, options) => {
|
|
1042
|
+
Abort.throwIfAborted(options);
|
|
1043
|
+
return handle(connection, { abort: Abort.from(options) });
|
|
1044
|
+
},
|
|
782
1045
|
withTransaction: (handle, options) => {
|
|
783
1046
|
const withTx = connection.withTransaction;
|
|
784
1047
|
return withTx(handle, options);
|
|
@@ -789,48 +1052,45 @@ const createSingletonConnectionPool = (options) => {
|
|
|
789
1052
|
const { driverType, getConnection } = options;
|
|
790
1053
|
let connectionPromise = null;
|
|
791
1054
|
let closed = false;
|
|
792
|
-
const
|
|
1055
|
+
const operationGuard = guardConcurrentAccess();
|
|
793
1056
|
const closedError = () => /* @__PURE__ */ new Error("Singleton connection pool has been closed");
|
|
794
|
-
const
|
|
1057
|
+
const executeIfOpen = async (operation, operationOptions) => {
|
|
795
1058
|
if (closed) throw closedError();
|
|
796
|
-
|
|
797
|
-
activeOperations.add(activeOperation);
|
|
798
|
-
try {
|
|
799
|
-
return await activeOperation;
|
|
800
|
-
} finally {
|
|
801
|
-
activeOperations.delete(activeOperation);
|
|
802
|
-
}
|
|
1059
|
+
return operationGuard.execute(operation, operationOptions);
|
|
803
1060
|
};
|
|
804
|
-
const getExistingOrNewConnection = () => {
|
|
805
|
-
if (!connectionPromise) connectionPromise ??= Promise.resolve(getConnection());
|
|
1061
|
+
const getExistingOrNewConnection = (context) => {
|
|
1062
|
+
if (!connectionPromise) connectionPromise ??= Promise.resolve(getConnection(context));
|
|
806
1063
|
return connectionPromise;
|
|
807
1064
|
};
|
|
808
1065
|
const innerTransactionFactory = transactionFactoryWithAsyncAmbientConnection(options.driverType, getExistingOrNewConnection, options.closeConnection);
|
|
809
1066
|
return {
|
|
810
1067
|
driverType,
|
|
811
|
-
connection: () =>
|
|
1068
|
+
connection: (connectionOptions) => executeIfOpen((context) => getExistingOrNewConnection(context).then((conn) => wrapPooledConnection(conn, () => Promise.resolve())), connectionOptions),
|
|
812
1069
|
execute: (() => {
|
|
813
1070
|
const ambientExecutor = sqlExecutorInAmbientConnection({
|
|
814
1071
|
driverType,
|
|
815
1072
|
connection: getExistingOrNewConnection
|
|
816
1073
|
});
|
|
817
1074
|
return {
|
|
818
|
-
query: (sql, opts) =>
|
|
819
|
-
batchQuery: (sqls, opts) =>
|
|
820
|
-
command: (sql, opts) =>
|
|
821
|
-
batchCommand: (sqls, opts) =>
|
|
1075
|
+
query: (sql, opts) => executeIfOpen(() => ambientExecutor.query(sql, opts), opts),
|
|
1076
|
+
batchQuery: (sqls, opts) => executeIfOpen(() => ambientExecutor.batchQuery(sqls, opts), opts),
|
|
1077
|
+
command: (sql, opts) => executeIfOpen(() => ambientExecutor.command(sql, opts), opts),
|
|
1078
|
+
batchCommand: (sqls, opts) => executeIfOpen(() => ambientExecutor.batchCommand(sqls, opts), opts)
|
|
822
1079
|
};
|
|
823
1080
|
})(),
|
|
824
|
-
withConnection: (handle,
|
|
1081
|
+
withConnection: (handle, options) => executeIfOpen((context) => executeInAmbientConnection((connection) => handle(connection, context), {
|
|
1082
|
+
connection: getExistingOrNewConnection,
|
|
1083
|
+
...options
|
|
1084
|
+
}), options),
|
|
825
1085
|
transaction: (transactionOptions) => {
|
|
826
1086
|
if (closed) throw closedError();
|
|
827
1087
|
return innerTransactionFactory.transaction(transactionOptions);
|
|
828
1088
|
},
|
|
829
|
-
withTransaction: (handle, transactionOptions) =>
|
|
1089
|
+
withTransaction: (handle, transactionOptions) => executeIfOpen((context) => innerTransactionFactory.withTransaction((tx) => handle(tx, context), transactionOptions), transactionOptions),
|
|
830
1090
|
close: async (closeOptions) => {
|
|
831
1091
|
if (closed) return;
|
|
832
1092
|
closed = true;
|
|
833
|
-
|
|
1093
|
+
await operationGuard.stop(closeOptions);
|
|
834
1094
|
if (!connectionPromise) return;
|
|
835
1095
|
const connection = await connectionPromise;
|
|
836
1096
|
connectionPromise = null;
|
|
@@ -840,63 +1100,49 @@ const createSingletonConnectionPool = (options) => {
|
|
|
840
1100
|
};
|
|
841
1101
|
const createBoundedConnectionPool = (options) => {
|
|
842
1102
|
const { driverType, maxConnections } = options;
|
|
843
|
-
const
|
|
844
|
-
const getTrackedConnection = async () => {
|
|
845
|
-
const connection = await options.getConnection();
|
|
846
|
-
allConnections.add(connection);
|
|
847
|
-
return connection;
|
|
848
|
-
};
|
|
849
|
-
const guardMaxConnections = guardBoundedAccess(getTrackedConnection, {
|
|
1103
|
+
const guardMaxConnections = guardBoundedAccess(options.getConnection, {
|
|
850
1104
|
maxResources: maxConnections,
|
|
851
|
-
reuseResources: true
|
|
1105
|
+
reuseResources: true,
|
|
1106
|
+
closeResource: (connection) => connection.close()
|
|
852
1107
|
});
|
|
853
1108
|
let closed = false;
|
|
854
1109
|
const closedError = () => /* @__PURE__ */ new Error("Bounded connection pool has been closed");
|
|
855
1110
|
const ensureOpen = () => {
|
|
856
1111
|
if (closed) throw closedError();
|
|
857
1112
|
};
|
|
858
|
-
const
|
|
859
|
-
const connections = [...allConnections];
|
|
860
|
-
allConnections.clear();
|
|
861
|
-
await Promise.all(connections.map((conn) => conn.close()));
|
|
862
|
-
};
|
|
863
|
-
const executeWithPooling = async (operation) => {
|
|
1113
|
+
const executeWithPooledConnection = async (operation, operationOptions) => {
|
|
864
1114
|
ensureOpen();
|
|
865
|
-
|
|
866
|
-
try {
|
|
867
|
-
return await operation(conn);
|
|
868
|
-
} finally {
|
|
869
|
-
guardMaxConnections.release(conn);
|
|
870
|
-
}
|
|
1115
|
+
return guardMaxConnections.execute(operation, operationOptions);
|
|
871
1116
|
};
|
|
872
1117
|
return {
|
|
873
1118
|
driverType,
|
|
874
|
-
connection: async () => {
|
|
1119
|
+
connection: async (connectionOptions) => {
|
|
875
1120
|
ensureOpen();
|
|
876
|
-
const conn = await guardMaxConnections.acquire();
|
|
1121
|
+
const conn = await guardMaxConnections.acquire(connectionOptions);
|
|
877
1122
|
return wrapPooledConnection(conn, () => Promise.resolve(guardMaxConnections.release(conn)));
|
|
878
1123
|
},
|
|
879
1124
|
execute: {
|
|
880
|
-
query: (sql, opts) =>
|
|
881
|
-
batchQuery: (sqls, opts) =>
|
|
882
|
-
command: (sql, opts) =>
|
|
883
|
-
batchCommand: (sqls, opts) =>
|
|
1125
|
+
query: (sql, opts) => executeWithPooledConnection((c) => c.execute.query(sql, opts), opts),
|
|
1126
|
+
batchQuery: (sqls, opts) => executeWithPooledConnection((c) => c.execute.batchQuery(sqls, opts), opts),
|
|
1127
|
+
command: (sql, opts) => executeWithPooledConnection((c) => c.execute.command(sql, opts), opts),
|
|
1128
|
+
batchCommand: (sqls, opts) => executeWithPooledConnection((c) => c.execute.batchCommand(sqls, opts), opts)
|
|
884
1129
|
},
|
|
885
|
-
withConnection:
|
|
1130
|
+
withConnection: executeWithPooledConnection,
|
|
886
1131
|
transaction: (transactionOptions) => {
|
|
887
1132
|
ensureOpen();
|
|
888
|
-
return transactionFactoryWithAsyncAmbientConnection(driverType, guardMaxConnections.acquire
|
|
1133
|
+
return transactionFactoryWithAsyncAmbientConnection(driverType, (context) => guardMaxConnections.acquire({
|
|
1134
|
+
...transactionOptions,
|
|
1135
|
+
abort: context.abort
|
|
1136
|
+
}), guardMaxConnections.release).transaction(transactionOptions);
|
|
889
1137
|
},
|
|
890
|
-
withTransaction: (handle, transactionOptions) =>
|
|
1138
|
+
withTransaction: (handle, transactionOptions) => executeWithPooledConnection((conn, context) => {
|
|
891
1139
|
const withTx = conn.withTransaction;
|
|
892
|
-
return withTx(handle, transactionOptions);
|
|
893
|
-
}),
|
|
1140
|
+
return withTx((tx) => handle(tx, context), transactionOptions);
|
|
1141
|
+
}, transactionOptions),
|
|
894
1142
|
close: async (closeOptions) => {
|
|
895
1143
|
if (closed) return;
|
|
896
1144
|
closed = true;
|
|
897
|
-
|
|
898
|
-
await guardMaxConnections.stop({ force: true });
|
|
899
|
-
await closeAllConnections();
|
|
1145
|
+
await guardMaxConnections.stop(closeOptions);
|
|
900
1146
|
}
|
|
901
1147
|
};
|
|
902
1148
|
};
|
|
@@ -911,16 +1157,22 @@ const createAlwaysNewConnectionPool = (options) => {
|
|
|
911
1157
|
const { driverType, getConnection, connectionOptions } = options;
|
|
912
1158
|
return createConnectionPool({
|
|
913
1159
|
driverType,
|
|
914
|
-
getConnection: () => connectionOptions ? getConnection(connectionOptions) : getConnection()
|
|
1160
|
+
getConnection: (context) => connectionOptions ? getConnection(connectionOptions, context) : getConnection(context)
|
|
915
1161
|
});
|
|
916
1162
|
};
|
|
917
1163
|
const createConnectionPool = (pool) => {
|
|
918
1164
|
const { driverType, getConnection } = pool;
|
|
919
|
-
const connection = "connection" in pool ? pool.connection : () =>
|
|
1165
|
+
const connection = "connection" in pool ? pool.connection : (options) => {
|
|
1166
|
+
Abort.throwIfAborted(options);
|
|
1167
|
+
return Promise.resolve(getConnection({ abort: Abort.from(options) }));
|
|
1168
|
+
};
|
|
920
1169
|
return {
|
|
921
1170
|
driverType,
|
|
922
1171
|
connection,
|
|
923
|
-
withConnection: "withConnection" in pool ? pool.withConnection : (handle,
|
|
1172
|
+
withConnection: "withConnection" in pool ? pool.withConnection : (handle, options) => executeInNewConnection((connection) => handle(connection, { abort: Abort.from(options) }), {
|
|
1173
|
+
connection,
|
|
1174
|
+
...options
|
|
1175
|
+
}),
|
|
924
1176
|
close: "close" in pool ? pool.close : () => Promise.resolve(),
|
|
925
1177
|
execute: "execute" in pool ? pool.execute : sqlExecutorInNewConnection({
|
|
926
1178
|
driverType,
|
|
@@ -2529,6 +2781,7 @@ function dumbo(options) {
|
|
|
2529
2781
|
//#endregion
|
|
2530
2782
|
exports.ANSISQLIdentifierQuote = ANSISQLIdentifierQuote;
|
|
2531
2783
|
exports.ANSISQLParamPlaceholder = ANSISQLParamPlaceholder;
|
|
2784
|
+
exports.Abort = Abort;
|
|
2532
2785
|
exports.AdminShutdownError = AdminShutdownError;
|
|
2533
2786
|
exports.AutoIncrementSQLColumnToken = AutoIncrementSQLColumnToken;
|
|
2534
2787
|
exports.BatchCommandNoChangesError = BatchCommandNoChangesError;
|
|
@@ -2634,6 +2887,7 @@ exports.dumboDatabaseDriverRegistry = dumboDatabaseDriverRegistry;
|
|
|
2634
2887
|
exports.dumboDatabaseMetadataRegistry = dumboDatabaseMetadataRegistry$1;
|
|
2635
2888
|
exports.dumboSchema = dumboSchema;
|
|
2636
2889
|
exports.executeInAmbientConnection = executeInAmbientConnection;
|
|
2890
|
+
exports.executeInNestedTransaction = executeInNestedTransaction;
|
|
2637
2891
|
exports.executeInNewConnection = executeInNewConnection;
|
|
2638
2892
|
exports.executeInNewDbClient = executeInNewDbClient;
|
|
2639
2893
|
exports.executeInTransaction = executeInTransaction;
|