@fragno-dev/db 0.1.14 → 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 -139
- package/CHANGELOG.md +24 -0
- package/dist/adapters/adapters.d.ts +15 -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 +3 -1
- package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-adapter.js +9 -2
- package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-query.js +2 -2
- package/dist/adapters/drizzle/drizzle-query.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.js +27 -8
- package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-decoder.js +22 -15
- 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/kysely/kysely-adapter.d.ts +3 -1
- package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
- package/dist/adapters/kysely/kysely-adapter.js +7 -1
- 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 +25 -18
- package/dist/adapters/kysely/kysely-query.js.map +1 -1
- package/dist/adapters/kysely/kysely-shared.d.ts +3 -0
- package/dist/adapters/kysely/kysely-shared.d.ts.map +1 -1
- 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 +34 -11
- 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 -20
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +7 -35
- 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 +2 -2
- 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 +104 -50
- package/dist/query/unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work.js +384 -194
- 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 +9 -2
- package/src/adapters/adapters.ts +16 -0
- package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +80 -16
- package/src/adapters/drizzle/drizzle-adapter-sqlite.test.ts +158 -2
- package/src/adapters/drizzle/drizzle-adapter.test.ts +3 -51
- package/src/adapters/drizzle/drizzle-adapter.ts +20 -7
- package/src/adapters/drizzle/drizzle-query.ts +1 -2
- 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 +21 -4
- package/src/adapters/drizzle/drizzle-uow-compiler.ts +44 -3
- package/src/adapters/drizzle/drizzle-uow-decoder.ts +32 -22
- 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 +64 -20
- package/src/adapters/kysely/kysely-adapter-sqlite.test.ts +156 -0
- package/src/adapters/kysely/kysely-adapter.ts +9 -1
- package/src/adapters/kysely/kysely-query-compiler.ts +3 -8
- package/src/adapters/kysely/kysely-query.ts +34 -25
- package/src/adapters/kysely/kysely-shared.ts +34 -0
- package/src/adapters/kysely/kysely-uow-compiler.test.ts +61 -73
- package/src/adapters/kysely/kysely-uow-compiler.ts +44 -12
- package/src/adapters/kysely/kysely-uow-executor.ts +26 -7
- package/src/adapters/kysely/kysely-uow-joins.test.ts +31 -48
- 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 +25 -52
- 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 +2 -2
- 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 +2 -2
- package/src/query/unit-of-work.test.ts +873 -191
- package/src/query/unit-of-work.ts +602 -409
- package/src/schema/serialize.ts +22 -11
- package/src/with-database.ts +140 -0
- package/tsdown.config.ts +1 -0
- package/dist/bind-services.d.ts +0 -7
- package/dist/bind-services.d.ts.map +0 -1
- package/dist/bind-services.js +0 -14
- package/dist/bind-services.js.map +0 -1
- package/dist/fragment.d.ts +0 -173
- package/dist/fragment.d.ts.map +0 -1
- package/dist/fragment.js +0 -191
- 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/bind-services.test.ts +0 -214
- package/src/bind-services.ts +0 -37
- package/src/db-fragment.test.ts +0 -800
- package/src/fragment.ts +0 -727
- package/src/query/unit-of-work-multi-schema.test.ts +0 -64
- package/src/shared/settings-schema.ts +0 -61
- package/src/uow-context-integration.test.ts +0 -102
- package/src/uow-context.test.ts +0 -182
|
@@ -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,10 +528,10 @@ 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 = [];
|
|
@@ -382,39 +541,84 @@ var UnitOfWork = class {
|
|
|
382
541
|
#schemaNamespaceMap;
|
|
383
542
|
#retrievalResults;
|
|
384
543
|
#createdInternalIds = [];
|
|
385
|
-
#
|
|
386
|
-
#
|
|
387
|
-
#
|
|
388
|
-
#
|
|
389
|
-
|
|
390
|
-
|
|
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) {
|
|
391
550
|
this.#compiler = compiler;
|
|
392
551
|
this.#executor = executor;
|
|
393
552
|
this.#decoder = decoder;
|
|
553
|
+
this.#schemaNamespaceMap = schemaNamespaceMap;
|
|
394
554
|
this.#name = name;
|
|
395
555
|
this.#config = config;
|
|
396
|
-
this.#
|
|
397
|
-
this.#retrievalPhasePromise = new Promise((resolve) => {
|
|
398
|
-
this.#retrievalPhaseResolve = resolve;
|
|
399
|
-
});
|
|
400
|
-
this.#mutationPhasePromise = new Promise((resolve) => {
|
|
401
|
-
this.#mutationPhaseResolve = resolve;
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
get schema() {
|
|
405
|
-
return this.#schema;
|
|
406
|
-
}
|
|
407
|
-
get $results() {
|
|
408
|
-
throw new Error("type only");
|
|
556
|
+
this.#nonce = config?.nonce ?? crypto.randomUUID();
|
|
409
557
|
}
|
|
410
558
|
/**
|
|
411
|
-
* Get a schema-specific view of this UOW for type-safe operations
|
|
412
|
-
* Returns a wrapper that
|
|
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.
|
|
413
561
|
* The namespace is automatically resolved from the schema-namespace map.
|
|
414
562
|
*/
|
|
415
563
|
forSchema(schema) {
|
|
416
564
|
const resolvedNamespace = this.#schemaNamespaceMap?.get(schema);
|
|
417
|
-
return new
|
|
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();
|
|
418
622
|
}
|
|
419
623
|
get state() {
|
|
420
624
|
return this.#state;
|
|
@@ -422,175 +626,93 @@ var UnitOfWork = class {
|
|
|
422
626
|
get name() {
|
|
423
627
|
return this.#name;
|
|
424
628
|
}
|
|
629
|
+
get nonce() {
|
|
630
|
+
return this.#nonce;
|
|
631
|
+
}
|
|
425
632
|
/**
|
|
426
633
|
* Promise that resolves when the retrieval phase is executed
|
|
427
634
|
* Service methods can await this to coordinate multi-phase logic
|
|
428
635
|
*/
|
|
429
636
|
get retrievalPhase() {
|
|
430
|
-
return this.#
|
|
637
|
+
return this.#retrievalPhaseDeferred.promise;
|
|
431
638
|
}
|
|
432
639
|
/**
|
|
433
640
|
* Promise that resolves when the mutation phase is executed
|
|
434
641
|
* Service methods can await this to coordinate multi-phase logic
|
|
435
642
|
*/
|
|
436
643
|
get mutationPhase() {
|
|
437
|
-
return this.#
|
|
644
|
+
return this.#mutationPhaseDeferred.promise;
|
|
438
645
|
}
|
|
439
646
|
/**
|
|
440
647
|
* Execute the retrieval phase and transition to mutation phase
|
|
441
648
|
* Returns all results from find operations
|
|
442
649
|
*/
|
|
443
650
|
async executeRetrieve() {
|
|
651
|
+
if (this.#coordinator.isRestricted) throw new Error("executeRetrieve() cannot be called on restricted child UOWs");
|
|
444
652
|
if (this.#state !== "building-retrieval") throw new Error(`Cannot execute retrieval from state ${this.#state}. Must be in building-retrieval state.`);
|
|
445
|
-
|
|
446
|
-
this.#
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
for (const op of this.#retrievalOps) {
|
|
453
|
-
const compiled = this.#compiler.compileRetrievalOperation(op);
|
|
454
|
-
if (compiled !== null) {
|
|
455
|
-
this.#config?.onQuery?.(compiled);
|
|
456
|
-
retrievalBatch.push(compiled);
|
|
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;
|
|
457
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
|
+
}
|
|
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;
|
|
458
683
|
}
|
|
459
|
-
if (this.#config?.dryRun) {
|
|
460
|
-
this.#state = "executed";
|
|
461
|
-
return [];
|
|
462
|
-
}
|
|
463
|
-
const rawResults = await this.#executor.executeRetrievalPhase(retrievalBatch);
|
|
464
|
-
this.#retrievalResults = this.#decoder(rawResults, this.#retrievalOps);
|
|
465
|
-
this.#state = "building-mutation";
|
|
466
|
-
this.#retrievalPhaseResolve?.(this.#retrievalResults);
|
|
467
|
-
return this.#retrievalResults;
|
|
468
|
-
}
|
|
469
|
-
find(tableName, builderFn) {
|
|
470
|
-
if (this.#state !== "building-retrieval") throw new Error(`find() can only be called during retrieval phase. Current state: ${this.#state}`);
|
|
471
|
-
const table = this.#schema.tables[tableName];
|
|
472
|
-
if (!table) throw new Error(`Table ${tableName} not found in schema`);
|
|
473
|
-
const builder = new FindBuilder(tableName, table);
|
|
474
|
-
if (builderFn) builderFn(builder);
|
|
475
|
-
else builder.whereIndex("primary");
|
|
476
|
-
const { indexName, options, type } = builder.build();
|
|
477
|
-
this.#retrievalOps.push({
|
|
478
|
-
type,
|
|
479
|
-
schema: this.#schema,
|
|
480
|
-
table,
|
|
481
|
-
indexName,
|
|
482
|
-
options
|
|
483
|
-
});
|
|
484
|
-
return this;
|
|
485
|
-
}
|
|
486
|
-
/**
|
|
487
|
-
* Add a find operation with cursor metadata (retrieval phase only)
|
|
488
|
-
*/
|
|
489
|
-
findWithCursor(tableName, builderFn) {
|
|
490
|
-
if (this.#state !== "building-retrieval") throw new Error(`findWithCursor() can only be called during retrieval phase. Current state: ${this.#state}`);
|
|
491
|
-
const table = this.#schema.tables[tableName];
|
|
492
|
-
if (!table) throw new Error(`Table ${tableName} not found in schema`);
|
|
493
|
-
const builder = new FindBuilder(tableName, table);
|
|
494
|
-
builderFn(builder);
|
|
495
|
-
const { indexName, options, type } = builder.build();
|
|
496
|
-
this.#retrievalOps.push({
|
|
497
|
-
type,
|
|
498
|
-
schema: this.#schema,
|
|
499
|
-
table,
|
|
500
|
-
indexName,
|
|
501
|
-
options,
|
|
502
|
-
withCursor: true
|
|
503
|
-
});
|
|
504
|
-
return this;
|
|
505
|
-
}
|
|
506
|
-
/**
|
|
507
|
-
* Add a create operation (mutation phase only)
|
|
508
|
-
* Returns a FragnoId with the external ID that can be used immediately in subsequent operations
|
|
509
|
-
*/
|
|
510
|
-
create(table, values) {
|
|
511
|
-
if (this.#state === "executed") throw new Error(`create() can only be called during mutation phase.`);
|
|
512
|
-
const tableSchema = this.#schema.tables[table];
|
|
513
|
-
if (!tableSchema) throw new Error(`Table ${table} not found in schema`);
|
|
514
|
-
const idColumn = tableSchema.getIdColumn();
|
|
515
|
-
let externalId;
|
|
516
|
-
let updatedValues = values;
|
|
517
|
-
const providedIdValue = values[idColumn.ormName];
|
|
518
|
-
if (providedIdValue !== void 0) if (typeof providedIdValue === "object" && providedIdValue !== null && "externalId" in providedIdValue) externalId = providedIdValue.externalId;
|
|
519
|
-
else externalId = providedIdValue;
|
|
520
|
-
else {
|
|
521
|
-
const generated = idColumn.generateDefaultValue();
|
|
522
|
-
if (generated === void 0) throw new Error(`No ID value provided and ID column ${idColumn.ormName} has no default generator`);
|
|
523
|
-
externalId = generated;
|
|
524
|
-
updatedValues = {
|
|
525
|
-
...values,
|
|
526
|
-
[idColumn.ormName]: externalId
|
|
527
|
-
};
|
|
528
|
-
}
|
|
529
|
-
this.#mutationOps.push({
|
|
530
|
-
type: "create",
|
|
531
|
-
schema: this.#schema,
|
|
532
|
-
table,
|
|
533
|
-
values: updatedValues,
|
|
534
|
-
generatedExternalId: externalId
|
|
535
|
-
});
|
|
536
|
-
return FragnoId.fromExternal(externalId, 0);
|
|
537
|
-
}
|
|
538
|
-
/**
|
|
539
|
-
* Add an update operation using a builder callback (mutation phase only)
|
|
540
|
-
*/
|
|
541
|
-
update(table, id, builderFn) {
|
|
542
|
-
if (this.#state === "executed") throw new Error(`update() can only be called during mutation phase.`);
|
|
543
|
-
const builder = new UpdateBuilder(table, id);
|
|
544
|
-
builderFn(builder);
|
|
545
|
-
const { id: opId, checkVersion, set } = builder.build();
|
|
546
|
-
this.#mutationOps.push({
|
|
547
|
-
type: "update",
|
|
548
|
-
schema: this.#schema,
|
|
549
|
-
table,
|
|
550
|
-
id: opId,
|
|
551
|
-
checkVersion,
|
|
552
|
-
set
|
|
553
|
-
});
|
|
554
|
-
}
|
|
555
|
-
/**
|
|
556
|
-
* Add a delete operation using a builder callback (mutation phase only)
|
|
557
|
-
*/
|
|
558
|
-
delete(table, id, builderFn) {
|
|
559
|
-
if (this.#state === "executed") throw new Error(`delete() can only be called during mutation phase.`);
|
|
560
|
-
const builder = new DeleteBuilder(table, id);
|
|
561
|
-
builderFn?.(builder);
|
|
562
|
-
const { id: opId, checkVersion } = builder.build();
|
|
563
|
-
this.#mutationOps.push({
|
|
564
|
-
type: "delete",
|
|
565
|
-
schema: this.#schema,
|
|
566
|
-
table,
|
|
567
|
-
id: opId,
|
|
568
|
-
checkVersion
|
|
569
|
-
});
|
|
570
684
|
}
|
|
571
685
|
/**
|
|
572
686
|
* Execute the mutation phase
|
|
573
687
|
* Returns success flag indicating if mutations completed without conflicts
|
|
574
688
|
*/
|
|
575
689
|
async executeMutations() {
|
|
690
|
+
if (this.#coordinator.isRestricted) throw new Error("executeMutations() cannot be called on restricted child UOWs");
|
|
576
691
|
if (this.#state === "executed") throw new Error(`Cannot execute mutations from state ${this.#state}.`);
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
const
|
|
580
|
-
|
|
581
|
-
this.#
|
|
582
|
-
|
|
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
|
+
}
|
|
583
701
|
}
|
|
584
|
-
|
|
585
|
-
|
|
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);
|
|
586
708
|
this.#state = "executed";
|
|
587
|
-
|
|
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;
|
|
588
715
|
}
|
|
589
|
-
const result = await this.#executor.executeMutationPhase(mutationBatch);
|
|
590
|
-
this.#state = "executed";
|
|
591
|
-
if (result.success) this.#createdInternalIds = result.createdInternalIds;
|
|
592
|
-
this.#mutationPhaseResolve?.();
|
|
593
|
-
return { success: result.success };
|
|
594
716
|
}
|
|
595
717
|
/**
|
|
596
718
|
* Get the retrieval operations (for inspection/debugging)
|
|
@@ -606,17 +728,19 @@ var UnitOfWork = class {
|
|
|
606
728
|
}
|
|
607
729
|
/**
|
|
608
730
|
* @internal
|
|
609
|
-
* Add a retrieval operation (used by
|
|
731
|
+
* Add a retrieval operation (used by TypedUnitOfWork)
|
|
610
732
|
*/
|
|
611
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.`);
|
|
612
735
|
this.#retrievalOps.push(op);
|
|
613
736
|
return this.#retrievalOps.length - 1;
|
|
614
737
|
}
|
|
615
738
|
/**
|
|
616
739
|
* @internal
|
|
617
|
-
* Add a mutation operation (used by
|
|
740
|
+
* Add a mutation operation (used by TypedUnitOfWork)
|
|
618
741
|
*/
|
|
619
742
|
addMutationOperation(op) {
|
|
743
|
+
if (this.#state === "executed") throw new Error(`Cannot add mutation operation in executed state.`);
|
|
620
744
|
this.#mutationOps.push(op);
|
|
621
745
|
}
|
|
622
746
|
/**
|
|
@@ -665,18 +789,20 @@ var UnitOfWork = class {
|
|
|
665
789
|
}
|
|
666
790
|
};
|
|
667
791
|
/**
|
|
668
|
-
* A
|
|
669
|
-
* All operations are stored in the
|
|
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.
|
|
670
795
|
*/
|
|
671
|
-
var
|
|
796
|
+
var TypedUnitOfWork = class {
|
|
672
797
|
#schema;
|
|
673
798
|
#namespace;
|
|
674
|
-
#
|
|
799
|
+
#uow;
|
|
675
800
|
#operationIndices = [];
|
|
676
|
-
|
|
801
|
+
#cachedRetrievalPhase;
|
|
802
|
+
constructor(schema, namespace, uow) {
|
|
677
803
|
this.#schema = schema;
|
|
678
804
|
this.#namespace = namespace;
|
|
679
|
-
this.#
|
|
805
|
+
this.#uow = uow;
|
|
680
806
|
}
|
|
681
807
|
get $results() {
|
|
682
808
|
throw new Error("type only");
|
|
@@ -685,33 +811,55 @@ var UnitOfWorkSchemaView = class {
|
|
|
685
811
|
return this.#schema;
|
|
686
812
|
}
|
|
687
813
|
get name() {
|
|
688
|
-
return this.#
|
|
814
|
+
return this.#uow.name;
|
|
815
|
+
}
|
|
816
|
+
get nonce() {
|
|
817
|
+
return this.#uow.nonce;
|
|
689
818
|
}
|
|
690
819
|
get state() {
|
|
691
|
-
return this.#
|
|
820
|
+
return this.#uow.state;
|
|
692
821
|
}
|
|
693
822
|
get retrievalPhase() {
|
|
694
|
-
|
|
695
|
-
|
|
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
|
+
});
|
|
696
831
|
});
|
|
832
|
+
return this.#cachedRetrievalPhase;
|
|
697
833
|
}
|
|
698
834
|
get mutationPhase() {
|
|
699
|
-
return this.#
|
|
835
|
+
return this.#uow.mutationPhase;
|
|
700
836
|
}
|
|
701
837
|
getRetrievalOperations() {
|
|
702
|
-
return this.#
|
|
838
|
+
return this.#uow.getRetrievalOperations();
|
|
703
839
|
}
|
|
704
840
|
getMutationOperations() {
|
|
705
|
-
return this.#
|
|
841
|
+
return this.#uow.getMutationOperations();
|
|
706
842
|
}
|
|
707
843
|
getCreatedIds() {
|
|
708
|
-
return this.#
|
|
844
|
+
return this.#uow.getCreatedIds();
|
|
709
845
|
}
|
|
710
846
|
async executeRetrieve() {
|
|
711
|
-
return this.#
|
|
847
|
+
return this.#uow.executeRetrieve();
|
|
712
848
|
}
|
|
713
849
|
async executeMutations() {
|
|
714
|
-
return this.#
|
|
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);
|
|
715
863
|
}
|
|
716
864
|
find(tableName, builderFn) {
|
|
717
865
|
const table = this.#schema.tables[tableName];
|
|
@@ -720,7 +868,7 @@ var UnitOfWorkSchemaView = class {
|
|
|
720
868
|
if (builderFn) builderFn(builder);
|
|
721
869
|
else builder.whereIndex("primary");
|
|
722
870
|
const { indexName, options, type } = builder.build();
|
|
723
|
-
const operationIndex = this.#
|
|
871
|
+
const operationIndex = this.#uow.addRetrievalOperation({
|
|
724
872
|
type,
|
|
725
873
|
schema: this.#schema,
|
|
726
874
|
namespace: this.#namespace,
|
|
@@ -731,13 +879,33 @@ var UnitOfWorkSchemaView = class {
|
|
|
731
879
|
this.#operationIndices.push(operationIndex);
|
|
732
880
|
return this;
|
|
733
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);
|
|
900
|
+
return this;
|
|
901
|
+
}
|
|
734
902
|
findWithCursor(tableName, builderFn) {
|
|
735
903
|
const table = this.#schema.tables[tableName];
|
|
736
904
|
if (!table) throw new Error(`Table ${tableName} not found in schema`);
|
|
737
905
|
const builder = new FindBuilder(tableName, table);
|
|
738
906
|
builderFn(builder);
|
|
739
907
|
const { indexName, options, type } = builder.build();
|
|
740
|
-
const operationIndex = this.#
|
|
908
|
+
const operationIndex = this.#uow.addRetrievalOperation({
|
|
741
909
|
type,
|
|
742
910
|
schema: this.#schema,
|
|
743
911
|
namespace: this.#namespace,
|
|
@@ -767,7 +935,7 @@ var UnitOfWorkSchemaView = class {
|
|
|
767
935
|
[idColumn.ormName]: externalId
|
|
768
936
|
};
|
|
769
937
|
}
|
|
770
|
-
this.#
|
|
938
|
+
this.#uow.addMutationOperation({
|
|
771
939
|
type: "create",
|
|
772
940
|
schema: this.#schema,
|
|
773
941
|
namespace: this.#namespace,
|
|
@@ -781,7 +949,7 @@ var UnitOfWorkSchemaView = class {
|
|
|
781
949
|
const builder = new UpdateBuilder(tableName, id);
|
|
782
950
|
builderFn(builder);
|
|
783
951
|
const { id: opId, checkVersion, set } = builder.build();
|
|
784
|
-
this.#
|
|
952
|
+
this.#uow.addMutationOperation({
|
|
785
953
|
type: "update",
|
|
786
954
|
schema: this.#schema,
|
|
787
955
|
namespace: this.#namespace,
|
|
@@ -795,7 +963,7 @@ var UnitOfWorkSchemaView = class {
|
|
|
795
963
|
const builder = new DeleteBuilder(tableName, id);
|
|
796
964
|
builderFn?.(builder);
|
|
797
965
|
const { id: opId, checkVersion } = builder.build();
|
|
798
|
-
this.#
|
|
966
|
+
this.#uow.addMutationOperation({
|
|
799
967
|
type: "delete",
|
|
800
968
|
schema: this.#schema,
|
|
801
969
|
namespace: this.#namespace,
|
|
@@ -804,11 +972,33 @@ var UnitOfWorkSchemaView = class {
|
|
|
804
972
|
checkVersion
|
|
805
973
|
});
|
|
806
974
|
}
|
|
807
|
-
|
|
808
|
-
|
|
975
|
+
/**
|
|
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.
|
|
978
|
+
*
|
|
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
|
+
* ```
|
|
990
|
+
*/
|
|
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
|
+
});
|
|
809
999
|
}
|
|
810
1000
|
};
|
|
811
1001
|
|
|
812
1002
|
//#endregion
|
|
813
|
-
export { DeleteBuilder, FindBuilder, JoinFindBuilder,
|
|
1003
|
+
export { DeleteBuilder, FindBuilder, JoinFindBuilder, TypedUnitOfWork, UnitOfWork, UpdateBuilder, buildJoinIndexed, createUnitOfWork };
|
|
814
1004
|
//# sourceMappingURL=unit-of-work.js.map
|