@fragno-dev/db 0.1.13 → 0.1.15
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/.turbo/turbo-build.log +179 -132
- package/CHANGELOG.md +30 -0
- package/dist/adapters/adapters.d.ts +27 -1
- package/dist/adapters/adapters.d.ts.map +1 -1
- package/dist/adapters/adapters.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-adapter.d.ts +5 -1
- package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-adapter.js +15 -3
- package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-query.js +7 -5
- package/dist/adapters/drizzle/drizzle-query.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts +0 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.js +76 -44
- package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-decoder.js +23 -16
- package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-executor.js +18 -7
- package/dist/adapters/drizzle/drizzle-uow-executor.js.map +1 -1
- package/dist/adapters/drizzle/generate.d.ts +4 -1
- package/dist/adapters/drizzle/generate.d.ts.map +1 -1
- package/dist/adapters/drizzle/generate.js +11 -18
- package/dist/adapters/drizzle/generate.js.map +1 -1
- package/dist/adapters/drizzle/shared.d.ts +14 -1
- package/dist/adapters/drizzle/shared.d.ts.map +1 -0
- package/dist/adapters/kysely/kysely-adapter.d.ts +5 -1
- package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
- package/dist/adapters/kysely/kysely-adapter.js +14 -3
- package/dist/adapters/kysely/kysely-adapter.js.map +1 -1
- package/dist/adapters/kysely/kysely-query-builder.js +1 -1
- package/dist/adapters/kysely/kysely-query-compiler.js +3 -2
- package/dist/adapters/kysely/kysely-query-compiler.js.map +1 -1
- package/dist/adapters/kysely/kysely-query.d.ts +1 -0
- package/dist/adapters/kysely/kysely-query.d.ts.map +1 -1
- package/dist/adapters/kysely/kysely-query.js +28 -19
- package/dist/adapters/kysely/kysely-query.js.map +1 -1
- package/dist/adapters/kysely/kysely-shared.d.ts +14 -0
- package/dist/adapters/kysely/kysely-shared.d.ts.map +1 -0
- package/dist/adapters/kysely/kysely-shared.js +16 -1
- package/dist/adapters/kysely/kysely-shared.js.map +1 -1
- package/dist/adapters/kysely/kysely-uow-compiler.js +68 -16
- package/dist/adapters/kysely/kysely-uow-compiler.js.map +1 -1
- package/dist/adapters/kysely/kysely-uow-executor.js +8 -4
- package/dist/adapters/kysely/kysely-uow-executor.js.map +1 -1
- package/dist/adapters/kysely/migration/execute-base.js +1 -1
- package/dist/adapters/kysely/migration/execute-base.js.map +1 -1
- package/dist/db-fragment-definition-builder.d.ts +152 -0
- package/dist/db-fragment-definition-builder.d.ts.map +1 -0
- package/dist/db-fragment-definition-builder.js +137 -0
- package/dist/db-fragment-definition-builder.js.map +1 -0
- package/dist/fragments/internal-fragment.d.ts +19 -0
- package/dist/fragments/internal-fragment.d.ts.map +1 -0
- package/dist/fragments/internal-fragment.js +39 -0
- package/dist/fragments/internal-fragment.js.map +1 -0
- package/dist/migration-engine/generation-engine.d.ts.map +1 -1
- package/dist/migration-engine/generation-engine.js +35 -15
- package/dist/migration-engine/generation-engine.js.map +1 -1
- package/dist/mod.d.ts +8 -18
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +7 -34
- package/dist/mod.js.map +1 -1
- package/dist/node_modules/.pnpm/rou3@0.7.8/node_modules/rou3/dist/index.js +165 -0
- package/dist/node_modules/.pnpm/rou3@0.7.8/node_modules/rou3/dist/index.js.map +1 -0
- package/dist/packages/fragno/dist/api/bind-services.js +20 -0
- package/dist/packages/fragno/dist/api/bind-services.js.map +1 -0
- package/dist/packages/fragno/dist/api/error.js +48 -0
- package/dist/packages/fragno/dist/api/error.js.map +1 -0
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js +320 -0
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +1 -0
- package/dist/packages/fragno/dist/api/fragment-instantiator.js +487 -0
- package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +1 -0
- package/dist/packages/fragno/dist/api/fragno-response.js +73 -0
- package/dist/packages/fragno/dist/api/fragno-response.js.map +1 -0
- package/dist/packages/fragno/dist/api/internal/response-stream.js +81 -0
- package/dist/packages/fragno/dist/api/internal/response-stream.js.map +1 -0
- package/dist/packages/fragno/dist/api/internal/route.js +10 -0
- package/dist/packages/fragno/dist/api/internal/route.js.map +1 -0
- package/dist/packages/fragno/dist/api/mutable-request-state.js +97 -0
- package/dist/packages/fragno/dist/api/mutable-request-state.js.map +1 -0
- package/dist/packages/fragno/dist/api/request-context-storage.js +43 -0
- package/dist/packages/fragno/dist/api/request-context-storage.js.map +1 -0
- package/dist/packages/fragno/dist/api/request-input-context.js +118 -0
- package/dist/packages/fragno/dist/api/request-input-context.js.map +1 -0
- package/dist/packages/fragno/dist/api/request-middleware.js +83 -0
- package/dist/packages/fragno/dist/api/request-middleware.js.map +1 -0
- package/dist/packages/fragno/dist/api/request-output-context.js +119 -0
- package/dist/packages/fragno/dist/api/request-output-context.js.map +1 -0
- package/dist/packages/fragno/dist/api/route.js +17 -0
- package/dist/packages/fragno/dist/api/route.js.map +1 -0
- package/dist/packages/fragno/dist/internal/symbols.js +10 -0
- package/dist/packages/fragno/dist/internal/symbols.js.map +1 -0
- package/dist/query/cursor.d.ts +10 -2
- package/dist/query/cursor.d.ts.map +1 -1
- package/dist/query/cursor.js +11 -4
- package/dist/query/cursor.js.map +1 -1
- package/dist/query/execute-unit-of-work.d.ts +123 -0
- package/dist/query/execute-unit-of-work.d.ts.map +1 -0
- package/dist/query/execute-unit-of-work.js +184 -0
- package/dist/query/execute-unit-of-work.js.map +1 -0
- package/dist/query/query.d.ts +3 -3
- package/dist/query/query.d.ts.map +1 -1
- package/dist/query/result-transform.js +4 -2
- package/dist/query/result-transform.js.map +1 -1
- package/dist/query/retry-policy.d.ts +88 -0
- package/dist/query/retry-policy.d.ts.map +1 -0
- package/dist/query/retry-policy.js +61 -0
- package/dist/query/retry-policy.js.map +1 -0
- package/dist/query/unit-of-work.d.ts +171 -32
- package/dist/query/unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work.js +530 -133
- package/dist/query/unit-of-work.js.map +1 -1
- package/dist/schema/serialize.js +12 -7
- package/dist/schema/serialize.js.map +1 -1
- package/dist/with-database.d.ts +28 -0
- package/dist/with-database.d.ts.map +1 -0
- package/dist/with-database.js +34 -0
- package/dist/with-database.js.map +1 -0
- package/package.json +10 -3
- package/src/adapters/adapters.ts +30 -0
- package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +86 -17
- package/src/adapters/drizzle/drizzle-adapter-sqlite.test.ts +291 -7
- package/src/adapters/drizzle/drizzle-adapter.test.ts +3 -51
- package/src/adapters/drizzle/drizzle-adapter.ts +35 -7
- package/src/adapters/drizzle/drizzle-query.ts +25 -15
- package/src/adapters/drizzle/drizzle-uow-compiler-mysql.test.ts +1442 -0
- package/src/adapters/drizzle/drizzle-uow-compiler-sqlite.test.ts +1414 -0
- package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +78 -61
- package/src/adapters/drizzle/drizzle-uow-compiler.ts +123 -42
- package/src/adapters/drizzle/drizzle-uow-decoder.ts +34 -27
- package/src/adapters/drizzle/drizzle-uow-executor.ts +41 -8
- package/src/adapters/drizzle/generate.test.ts +102 -269
- package/src/adapters/drizzle/generate.ts +12 -30
- package/src/adapters/drizzle/test-utils.ts +36 -5
- package/src/adapters/kysely/kysely-adapter-pglite.test.ts +66 -22
- package/src/adapters/kysely/kysely-adapter-sqlite.test.ts +156 -0
- package/src/adapters/kysely/kysely-adapter.ts +25 -2
- package/src/adapters/kysely/kysely-query-compiler.ts +3 -8
- package/src/adapters/kysely/kysely-query.ts +57 -37
- package/src/adapters/kysely/kysely-shared.ts +34 -0
- package/src/adapters/kysely/kysely-uow-compiler.test.ts +62 -74
- package/src/adapters/kysely/kysely-uow-compiler.ts +92 -24
- package/src/adapters/kysely/kysely-uow-executor.ts +26 -7
- package/src/adapters/kysely/kysely-uow-joins.test.ts +33 -50
- package/src/adapters/kysely/migration/execute-base.ts +1 -1
- package/src/db-fragment-definition-builder.test.ts +887 -0
- package/src/db-fragment-definition-builder.ts +506 -0
- package/src/db-fragment-instantiator.test.ts +467 -0
- package/src/db-fragment-integration.test.ts +408 -0
- package/src/fragments/internal-fragment.test.ts +160 -0
- package/src/fragments/internal-fragment.ts +85 -0
- package/src/migration-engine/generation-engine.test.ts +58 -15
- package/src/migration-engine/generation-engine.ts +78 -25
- package/src/mod.ts +35 -43
- package/src/query/cursor.test.ts +119 -0
- package/src/query/cursor.ts +17 -4
- package/src/query/execute-unit-of-work.test.ts +1310 -0
- package/src/query/execute-unit-of-work.ts +463 -0
- package/src/query/query.ts +4 -4
- package/src/query/result-transform.test.ts +129 -0
- package/src/query/result-transform.ts +4 -1
- package/src/query/retry-policy.test.ts +217 -0
- package/src/query/retry-policy.ts +141 -0
- package/src/query/unit-of-work-coordinator.test.ts +833 -0
- package/src/query/unit-of-work-types.test.ts +15 -2
- package/src/query/unit-of-work.test.ts +878 -200
- package/src/query/unit-of-work.ts +963 -321
- package/src/schema/serialize.ts +22 -11
- package/src/with-database.ts +140 -0
- package/tsdown.config.ts +1 -0
- package/dist/fragment.d.ts +0 -54
- package/dist/fragment.d.ts.map +0 -1
- package/dist/fragment.js +0 -92
- package/dist/fragment.js.map +0 -1
- package/dist/shared/settings-schema.js +0 -36
- package/dist/shared/settings-schema.js.map +0 -1
- package/src/fragment.test.ts +0 -341
- package/src/fragment.ts +0 -198
- package/src/shared/settings-schema.ts +0 -61
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FragnoId } from "../schema/create.js";
|
|
2
|
-
import { Cursor } from "./cursor.js";
|
|
3
2
|
import { buildCondition } from "./condition-builder.js";
|
|
3
|
+
import { Cursor } from "./cursor.js";
|
|
4
4
|
|
|
5
5
|
//#region src/query/unit-of-work.ts
|
|
6
6
|
/**
|
|
@@ -338,29 +338,188 @@ function buildJoinIndexed(table, fn) {
|
|
|
338
338
|
fn(builder);
|
|
339
339
|
return compiled;
|
|
340
340
|
}
|
|
341
|
-
function createUnitOfWork(
|
|
342
|
-
return new UnitOfWork(
|
|
341
|
+
function createUnitOfWork(compiler, executor, decoder, schemaNamespaceMap, name) {
|
|
342
|
+
return new UnitOfWork(compiler, executor, decoder, name, void 0, schemaNamespaceMap);
|
|
343
343
|
}
|
|
344
344
|
/**
|
|
345
|
+
* Encapsulates a promise with its resolver/rejecter functions.
|
|
346
|
+
* Simplifies management of deferred promises with built-in error handling.
|
|
347
|
+
*/
|
|
348
|
+
var DeferredPromise = class {
|
|
349
|
+
#resolve;
|
|
350
|
+
#reject;
|
|
351
|
+
#promise;
|
|
352
|
+
constructor() {
|
|
353
|
+
const { promise, resolve, reject } = Promise.withResolvers();
|
|
354
|
+
this.#promise = promise;
|
|
355
|
+
this.#resolve = resolve;
|
|
356
|
+
this.#reject = reject;
|
|
357
|
+
this.#promise.catch(() => {});
|
|
358
|
+
}
|
|
359
|
+
get promise() {
|
|
360
|
+
return this.#promise;
|
|
361
|
+
}
|
|
362
|
+
resolve(value) {
|
|
363
|
+
this.#resolve?.(value);
|
|
364
|
+
}
|
|
365
|
+
reject(error) {
|
|
366
|
+
this.#reject?.(error);
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Reset to a new promise
|
|
370
|
+
*/
|
|
371
|
+
reset() {
|
|
372
|
+
const { promise, resolve, reject } = Promise.withResolvers();
|
|
373
|
+
this.#promise = promise;
|
|
374
|
+
this.#resolve = resolve;
|
|
375
|
+
this.#reject = reject;
|
|
376
|
+
this.#promise.catch(() => {});
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
/**
|
|
380
|
+
* Tracks readiness signals from a group of children.
|
|
381
|
+
* Maintains a promise that resolves when all registered children have signaled.
|
|
382
|
+
*/
|
|
383
|
+
var ReadinessTracker = class {
|
|
384
|
+
#expectedCount = 0;
|
|
385
|
+
#signalCount = 0;
|
|
386
|
+
#resolve;
|
|
387
|
+
#promise = Promise.resolve();
|
|
388
|
+
get promise() {
|
|
389
|
+
return this.#promise;
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Register that we're expecting a signal from a child
|
|
393
|
+
*/
|
|
394
|
+
registerChild() {
|
|
395
|
+
if (this.#expectedCount === 0) {
|
|
396
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
397
|
+
this.#promise = promise;
|
|
398
|
+
this.#resolve = resolve;
|
|
399
|
+
}
|
|
400
|
+
this.#expectedCount++;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Signal that one child is ready
|
|
404
|
+
*/
|
|
405
|
+
signal() {
|
|
406
|
+
this.#signalCount++;
|
|
407
|
+
if (this.#signalCount >= this.#expectedCount && this.#resolve) this.#resolve();
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Reset to initial state
|
|
411
|
+
*/
|
|
412
|
+
reset() {
|
|
413
|
+
this.#expectedCount = 0;
|
|
414
|
+
this.#signalCount = 0;
|
|
415
|
+
this.#resolve = void 0;
|
|
416
|
+
this.#promise = Promise.resolve();
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
/**
|
|
420
|
+
* Manages parent-child relationships and readiness coordination for Unit of Work instances.
|
|
421
|
+
* This allows parent UOWs to wait for all child UOWs to signal readiness before executing phases.
|
|
422
|
+
*/
|
|
423
|
+
var UOWChildCoordinator = class {
|
|
424
|
+
#parent = null;
|
|
425
|
+
#parentCoordinator = null;
|
|
426
|
+
#children = /* @__PURE__ */ new Set();
|
|
427
|
+
#isRestricted = false;
|
|
428
|
+
#retrievalTracker = new ReadinessTracker();
|
|
429
|
+
#mutationTracker = new ReadinessTracker();
|
|
430
|
+
get isRestricted() {
|
|
431
|
+
return this.#isRestricted;
|
|
432
|
+
}
|
|
433
|
+
get parent() {
|
|
434
|
+
return this.#parent;
|
|
435
|
+
}
|
|
436
|
+
get children() {
|
|
437
|
+
return this.#children;
|
|
438
|
+
}
|
|
439
|
+
get retrievalReadinessPromise() {
|
|
440
|
+
return this.#retrievalTracker.promise;
|
|
441
|
+
}
|
|
442
|
+
get mutationReadinessPromise() {
|
|
443
|
+
return this.#mutationTracker.promise;
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Mark this UOW as a restricted child of the given parent
|
|
447
|
+
*/
|
|
448
|
+
setAsRestricted(parent, parentCoordinator) {
|
|
449
|
+
this.#parent = parent;
|
|
450
|
+
this.#parentCoordinator = parentCoordinator;
|
|
451
|
+
this.#isRestricted = true;
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Register a child UOW
|
|
455
|
+
*/
|
|
456
|
+
addChild(child) {
|
|
457
|
+
this.#children.add(child);
|
|
458
|
+
this.#retrievalTracker.registerChild();
|
|
459
|
+
this.#mutationTracker.registerChild();
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Signal that this child is ready for retrieval phase execution.
|
|
463
|
+
* Only valid for restricted (child) UOWs.
|
|
464
|
+
*/
|
|
465
|
+
signalReadyForRetrieval() {
|
|
466
|
+
if (!this.#parentCoordinator) throw new Error("signalReadyForRetrieval() can only be called on restricted child UOWs");
|
|
467
|
+
this.#parentCoordinator.notifyChildReadyForRetrieval();
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Signal that this child is ready for mutation phase execution.
|
|
471
|
+
* Only valid for restricted (child) UOWs.
|
|
472
|
+
*/
|
|
473
|
+
signalReadyForMutation() {
|
|
474
|
+
if (!this.#parentCoordinator) throw new Error("signalReadyForMutation() can only be called on restricted child UOWs");
|
|
475
|
+
this.#parentCoordinator.notifyChildReadyForMutation();
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Notify this coordinator that a child is ready for retrieval (internal use).
|
|
479
|
+
* Called by child UOWs when they signal readiness.
|
|
480
|
+
*/
|
|
481
|
+
notifyChildReadyForRetrieval() {
|
|
482
|
+
this.#retrievalTracker.signal();
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Notify this coordinator that a child is ready for mutation (internal use).
|
|
486
|
+
* Called by child UOWs when they signal readiness.
|
|
487
|
+
*/
|
|
488
|
+
notifyChildReadyForMutation() {
|
|
489
|
+
this.#mutationTracker.signal();
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Reset coordination state for retry support
|
|
493
|
+
*/
|
|
494
|
+
reset() {
|
|
495
|
+
this.#children.clear();
|
|
496
|
+
this.#retrievalTracker.reset();
|
|
497
|
+
this.#mutationTracker.reset();
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
/**
|
|
345
501
|
* Unit of Work implementation with optimistic concurrency control
|
|
346
502
|
*
|
|
347
503
|
* UOW has two phases:
|
|
348
504
|
* 1. Retrieval phase: Read operations to fetch entities with their versions
|
|
349
505
|
* 2. Mutation phase: Write operations that check versions before committing
|
|
350
506
|
*
|
|
507
|
+
* This is the untyped base storage. Use TypedUnitOfWork for type-safe operations.
|
|
508
|
+
*
|
|
351
509
|
* @example
|
|
352
510
|
* ```ts
|
|
353
511
|
* const uow = queryEngine.createUnitOfWork("update-user-balance");
|
|
512
|
+
* const typedUow = uow.forSchema(mySchema);
|
|
354
513
|
*
|
|
355
514
|
* // Retrieval phase
|
|
356
|
-
*
|
|
515
|
+
* typedUow.find("users", (b) => b.whereIndex("primary", (eb) => eb("id", "=", userId)));
|
|
357
516
|
*
|
|
358
517
|
* // Execute retrieval and transition to mutation phase
|
|
359
518
|
* const [users] = await uow.executeRetrieve();
|
|
360
519
|
*
|
|
361
520
|
* // Mutation phase with version check
|
|
362
521
|
* const user = users[0];
|
|
363
|
-
*
|
|
522
|
+
* typedUow.update("users", user.id, (b) => b.set({ balance: newBalance }).check());
|
|
364
523
|
*
|
|
365
524
|
* // Execute mutations
|
|
366
525
|
* const { success } = await uow.executeMutations();
|
|
@@ -369,28 +528,97 @@ function createUnitOfWork(schema, compiler, executor, decoder, name) {
|
|
|
369
528
|
* }
|
|
370
529
|
* ```
|
|
371
530
|
*/
|
|
372
|
-
var UnitOfWork = class {
|
|
373
|
-
#schema;
|
|
531
|
+
var UnitOfWork = class UnitOfWork {
|
|
374
532
|
#name;
|
|
375
533
|
#config;
|
|
534
|
+
#nonce;
|
|
376
535
|
#state = "building-retrieval";
|
|
377
536
|
#retrievalOps = [];
|
|
378
537
|
#mutationOps = [];
|
|
379
538
|
#compiler;
|
|
380
539
|
#executor;
|
|
381
540
|
#decoder;
|
|
541
|
+
#schemaNamespaceMap;
|
|
382
542
|
#retrievalResults;
|
|
383
543
|
#createdInternalIds = [];
|
|
384
|
-
|
|
385
|
-
|
|
544
|
+
#retrievalPhaseDeferred = new DeferredPromise();
|
|
545
|
+
#mutationPhaseDeferred = new DeferredPromise();
|
|
546
|
+
#retrievalError = null;
|
|
547
|
+
#mutationError = null;
|
|
548
|
+
#coordinator = new UOWChildCoordinator();
|
|
549
|
+
constructor(compiler, executor, decoder, name, config, schemaNamespaceMap) {
|
|
386
550
|
this.#compiler = compiler;
|
|
387
551
|
this.#executor = executor;
|
|
388
552
|
this.#decoder = decoder;
|
|
553
|
+
this.#schemaNamespaceMap = schemaNamespaceMap;
|
|
389
554
|
this.#name = name;
|
|
390
555
|
this.#config = config;
|
|
556
|
+
this.#nonce = config?.nonce ?? crypto.randomUUID();
|
|
391
557
|
}
|
|
392
|
-
|
|
393
|
-
|
|
558
|
+
/**
|
|
559
|
+
* Get a schema-specific typed view of this UOW for type-safe operations.
|
|
560
|
+
* Returns a wrapper that provides typed operations for the given schema.
|
|
561
|
+
* The namespace is automatically resolved from the schema-namespace map.
|
|
562
|
+
*/
|
|
563
|
+
forSchema(schema) {
|
|
564
|
+
const resolvedNamespace = this.#schemaNamespaceMap?.get(schema);
|
|
565
|
+
return new TypedUnitOfWork(schema, resolvedNamespace, this);
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Create a restricted child UOW that cannot execute phases.
|
|
569
|
+
* The child shares the same operation storage but must signal readiness
|
|
570
|
+
* before the parent can execute each phase.
|
|
571
|
+
*/
|
|
572
|
+
restrict() {
|
|
573
|
+
const child = new UnitOfWork(this.#compiler, this.#executor, this.#decoder, this.#name, {
|
|
574
|
+
...this.#config,
|
|
575
|
+
nonce: this.#nonce
|
|
576
|
+
}, this.#schemaNamespaceMap);
|
|
577
|
+
child.#coordinator.setAsRestricted(this, this.#coordinator);
|
|
578
|
+
child.#state = this.#state;
|
|
579
|
+
child.#retrievalOps = this.#retrievalOps;
|
|
580
|
+
child.#mutationOps = this.#mutationOps;
|
|
581
|
+
child.#retrievalResults = this.#retrievalResults;
|
|
582
|
+
child.#createdInternalIds = this.#createdInternalIds;
|
|
583
|
+
child.#retrievalPhaseDeferred = this.#retrievalPhaseDeferred;
|
|
584
|
+
child.#mutationPhaseDeferred = this.#mutationPhaseDeferred;
|
|
585
|
+
child.#retrievalError = this.#retrievalError;
|
|
586
|
+
child.#mutationError = this.#mutationError;
|
|
587
|
+
this.#coordinator.addChild(child);
|
|
588
|
+
child.signalReadyForRetrieval();
|
|
589
|
+
child.signalReadyForMutation();
|
|
590
|
+
return child;
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Signal that this child is ready for retrieval phase execution.
|
|
594
|
+
* Only valid for restricted (child) UOWs.
|
|
595
|
+
*/
|
|
596
|
+
signalReadyForRetrieval() {
|
|
597
|
+
this.#coordinator.signalReadyForRetrieval();
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Signal that this child is ready for mutation phase execution.
|
|
601
|
+
* Only valid for restricted (child) UOWs.
|
|
602
|
+
*/
|
|
603
|
+
signalReadyForMutation() {
|
|
604
|
+
this.#coordinator.signalReadyForMutation();
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Reset the UOW to initial state for retry support.
|
|
608
|
+
* Clears operations, resets state, and resets phase promises.
|
|
609
|
+
*/
|
|
610
|
+
reset() {
|
|
611
|
+
if (this.#coordinator.isRestricted) throw new Error("reset() cannot be called on restricted child UOWs");
|
|
612
|
+
this.#retrievalOps = [];
|
|
613
|
+
this.#mutationOps = [];
|
|
614
|
+
this.#retrievalResults = void 0;
|
|
615
|
+
this.#createdInternalIds = [];
|
|
616
|
+
this.#state = "building-retrieval";
|
|
617
|
+
this.#retrievalError = null;
|
|
618
|
+
this.#mutationError = null;
|
|
619
|
+
this.#retrievalPhaseDeferred.reset();
|
|
620
|
+
this.#mutationPhaseDeferred.reset();
|
|
621
|
+
this.#coordinator.reset();
|
|
394
622
|
}
|
|
395
623
|
get state() {
|
|
396
624
|
return this.#state;
|
|
@@ -398,75 +626,300 @@ var UnitOfWork = class {
|
|
|
398
626
|
get name() {
|
|
399
627
|
return this.#name;
|
|
400
628
|
}
|
|
629
|
+
get nonce() {
|
|
630
|
+
return this.#nonce;
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Promise that resolves when the retrieval phase is executed
|
|
634
|
+
* Service methods can await this to coordinate multi-phase logic
|
|
635
|
+
*/
|
|
636
|
+
get retrievalPhase() {
|
|
637
|
+
return this.#retrievalPhaseDeferred.promise;
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Promise that resolves when the mutation phase is executed
|
|
641
|
+
* Service methods can await this to coordinate multi-phase logic
|
|
642
|
+
*/
|
|
643
|
+
get mutationPhase() {
|
|
644
|
+
return this.#mutationPhaseDeferred.promise;
|
|
645
|
+
}
|
|
401
646
|
/**
|
|
402
647
|
* Execute the retrieval phase and transition to mutation phase
|
|
403
648
|
* Returns all results from find operations
|
|
404
649
|
*/
|
|
405
650
|
async executeRetrieve() {
|
|
406
|
-
if (this.#
|
|
651
|
+
if (this.#coordinator.isRestricted) throw new Error("executeRetrieve() cannot be called on restricted child UOWs");
|
|
407
652
|
if (this.#state !== "building-retrieval") throw new Error(`Cannot execute retrieval from state ${this.#state}. Must be in building-retrieval state.`);
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
653
|
+
try {
|
|
654
|
+
await this.#coordinator.retrievalReadinessPromise;
|
|
655
|
+
if (this.#retrievalOps.length === 0) {
|
|
656
|
+
this.#state = "building-mutation";
|
|
657
|
+
const emptyResults = [];
|
|
658
|
+
this.#retrievalPhaseDeferred.resolve(emptyResults);
|
|
659
|
+
return emptyResults;
|
|
660
|
+
}
|
|
661
|
+
const retrievalBatch = [];
|
|
662
|
+
for (const op of this.#retrievalOps) {
|
|
663
|
+
const compiled = this.#compiler.compileRetrievalOperation(op);
|
|
664
|
+
if (compiled !== null) {
|
|
665
|
+
this.#config?.onQuery?.(compiled);
|
|
666
|
+
retrievalBatch.push(compiled);
|
|
667
|
+
}
|
|
414
668
|
}
|
|
669
|
+
if (this.#config?.dryRun) {
|
|
670
|
+
this.#state = "executed";
|
|
671
|
+
const emptyResults = [];
|
|
672
|
+
this.#retrievalPhaseDeferred.resolve(emptyResults);
|
|
673
|
+
return emptyResults;
|
|
674
|
+
}
|
|
675
|
+
const rawResults = await this.#executor.executeRetrievalPhase(retrievalBatch);
|
|
676
|
+
this.#retrievalResults = this.#decoder(rawResults, this.#retrievalOps);
|
|
677
|
+
this.#state = "building-mutation";
|
|
678
|
+
this.#retrievalPhaseDeferred.resolve(this.#retrievalResults);
|
|
679
|
+
return this.#retrievalResults;
|
|
680
|
+
} catch (error) {
|
|
681
|
+
this.#retrievalError = error instanceof Error ? error : new Error(String(error));
|
|
682
|
+
throw error;
|
|
415
683
|
}
|
|
416
|
-
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Execute the mutation phase
|
|
687
|
+
* Returns success flag indicating if mutations completed without conflicts
|
|
688
|
+
*/
|
|
689
|
+
async executeMutations() {
|
|
690
|
+
if (this.#coordinator.isRestricted) throw new Error("executeMutations() cannot be called on restricted child UOWs");
|
|
691
|
+
if (this.#state === "executed") throw new Error(`Cannot execute mutations from state ${this.#state}.`);
|
|
692
|
+
try {
|
|
693
|
+
await this.#coordinator.mutationReadinessPromise;
|
|
694
|
+
const mutationBatch = [];
|
|
695
|
+
for (const op of this.#mutationOps) {
|
|
696
|
+
const compiled = this.#compiler.compileMutationOperation(op);
|
|
697
|
+
if (compiled !== null) {
|
|
698
|
+
this.#config?.onQuery?.(compiled);
|
|
699
|
+
mutationBatch.push(compiled);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
if (this.#config?.dryRun) {
|
|
703
|
+
this.#state = "executed";
|
|
704
|
+
this.#mutationPhaseDeferred.resolve();
|
|
705
|
+
return { success: true };
|
|
706
|
+
}
|
|
707
|
+
const result = await this.#executor.executeMutationPhase(mutationBatch);
|
|
417
708
|
this.#state = "executed";
|
|
418
|
-
|
|
709
|
+
if (result.success) this.#createdInternalIds = result.createdInternalIds;
|
|
710
|
+
this.#mutationPhaseDeferred.resolve();
|
|
711
|
+
return { success: result.success };
|
|
712
|
+
} catch (error) {
|
|
713
|
+
this.#mutationError = error instanceof Error ? error : new Error(String(error));
|
|
714
|
+
throw error;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Get the retrieval operations (for inspection/debugging)
|
|
719
|
+
*/
|
|
720
|
+
getRetrievalOperations() {
|
|
721
|
+
return this.#retrievalOps;
|
|
722
|
+
}
|
|
723
|
+
/**
|
|
724
|
+
* Get the mutation operations (for inspection/debugging)
|
|
725
|
+
*/
|
|
726
|
+
getMutationOperations() {
|
|
727
|
+
return this.#mutationOps;
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* @internal
|
|
731
|
+
* Add a retrieval operation (used by TypedUnitOfWork)
|
|
732
|
+
*/
|
|
733
|
+
addRetrievalOperation(op) {
|
|
734
|
+
if (this.#state !== "building-retrieval") throw new Error(`Cannot add retrieval operation in state ${this.#state}. Must be in building-retrieval state.`);
|
|
735
|
+
this.#retrievalOps.push(op);
|
|
736
|
+
return this.#retrievalOps.length - 1;
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* @internal
|
|
740
|
+
* Add a mutation operation (used by TypedUnitOfWork)
|
|
741
|
+
*/
|
|
742
|
+
addMutationOperation(op) {
|
|
743
|
+
if (this.#state === "executed") throw new Error(`Cannot add mutation operation in executed state.`);
|
|
744
|
+
this.#mutationOps.push(op);
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* Get the IDs of created entities after executeMutations() has been called.
|
|
748
|
+
* Returns FragnoId objects with external IDs (always available) and internal IDs
|
|
749
|
+
* (available when database supports RETURNING).
|
|
750
|
+
*
|
|
751
|
+
* @throws Error if called before executeMutations()
|
|
752
|
+
* @returns Array of FragnoIds in the same order as create() calls
|
|
753
|
+
*/
|
|
754
|
+
getCreatedIds() {
|
|
755
|
+
if (this.#state !== "executed") throw new Error(`getCreatedIds() can only be called after executeMutations(). Current state: ${this.#state}`);
|
|
756
|
+
const createdIds = [];
|
|
757
|
+
let createIndex = 0;
|
|
758
|
+
for (const op of this.#mutationOps) if (op.type === "create") {
|
|
759
|
+
const internalId = this.#createdInternalIds[createIndex] ?? void 0;
|
|
760
|
+
createdIds.push(new FragnoId({
|
|
761
|
+
externalId: op.generatedExternalId,
|
|
762
|
+
internalId,
|
|
763
|
+
version: 0
|
|
764
|
+
}));
|
|
765
|
+
createIndex++;
|
|
419
766
|
}
|
|
420
|
-
|
|
421
|
-
this.#state = "building-mutation";
|
|
422
|
-
return this.#retrievalResults;
|
|
767
|
+
return createdIds;
|
|
423
768
|
}
|
|
424
769
|
/**
|
|
425
|
-
*
|
|
770
|
+
* @internal
|
|
771
|
+
* Compile the unit of work to executable queries for testing
|
|
426
772
|
*/
|
|
773
|
+
compile(compiler) {
|
|
774
|
+
const retrievalBatch = [];
|
|
775
|
+
for (const op of this.#retrievalOps) {
|
|
776
|
+
const compiled = compiler.compileRetrievalOperation(op);
|
|
777
|
+
if (compiled !== null) retrievalBatch.push(compiled);
|
|
778
|
+
}
|
|
779
|
+
const mutationBatch = [];
|
|
780
|
+
for (const op of this.#mutationOps) {
|
|
781
|
+
const compiled = compiler.compileMutationOperation(op);
|
|
782
|
+
if (compiled !== null) mutationBatch.push(compiled);
|
|
783
|
+
}
|
|
784
|
+
return {
|
|
785
|
+
name: this.#name,
|
|
786
|
+
retrievalBatch,
|
|
787
|
+
mutationBatch
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
};
|
|
791
|
+
/**
|
|
792
|
+
* A typed facade around a UnitOfWork that provides type-safe operations for a specific schema.
|
|
793
|
+
* All operations are stored in the underlying UOW, but this facade ensures type safety and
|
|
794
|
+
* filters retrieval results to only include operations added through this facade.
|
|
795
|
+
*/
|
|
796
|
+
var TypedUnitOfWork = class {
|
|
797
|
+
#schema;
|
|
798
|
+
#namespace;
|
|
799
|
+
#uow;
|
|
800
|
+
#operationIndices = [];
|
|
801
|
+
#cachedRetrievalPhase;
|
|
802
|
+
constructor(schema, namespace, uow) {
|
|
803
|
+
this.#schema = schema;
|
|
804
|
+
this.#namespace = namespace;
|
|
805
|
+
this.#uow = uow;
|
|
806
|
+
}
|
|
807
|
+
get $results() {
|
|
808
|
+
throw new Error("type only");
|
|
809
|
+
}
|
|
810
|
+
get schema() {
|
|
811
|
+
return this.#schema;
|
|
812
|
+
}
|
|
813
|
+
get name() {
|
|
814
|
+
return this.#uow.name;
|
|
815
|
+
}
|
|
816
|
+
get nonce() {
|
|
817
|
+
return this.#uow.nonce;
|
|
818
|
+
}
|
|
819
|
+
get state() {
|
|
820
|
+
return this.#uow.state;
|
|
821
|
+
}
|
|
822
|
+
get retrievalPhase() {
|
|
823
|
+
if (!this.#cachedRetrievalPhase) this.#cachedRetrievalPhase = this.#uow.retrievalPhase.then((allResults) => {
|
|
824
|
+
const allOperations = this.#uow.getRetrievalOperations();
|
|
825
|
+
return this.#operationIndices.map((opIndex) => {
|
|
826
|
+
const result = allResults[opIndex];
|
|
827
|
+
const operation = allOperations[opIndex];
|
|
828
|
+
if (operation?.type === "find" && operation.withSingleResult) return Array.isArray(result) ? result[0] ?? null : result;
|
|
829
|
+
return result;
|
|
830
|
+
});
|
|
831
|
+
});
|
|
832
|
+
return this.#cachedRetrievalPhase;
|
|
833
|
+
}
|
|
834
|
+
get mutationPhase() {
|
|
835
|
+
return this.#uow.mutationPhase;
|
|
836
|
+
}
|
|
837
|
+
getRetrievalOperations() {
|
|
838
|
+
return this.#uow.getRetrievalOperations();
|
|
839
|
+
}
|
|
840
|
+
getMutationOperations() {
|
|
841
|
+
return this.#uow.getMutationOperations();
|
|
842
|
+
}
|
|
843
|
+
getCreatedIds() {
|
|
844
|
+
return this.#uow.getCreatedIds();
|
|
845
|
+
}
|
|
846
|
+
async executeRetrieve() {
|
|
847
|
+
return this.#uow.executeRetrieve();
|
|
848
|
+
}
|
|
849
|
+
async executeMutations() {
|
|
850
|
+
return this.#uow.executeMutations();
|
|
851
|
+
}
|
|
852
|
+
restrict() {
|
|
853
|
+
return this.#uow.restrict();
|
|
854
|
+
}
|
|
855
|
+
reset() {
|
|
856
|
+
return this.#uow.reset();
|
|
857
|
+
}
|
|
858
|
+
forSchema(schema) {
|
|
859
|
+
return this.#uow.forSchema(schema);
|
|
860
|
+
}
|
|
861
|
+
compile(compiler) {
|
|
862
|
+
return this.#uow.compile(compiler);
|
|
863
|
+
}
|
|
427
864
|
find(tableName, builderFn) {
|
|
428
|
-
if (this.#state !== "building-retrieval") throw new Error(`find() can only be called during retrieval phase. Current state: ${this.#state}`);
|
|
429
865
|
const table = this.#schema.tables[tableName];
|
|
430
866
|
if (!table) throw new Error(`Table ${tableName} not found in schema`);
|
|
431
867
|
const builder = new FindBuilder(tableName, table);
|
|
432
868
|
if (builderFn) builderFn(builder);
|
|
433
869
|
else builder.whereIndex("primary");
|
|
434
870
|
const { indexName, options, type } = builder.build();
|
|
435
|
-
this.#
|
|
871
|
+
const operationIndex = this.#uow.addRetrievalOperation({
|
|
436
872
|
type,
|
|
873
|
+
schema: this.#schema,
|
|
874
|
+
namespace: this.#namespace,
|
|
437
875
|
table,
|
|
438
876
|
indexName,
|
|
439
877
|
options
|
|
440
878
|
});
|
|
879
|
+
this.#operationIndices.push(operationIndex);
|
|
880
|
+
return this;
|
|
881
|
+
}
|
|
882
|
+
findFirst(tableName, builderFn) {
|
|
883
|
+
const table = this.#schema.tables[tableName];
|
|
884
|
+
if (!table) throw new Error(`Table ${tableName} not found in schema`);
|
|
885
|
+
const builder = new FindBuilder(tableName, table);
|
|
886
|
+
if (builderFn) builderFn(builder);
|
|
887
|
+
else builder.whereIndex("primary");
|
|
888
|
+
builder.pageSize(1);
|
|
889
|
+
const { indexName, options, type } = builder.build();
|
|
890
|
+
const operationIndex = this.#uow.addRetrievalOperation({
|
|
891
|
+
type,
|
|
892
|
+
schema: this.#schema,
|
|
893
|
+
namespace: this.#namespace,
|
|
894
|
+
table,
|
|
895
|
+
indexName,
|
|
896
|
+
options,
|
|
897
|
+
withSingleResult: true
|
|
898
|
+
});
|
|
899
|
+
this.#operationIndices.push(operationIndex);
|
|
441
900
|
return this;
|
|
442
901
|
}
|
|
443
|
-
/**
|
|
444
|
-
* Add a find operation with cursor metadata (retrieval phase only)
|
|
445
|
-
*/
|
|
446
902
|
findWithCursor(tableName, builderFn) {
|
|
447
|
-
if (this.#state !== "building-retrieval") throw new Error(`findWithCursor() can only be called during retrieval phase. Current state: ${this.#state}`);
|
|
448
903
|
const table = this.#schema.tables[tableName];
|
|
449
904
|
if (!table) throw new Error(`Table ${tableName} not found in schema`);
|
|
450
905
|
const builder = new FindBuilder(tableName, table);
|
|
451
906
|
builderFn(builder);
|
|
452
907
|
const { indexName, options, type } = builder.build();
|
|
453
|
-
this.#
|
|
908
|
+
const operationIndex = this.#uow.addRetrievalOperation({
|
|
454
909
|
type,
|
|
910
|
+
schema: this.#schema,
|
|
911
|
+
namespace: this.#namespace,
|
|
455
912
|
table,
|
|
456
913
|
indexName,
|
|
457
914
|
options,
|
|
458
915
|
withCursor: true
|
|
459
916
|
});
|
|
917
|
+
this.#operationIndices.push(operationIndex);
|
|
460
918
|
return this;
|
|
461
919
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
*/
|
|
466
|
-
create(table, values) {
|
|
467
|
-
if (this.#state === "executed") throw new Error(`create() can only be called during mutation phase.`);
|
|
468
|
-
const tableSchema = this.#schema.tables[table];
|
|
469
|
-
if (!tableSchema) throw new Error(`Table ${table} not found in schema`);
|
|
920
|
+
create(tableName, values) {
|
|
921
|
+
const tableSchema = this.#schema.tables[tableName];
|
|
922
|
+
if (!tableSchema) throw new Error(`Table ${tableName} not found in schema`);
|
|
470
923
|
const idColumn = tableSchema.getIdColumn();
|
|
471
924
|
let externalId;
|
|
472
925
|
let updatedValues = values;
|
|
@@ -482,126 +935,70 @@ var UnitOfWork = class {
|
|
|
482
935
|
[idColumn.ormName]: externalId
|
|
483
936
|
};
|
|
484
937
|
}
|
|
485
|
-
this.#
|
|
938
|
+
this.#uow.addMutationOperation({
|
|
486
939
|
type: "create",
|
|
487
|
-
|
|
940
|
+
schema: this.#schema,
|
|
941
|
+
namespace: this.#namespace,
|
|
942
|
+
table: tableName,
|
|
488
943
|
values: updatedValues,
|
|
489
944
|
generatedExternalId: externalId
|
|
490
945
|
});
|
|
491
946
|
return FragnoId.fromExternal(externalId, 0);
|
|
492
947
|
}
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
*/
|
|
496
|
-
update(table, id, builderFn) {
|
|
497
|
-
if (this.#state === "executed") throw new Error(`update() can only be called during mutation phase.`);
|
|
498
|
-
const builder = new UpdateBuilder(table, id);
|
|
948
|
+
update(tableName, id, builderFn) {
|
|
949
|
+
const builder = new UpdateBuilder(tableName, id);
|
|
499
950
|
builderFn(builder);
|
|
500
951
|
const { id: opId, checkVersion, set } = builder.build();
|
|
501
|
-
this.#
|
|
952
|
+
this.#uow.addMutationOperation({
|
|
502
953
|
type: "update",
|
|
503
|
-
|
|
954
|
+
schema: this.#schema,
|
|
955
|
+
namespace: this.#namespace,
|
|
956
|
+
table: tableName,
|
|
504
957
|
id: opId,
|
|
505
958
|
checkVersion,
|
|
506
959
|
set
|
|
507
960
|
});
|
|
508
961
|
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
*/
|
|
512
|
-
delete(table, id, builderFn) {
|
|
513
|
-
if (this.#state === "executed") throw new Error(`delete() can only be called during mutation phase.`);
|
|
514
|
-
const builder = new DeleteBuilder(table, id);
|
|
962
|
+
delete(tableName, id, builderFn) {
|
|
963
|
+
const builder = new DeleteBuilder(tableName, id);
|
|
515
964
|
builderFn?.(builder);
|
|
516
965
|
const { id: opId, checkVersion } = builder.build();
|
|
517
|
-
this.#
|
|
966
|
+
this.#uow.addMutationOperation({
|
|
518
967
|
type: "delete",
|
|
519
|
-
|
|
968
|
+
schema: this.#schema,
|
|
969
|
+
namespace: this.#namespace,
|
|
970
|
+
table: tableName,
|
|
520
971
|
id: opId,
|
|
521
972
|
checkVersion
|
|
522
973
|
});
|
|
523
974
|
}
|
|
524
975
|
/**
|
|
525
|
-
*
|
|
526
|
-
*
|
|
527
|
-
*/
|
|
528
|
-
async executeMutations() {
|
|
529
|
-
if (this.#state === "executed") throw new Error(`Cannot execute mutations from state ${this.#state}.`);
|
|
530
|
-
const mutationBatch = [];
|
|
531
|
-
for (const op of this.#mutationOps) {
|
|
532
|
-
const compiled = this.#compiler.compileMutationOperation(op);
|
|
533
|
-
if (compiled !== null) {
|
|
534
|
-
this.#config?.onQuery?.(compiled);
|
|
535
|
-
mutationBatch.push(compiled);
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
if (this.#config?.dryRun) {
|
|
539
|
-
this.#state = "executed";
|
|
540
|
-
return { success: true };
|
|
541
|
-
}
|
|
542
|
-
const result = await this.#executor.executeMutationPhase(mutationBatch);
|
|
543
|
-
this.#state = "executed";
|
|
544
|
-
if (result.success) this.#createdInternalIds = result.createdInternalIds;
|
|
545
|
-
return { success: result.success };
|
|
546
|
-
}
|
|
547
|
-
/**
|
|
548
|
-
* Get the retrieval operations (for inspection/debugging)
|
|
549
|
-
*/
|
|
550
|
-
getRetrievalOperations() {
|
|
551
|
-
return this.#retrievalOps;
|
|
552
|
-
}
|
|
553
|
-
/**
|
|
554
|
-
* Get the mutation operations (for inspection/debugging)
|
|
555
|
-
*/
|
|
556
|
-
getMutationOperations() {
|
|
557
|
-
return this.#mutationOps;
|
|
558
|
-
}
|
|
559
|
-
/**
|
|
560
|
-
* Get the IDs of created entities after executeMutations() has been called.
|
|
561
|
-
* Returns FragnoId objects with external IDs (always available) and internal IDs
|
|
562
|
-
* (available when database supports RETURNING).
|
|
976
|
+
* Check that a record's version hasn't changed since retrieval.
|
|
977
|
+
* This is useful for ensuring related records remain unchanged during a transaction.
|
|
563
978
|
*
|
|
564
|
-
* @
|
|
565
|
-
* @
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
internalId,
|
|
576
|
-
version: 0
|
|
577
|
-
}));
|
|
578
|
-
createIndex++;
|
|
579
|
-
}
|
|
580
|
-
return createdIds;
|
|
581
|
-
}
|
|
582
|
-
/**
|
|
583
|
-
* @internal
|
|
584
|
-
* Compile the unit of work to executable queries for testing
|
|
979
|
+
* @param tableName - The table name
|
|
980
|
+
* @param id - The FragnoId with version information (string IDs are not allowed)
|
|
981
|
+
* @throws Error if the ID is a string without version information
|
|
982
|
+
*
|
|
983
|
+
* @example
|
|
984
|
+
* ```ts
|
|
985
|
+
* // Ensure both accounts haven't changed before creating a transfer
|
|
986
|
+
* uow.check("accounts", fromAccount.id);
|
|
987
|
+
* uow.check("accounts", toAccount.id);
|
|
988
|
+
* uow.create("transactions", { fromAccountId, toAccountId, amount });
|
|
989
|
+
* ```
|
|
585
990
|
*/
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
const compiled = compiler.compileMutationOperation(op);
|
|
595
|
-
if (compiled !== null) mutationBatch.push(compiled);
|
|
596
|
-
}
|
|
597
|
-
return {
|
|
598
|
-
name: this.#name,
|
|
599
|
-
retrievalBatch,
|
|
600
|
-
mutationBatch
|
|
601
|
-
};
|
|
991
|
+
check(tableName, id) {
|
|
992
|
+
this.#uow.addMutationOperation({
|
|
993
|
+
type: "check",
|
|
994
|
+
schema: this.#schema,
|
|
995
|
+
namespace: this.#namespace,
|
|
996
|
+
table: tableName,
|
|
997
|
+
id
|
|
998
|
+
});
|
|
602
999
|
}
|
|
603
1000
|
};
|
|
604
1001
|
|
|
605
1002
|
//#endregion
|
|
606
|
-
export { DeleteBuilder, FindBuilder, JoinFindBuilder, UnitOfWork, UpdateBuilder, buildJoinIndexed, createUnitOfWork };
|
|
1003
|
+
export { DeleteBuilder, FindBuilder, JoinFindBuilder, TypedUnitOfWork, UnitOfWork, UpdateBuilder, buildJoinIndexed, createUnitOfWork };
|
|
607
1004
|
//# sourceMappingURL=unit-of-work.js.map
|