@fragno-dev/db 0.2.1 → 0.3.0
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 +206 -140
- package/CHANGELOG.md +67 -0
- package/README.md +30 -9
- package/dist/adapters/adapters.d.ts +23 -21
- package/dist/adapters/adapters.d.ts.map +1 -1
- package/dist/adapters/adapters.js.map +1 -1
- package/dist/adapters/generic-sql/driver-config.d.ts +16 -1
- package/dist/adapters/generic-sql/driver-config.d.ts.map +1 -1
- package/dist/adapters/generic-sql/driver-config.js +23 -1
- package/dist/adapters/generic-sql/driver-config.js.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-adapter.d.ts +27 -9
- package/dist/adapters/generic-sql/generic-sql-adapter.d.ts.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-adapter.js +55 -16
- package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-uow-executor.js +129 -3
- package/dist/adapters/generic-sql/generic-sql-uow-executor.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/mysql.js +24 -5
- package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/postgres.js +6 -5
- package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/sqlite.js +21 -10
- package/dist/adapters/generic-sql/migration/dialect/sqlite.js.map +1 -1
- package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -1
- package/dist/adapters/generic-sql/migration/prepared-migrations.js +8 -8
- package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -1
- package/dist/adapters/generic-sql/migration/sql-generator.js +74 -51
- package/dist/adapters/generic-sql/migration/sql-generator.js.map +1 -1
- package/dist/adapters/generic-sql/query/create-sql-query-compiler.js +6 -5
- package/dist/adapters/generic-sql/query/create-sql-query-compiler.js.map +1 -1
- package/dist/adapters/generic-sql/query/cursor-utils.js +42 -4
- package/dist/adapters/generic-sql/query/cursor-utils.js.map +1 -1
- package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js +25 -17
- package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js.map +1 -1
- package/dist/adapters/generic-sql/query/select-builder.js +5 -3
- package/dist/adapters/generic-sql/query/select-builder.js.map +1 -1
- package/dist/adapters/generic-sql/query/sql-query-compiler.js +15 -12
- package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -1
- package/dist/adapters/generic-sql/query/where-builder.js +38 -28
- package/dist/adapters/generic-sql/query/where-builder.js.map +1 -1
- package/dist/adapters/generic-sql/sqlite-storage.d.ts +13 -0
- package/dist/adapters/generic-sql/sqlite-storage.d.ts.map +1 -0
- package/dist/adapters/generic-sql/sqlite-storage.js +15 -0
- package/dist/adapters/generic-sql/sqlite-storage.js.map +1 -0
- package/dist/adapters/generic-sql/uow-decoder.js +7 -3
- package/dist/adapters/generic-sql/uow-decoder.js.map +1 -1
- package/dist/adapters/generic-sql/uow-encoder.js +28 -8
- package/dist/adapters/generic-sql/uow-encoder.js.map +1 -1
- package/dist/adapters/in-memory/condition-evaluator.js +131 -0
- package/dist/adapters/in-memory/condition-evaluator.js.map +1 -0
- package/dist/adapters/in-memory/errors.d.ts +13 -0
- package/dist/adapters/in-memory/errors.d.ts.map +1 -0
- package/dist/adapters/in-memory/errors.js +23 -0
- package/dist/adapters/in-memory/errors.js.map +1 -0
- package/dist/adapters/in-memory/in-memory-adapter.d.ts +27 -0
- package/dist/adapters/in-memory/in-memory-adapter.d.ts.map +1 -0
- package/dist/adapters/in-memory/in-memory-adapter.js +176 -0
- package/dist/adapters/in-memory/in-memory-adapter.js.map +1 -0
- package/dist/adapters/in-memory/in-memory-uow.js +648 -0
- package/dist/adapters/in-memory/in-memory-uow.js.map +1 -0
- package/dist/adapters/in-memory/index.d.ts +4 -0
- package/dist/adapters/in-memory/index.js +4 -0
- package/dist/adapters/in-memory/options.d.ts +28 -0
- package/dist/adapters/in-memory/options.d.ts.map +1 -0
- package/dist/adapters/in-memory/options.js +61 -0
- package/dist/adapters/in-memory/options.js.map +1 -0
- package/dist/adapters/in-memory/reference-resolution.js +26 -0
- package/dist/adapters/in-memory/reference-resolution.js.map +1 -0
- package/dist/adapters/in-memory/sorted-array-index.js +129 -0
- package/dist/adapters/in-memory/sorted-array-index.js.map +1 -0
- package/dist/adapters/in-memory/store.js +71 -0
- package/dist/adapters/in-memory/store.js.map +1 -0
- package/dist/adapters/in-memory/value-comparison.js +28 -0
- package/dist/adapters/in-memory/value-comparison.js.map +1 -0
- package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -1
- package/dist/adapters/shared/uow-operation-compiler.js +11 -11
- package/dist/adapters/shared/uow-operation-compiler.js.map +1 -1
- package/dist/adapters/sql/index.d.ts +5 -0
- package/dist/adapters/sql/index.js +4 -0
- package/dist/db-fragment-definition-builder.d.ts +45 -96
- package/dist/db-fragment-definition-builder.d.ts.map +1 -1
- package/dist/db-fragment-definition-builder.js +121 -99
- package/dist/db-fragment-definition-builder.js.map +1 -1
- package/dist/dispatchers/cloudflare-do/index.d.ts +26 -0
- package/dist/dispatchers/cloudflare-do/index.d.ts.map +1 -0
- package/dist/dispatchers/cloudflare-do/index.js +63 -0
- package/dist/dispatchers/cloudflare-do/index.js.map +1 -0
- package/dist/dispatchers/node/index.d.ts +17 -0
- package/dist/dispatchers/node/index.d.ts.map +1 -0
- package/dist/dispatchers/node/index.js +59 -0
- package/dist/dispatchers/node/index.js.map +1 -0
- package/dist/fragments/internal-fragment.d.ts +172 -9
- package/dist/fragments/internal-fragment.d.ts.map +1 -1
- package/dist/fragments/internal-fragment.js +193 -74
- package/dist/fragments/internal-fragment.js.map +1 -1
- package/dist/fragments/internal-fragment.routes.js +29 -0
- package/dist/fragments/internal-fragment.routes.js.map +1 -0
- package/dist/fragments/internal-fragment.schema.d.ts +9 -0
- package/dist/fragments/internal-fragment.schema.d.ts.map +1 -0
- package/dist/fragments/internal-fragment.schema.js +22 -0
- package/dist/fragments/internal-fragment.schema.js.map +1 -0
- package/dist/hooks/durable-hooks-processor.d.ts +14 -0
- package/dist/hooks/durable-hooks-processor.d.ts.map +1 -0
- package/dist/hooks/durable-hooks-processor.js +32 -0
- package/dist/hooks/durable-hooks-processor.js.map +1 -0
- package/dist/hooks/hooks.d.ts +47 -4
- package/dist/hooks/hooks.d.ts.map +1 -1
- package/dist/hooks/hooks.js +106 -39
- package/dist/hooks/hooks.js.map +1 -1
- package/dist/migration-engine/auto-from-schema.js +14 -11
- package/dist/migration-engine/auto-from-schema.js.map +1 -1
- package/dist/migration-engine/generation-engine.d.ts +16 -10
- package/dist/migration-engine/generation-engine.d.ts.map +1 -1
- package/dist/migration-engine/generation-engine.js +72 -33
- package/dist/migration-engine/generation-engine.js.map +1 -1
- package/dist/migration-engine/shared.js.map +1 -1
- package/dist/mod.d.ts +17 -10
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +14 -8
- package/dist/mod.js.map +1 -1
- package/dist/naming/sql-naming.d.ts +19 -0
- package/dist/naming/sql-naming.d.ts.map +1 -0
- package/dist/naming/sql-naming.js +116 -0
- package/dist/naming/sql-naming.js.map +1 -0
- package/dist/node_modules/.pnpm/{rou3@0.7.10 → rou3@0.7.12}/node_modules/rou3/dist/index.js +8 -5
- package/dist/node_modules/.pnpm/rou3@0.7.12/node_modules/rou3/dist/index.js.map +1 -0
- package/dist/outbox/outbox-builder.js +156 -0
- package/dist/outbox/outbox-builder.js.map +1 -0
- package/dist/outbox/outbox.d.ts +52 -0
- package/dist/outbox/outbox.d.ts.map +1 -0
- package/dist/outbox/outbox.js +37 -0
- package/dist/outbox/outbox.js.map +1 -0
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js +3 -2
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +1 -1
- package/dist/packages/fragno/dist/api/fragment-instantiator.js +164 -20
- package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +1 -1
- package/dist/packages/fragno/dist/api/request-input-context.js +67 -0
- package/dist/packages/fragno/dist/api/request-input-context.js.map +1 -1
- package/dist/packages/fragno/dist/api/route.js +14 -1
- package/dist/packages/fragno/dist/api/route.js.map +1 -1
- package/dist/packages/fragno/dist/internal/trace-context.js +12 -0
- package/dist/packages/fragno/dist/internal/trace-context.js.map +1 -0
- package/dist/query/column-defaults.js +20 -4
- package/dist/query/column-defaults.js.map +1 -1
- package/dist/query/cursor.d.ts +3 -1
- package/dist/query/cursor.d.ts.map +1 -1
- package/dist/query/cursor.js +45 -14
- package/dist/query/cursor.js.map +1 -1
- package/dist/query/db-now.d.ts +8 -0
- package/dist/query/db-now.d.ts.map +1 -0
- package/dist/query/db-now.js +7 -0
- package/dist/query/db-now.js.map +1 -0
- package/dist/query/serialize/create-sql-serializer.js +3 -2
- package/dist/query/serialize/create-sql-serializer.js.map +1 -1
- package/dist/query/serialize/dialect/mysql-serializer.js +12 -6
- package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -1
- package/dist/query/serialize/dialect/postgres-serializer.js +25 -7
- package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -1
- package/dist/query/serialize/dialect/sqlite-serializer.js +55 -11
- package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -1
- package/dist/query/serialize/sql-serializer.js +2 -2
- package/dist/query/serialize/sql-serializer.js.map +1 -1
- package/dist/query/simple-query-interface.d.ts +6 -1
- package/dist/query/simple-query-interface.d.ts.map +1 -1
- package/dist/query/unit-of-work/execute-unit-of-work.d.ts +351 -100
- package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work/execute-unit-of-work.js +440 -267
- package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -1
- package/dist/query/unit-of-work/unit-of-work.d.ts +67 -22
- package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work/unit-of-work.js +110 -13
- package/dist/query/unit-of-work/unit-of-work.js.map +1 -1
- package/dist/query/value-decoding.js +8 -5
- package/dist/query/value-decoding.js.map +1 -1
- package/dist/query/value-encoding.js +29 -9
- package/dist/query/value-encoding.js.map +1 -1
- package/dist/schema/create.d.ts +40 -14
- package/dist/schema/create.d.ts.map +1 -1
- package/dist/schema/create.js +82 -42
- package/dist/schema/create.js.map +1 -1
- package/dist/schema/generate-id.d.ts +20 -0
- package/dist/schema/generate-id.d.ts.map +1 -0
- package/dist/schema/generate-id.js +28 -0
- package/dist/schema/generate-id.js.map +1 -0
- package/dist/schema/type-conversion/create-sql-type-mapper.js +3 -2
- package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -1
- package/dist/schema/type-conversion/dialect/sqlite.js +9 -0
- package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -1
- package/dist/schema/validator.d.ts +10 -0
- package/dist/schema/validator.d.ts.map +1 -0
- package/dist/schema/validator.js +123 -0
- package/dist/schema/validator.js.map +1 -0
- package/dist/schema-output/drizzle.d.ts +30 -0
- package/dist/schema-output/drizzle.d.ts.map +1 -0
- package/dist/{adapters/drizzle/generate.js → schema-output/drizzle.js} +82 -56
- package/dist/schema-output/drizzle.js.map +1 -0
- package/dist/schema-output/prisma.d.ts +17 -0
- package/dist/schema-output/prisma.d.ts.map +1 -0
- package/dist/schema-output/prisma.js +296 -0
- package/dist/schema-output/prisma.js.map +1 -0
- package/dist/util/default-database-adapter.js +61 -0
- package/dist/util/default-database-adapter.js.map +1 -0
- package/dist/with-database.d.ts +1 -1
- package/dist/with-database.d.ts.map +1 -1
- package/dist/with-database.js +12 -3
- package/dist/with-database.js.map +1 -1
- package/package.json +43 -28
- package/src/adapters/adapters.ts +30 -24
- package/src/adapters/drizzle/migrate-drizzle.test.ts +54 -33
- package/src/adapters/drizzle/migration-parity-drizzle-kit.test.ts +599 -0
- package/src/adapters/drizzle/test-utils.ts +12 -8
- package/src/adapters/generic-sql/driver-config.ts +38 -0
- package/src/adapters/generic-sql/generic-sql-adapter.test.ts +5 -5
- package/src/adapters/generic-sql/generic-sql-adapter.ts +110 -24
- package/src/adapters/generic-sql/generic-sql-uow-executor.test.ts +54 -0
- package/src/adapters/generic-sql/generic-sql-uow-executor.ts +231 -3
- package/src/adapters/generic-sql/migration/adapter-migration-parity.test.ts +118 -0
- package/src/adapters/generic-sql/migration/dialect/mysql.test.ts +26 -8
- package/src/adapters/generic-sql/migration/dialect/mysql.ts +46 -8
- package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +25 -7
- package/src/adapters/generic-sql/migration/dialect/postgres.ts +8 -4
- package/src/adapters/generic-sql/migration/dialect/sqlite.test.ts +47 -8
- package/src/adapters/generic-sql/migration/dialect/sqlite.ts +27 -12
- package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +128 -39
- package/src/adapters/generic-sql/migration/prepared-migrations.ts +15 -8
- package/src/adapters/generic-sql/migration/sql-generator.ts +142 -65
- package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +9 -6
- package/src/adapters/generic-sql/query/cursor-utils.test.ts +271 -0
- package/src/adapters/generic-sql/query/cursor-utils.ts +41 -6
- package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +27 -27
- package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +38 -24
- package/src/adapters/generic-sql/query/select-builder.test.ts +15 -11
- package/src/adapters/generic-sql/query/select-builder.ts +6 -2
- package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +52 -2
- package/src/adapters/generic-sql/query/sql-query-compiler.ts +50 -15
- package/src/adapters/generic-sql/query/where-builder.test.ts +91 -17
- package/src/adapters/generic-sql/query/where-builder.ts +90 -38
- package/src/adapters/{kysely/kysely-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-migrations.test.ts} +6 -6
- package/src/adapters/generic-sql/sql-adapter-pglite-pagination.test.ts +806 -0
- package/src/adapters/{drizzle/drizzle-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-queries.test.ts} +11 -11
- package/src/adapters/generic-sql/{test/generic-drizzle-adapter-sqlite3.test.ts → sql-adapter-sqlite3-driver.test.ts} +49 -35
- package/src/adapters/{drizzle/drizzle-adapter-sqlite3.test.ts → generic-sql/sql-adapter-sqlite3-uow.test.ts} +48 -32
- package/src/adapters/{kysely/kysely-adapter-sqlocal.test.ts → generic-sql/sql-adapter-sqlocal.test.ts} +6 -6
- package/src/adapters/generic-sql/sqlite-storage.ts +20 -0
- package/src/adapters/generic-sql/uow-decoder.test.ts +1 -1
- package/src/adapters/generic-sql/uow-decoder.ts +21 -3
- package/src/adapters/generic-sql/uow-encoder.test.ts +33 -2
- package/src/adapters/generic-sql/uow-encoder.ts +50 -11
- package/src/adapters/in-memory/condition-evaluator.test.ts +193 -0
- package/src/adapters/in-memory/condition-evaluator.ts +275 -0
- package/src/adapters/in-memory/errors.ts +20 -0
- package/src/adapters/in-memory/in-memory-adapter.ts +277 -0
- package/src/adapters/in-memory/in-memory-uow.mutations.test.ts +296 -0
- package/src/adapters/in-memory/in-memory-uow.retrieval.test.ts +100 -0
- package/src/adapters/in-memory/in-memory-uow.ts +1348 -0
- package/src/adapters/in-memory/index.ts +3 -0
- package/src/adapters/in-memory/options.test.ts +41 -0
- package/src/adapters/in-memory/options.ts +87 -0
- package/src/adapters/in-memory/reference-resolution.test.ts +50 -0
- package/src/adapters/in-memory/reference-resolution.ts +67 -0
- package/src/adapters/in-memory/sorted-array-index.test.ts +123 -0
- package/src/adapters/in-memory/sorted-array-index.ts +228 -0
- package/src/adapters/in-memory/store.test.ts +68 -0
- package/src/adapters/in-memory/store.ts +145 -0
- package/src/adapters/in-memory/value-comparison.ts +53 -0
- package/src/adapters/in-memory/value-normalization.test.ts +57 -0
- package/src/adapters/prisma/prisma-adapter-sqlite3.test.ts +1163 -0
- package/src/adapters/shared/from-unit-of-work-compiler.ts +3 -1
- package/src/adapters/shared/uow-operation-compiler.ts +26 -16
- package/src/adapters/sql/index.ts +12 -0
- package/src/db-fragment-definition-builder.test.ts +88 -54
- package/src/db-fragment-definition-builder.ts +201 -322
- package/src/db-fragment-instantiator.test.ts +169 -101
- package/src/db-fragment-integration.test.ts +301 -149
- package/src/dispatchers/cloudflare-do/index.test.ts +73 -0
- package/src/dispatchers/cloudflare-do/index.ts +104 -0
- package/src/dispatchers/node/index.test.ts +91 -0
- package/src/dispatchers/node/index.ts +87 -0
- package/src/fragments/internal-fragment.routes.ts +42 -0
- package/src/fragments/internal-fragment.schema.ts +51 -0
- package/src/fragments/internal-fragment.test.ts +730 -274
- package/src/fragments/internal-fragment.ts +447 -154
- package/src/hooks/durable-hooks-processor.test.ts +117 -0
- package/src/hooks/durable-hooks-processor.ts +67 -0
- package/src/hooks/hooks.test.ts +411 -259
- package/src/hooks/hooks.ts +265 -66
- package/src/migration-engine/auto-from-schema.test.ts +14 -14
- package/src/migration-engine/auto-from-schema.ts +5 -2
- package/src/migration-engine/create.test.ts +2 -2
- package/src/migration-engine/generation-engine.test.ts +229 -104
- package/src/migration-engine/generation-engine.ts +94 -64
- package/src/migration-engine/shared.ts +1 -0
- package/src/mod.ts +78 -30
- package/src/naming/sql-naming.ts +180 -0
- package/src/outbox/outbox-builder.ts +241 -0
- package/src/outbox/outbox.test.ts +253 -0
- package/src/outbox/outbox.ts +137 -0
- package/src/query/column-defaults.ts +41 -3
- package/src/query/condition-builder.test.ts +3 -3
- package/src/query/cursor.test.ts +116 -18
- package/src/query/cursor.ts +75 -26
- package/src/query/db-now.ts +6 -0
- package/src/query/query-type.test.ts +2 -2
- package/src/query/serialize/create-sql-serializer.ts +7 -2
- package/src/query/serialize/dialect/mysql-serializer.ts +12 -4
- package/src/query/serialize/dialect/postgres-serializer.ts +34 -4
- package/src/query/serialize/dialect/sqlite-serializer.test.ts +51 -1
- package/src/query/serialize/dialect/sqlite-serializer.ts +92 -9
- package/src/query/serialize/sql-serializer.ts +4 -4
- package/src/query/simple-query-interface.ts +5 -0
- package/src/query/unit-of-work/execute-unit-of-work.test.ts +1512 -1458
- package/src/query/unit-of-work/execute-unit-of-work.ts +1708 -596
- package/src/query/unit-of-work/tx-builder.test.ts +1041 -0
- package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +32 -32
- package/src/query/unit-of-work/unit-of-work-types.test.ts +1 -1
- package/src/query/unit-of-work/unit-of-work.test.ts +231 -36
- package/src/query/unit-of-work/unit-of-work.ts +229 -31
- package/src/query/value-decoding.test.ts +13 -2
- package/src/query/value-decoding.ts +17 -4
- package/src/query/value-encoding.test.ts +85 -2
- package/src/query/value-encoding.ts +56 -6
- package/src/schema/create.test.ts +129 -42
- package/src/schema/create.ts +187 -47
- package/src/schema/generate-id.test.ts +57 -0
- package/src/schema/generate-id.ts +38 -0
- package/src/schema/serialize.test.ts +14 -2
- package/src/schema/type-conversion/create-sql-type-mapper.ts +7 -2
- package/src/schema/type-conversion/dialect/sqlite.ts +18 -0
- package/src/schema/type-conversion/type-mapping.test.ts +25 -1
- package/src/schema/validator.test.ts +197 -0
- package/src/schema/validator.ts +231 -0
- package/src/{adapters/drizzle/generate.test.ts → schema-output/drizzle.test.ts} +179 -129
- package/src/{adapters/drizzle/generate.ts → schema-output/drizzle.ts} +143 -93
- package/src/schema-output/prisma.test.ts +536 -0
- package/src/schema-output/prisma.ts +573 -0
- package/src/util/default-database-adapter.ts +106 -0
- package/src/with-database.ts +22 -3
- package/tsdown.config.ts +6 -4
- package/dist/adapters/drizzle/drizzle-adapter.d.ts +0 -20
- package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +0 -1
- package/dist/adapters/drizzle/drizzle-adapter.js +0 -27
- package/dist/adapters/drizzle/drizzle-adapter.js.map +0 -1
- package/dist/adapters/drizzle/generate.d.ts +0 -30
- package/dist/adapters/drizzle/generate.d.ts.map +0 -1
- package/dist/adapters/drizzle/generate.js.map +0 -1
- package/dist/adapters/kysely/kysely-adapter.d.ts +0 -19
- package/dist/adapters/kysely/kysely-adapter.d.ts.map +0 -1
- package/dist/adapters/kysely/kysely-adapter.js +0 -17
- package/dist/adapters/kysely/kysely-adapter.js.map +0 -1
- package/dist/adapters/shared/table-name-mapper.d.ts +0 -12
- package/dist/adapters/shared/table-name-mapper.d.ts.map +0 -1
- package/dist/adapters/shared/table-name-mapper.js +0 -43
- package/dist/adapters/shared/table-name-mapper.js.map +0 -1
- package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js.map +0 -1
- package/dist/schema-generator/schema-generator.d.ts +0 -15
- package/dist/schema-generator/schema-generator.d.ts.map +0 -1
- package/src/adapters/drizzle/drizzle-adapter.ts +0 -39
- package/src/adapters/kysely/kysely-adapter.ts +0 -27
- package/src/adapters/shared/table-name-mapper.ts +0 -50
- package/src/schema-generator/schema-generator.ts +0 -12
- package/src/shared/config.ts +0 -10
- package/src/shared/connection-pool.ts +0 -24
- package/src/shared/prisma.ts +0 -45
|
@@ -2,188 +2,249 @@ import { ExponentialBackoffRetryPolicy, NoRetryPolicy } from "./retry-policy.js"
|
|
|
2
2
|
|
|
3
3
|
//#region src/query/unit-of-work/execute-unit-of-work.ts
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
* This error triggers automatic retry behavior in executeRestrictedUnitOfWork.
|
|
5
|
+
* Symbol to identify TxResult objects
|
|
7
6
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
const TX_RESULT_BRAND = Symbol("TxResult");
|
|
8
|
+
/**
|
|
9
|
+
* Create a TxResult for service context.
|
|
10
|
+
* Schedules retrieve operations on the baseUow and returns a TxResult with callbacks stored.
|
|
11
|
+
* @internal Used by ServiceTxBuilder.build()
|
|
12
|
+
*/
|
|
13
|
+
function createServiceTx(schema, callbacks, baseUow) {
|
|
14
|
+
const { promise: retrievePhase, resolve: resolveRetrievePhase, reject: rejectRetrievePhase } = Promise.withResolvers();
|
|
15
|
+
const restrictedUow = baseUow.restrict({ readyFor: "none" });
|
|
16
|
+
let serviceCalls;
|
|
17
|
+
try {
|
|
18
|
+
if (callbacks.serviceCalls) serviceCalls = callbacks.serviceCalls();
|
|
19
|
+
} catch (error) {
|
|
20
|
+
restrictedUow.signalReadyForRetrieval();
|
|
21
|
+
restrictedUow.signalReadyForMutation();
|
|
22
|
+
retrievePhase.catch(() => {});
|
|
23
|
+
rejectRetrievePhase(error);
|
|
24
|
+
throw error;
|
|
12
25
|
}
|
|
13
|
-
|
|
26
|
+
let typedUow;
|
|
27
|
+
try {
|
|
28
|
+
if (schema && callbacks.retrieve) {
|
|
29
|
+
const emptyUow = restrictedUow.forSchema(schema);
|
|
30
|
+
typedUow = callbacks.retrieve(emptyUow);
|
|
31
|
+
}
|
|
32
|
+
} catch (error) {
|
|
33
|
+
restrictedUow.signalReadyForRetrieval();
|
|
34
|
+
restrictedUow.signalReadyForMutation();
|
|
35
|
+
retrievePhase.catch(() => {});
|
|
36
|
+
rejectRetrievePhase(error);
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
restrictedUow.signalReadyForRetrieval();
|
|
40
|
+
if (typedUow) typedUow.retrievalPhase.then((results) => resolveRetrievePhase(results), (error) => rejectRetrievePhase(error));
|
|
41
|
+
else if (!callbacks.retrieve) resolveRetrievePhase([]);
|
|
42
|
+
const internal = {
|
|
43
|
+
schema,
|
|
44
|
+
callbacks,
|
|
45
|
+
typedUow,
|
|
46
|
+
restrictedUow,
|
|
47
|
+
retrievePhase,
|
|
48
|
+
resolveRetrievePhase,
|
|
49
|
+
rejectRetrievePhase,
|
|
50
|
+
retrieveSuccessResult: void 0,
|
|
51
|
+
mutateResult: void 0,
|
|
52
|
+
finalResult: void 0,
|
|
53
|
+
serviceCalls
|
|
54
|
+
};
|
|
55
|
+
return {
|
|
56
|
+
[TX_RESULT_BRAND]: true,
|
|
57
|
+
_internal: internal
|
|
58
|
+
};
|
|
59
|
+
}
|
|
14
60
|
/**
|
|
15
|
-
*
|
|
61
|
+
* Recursively collect all TxResults from a service call tree.
|
|
62
|
+
* Returns them in a flat array in dependency order (serviceCalls before their dependents).
|
|
63
|
+
* Skips undefined values (which can occur with optional service patterns like
|
|
64
|
+
* optionalService?.method()).
|
|
16
65
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
66
|
+
function collectAllTxResults(txResults) {
|
|
67
|
+
const collected = [];
|
|
68
|
+
const seen = /* @__PURE__ */ new Set();
|
|
69
|
+
function collect(txResult) {
|
|
70
|
+
if (txResult === void 0) return;
|
|
71
|
+
if (seen.has(txResult)) return;
|
|
72
|
+
seen.add(txResult);
|
|
73
|
+
const serviceCalls = txResult._internal.serviceCalls;
|
|
74
|
+
if (serviceCalls) for (const serviceCall of serviceCalls) collect(serviceCall);
|
|
75
|
+
collected.push(txResult);
|
|
76
|
+
}
|
|
77
|
+
for (const txResult of txResults) collect(txResult);
|
|
78
|
+
return collected;
|
|
29
79
|
}
|
|
30
80
|
/**
|
|
31
|
-
* Execute a
|
|
32
|
-
*
|
|
33
|
-
* This function orchestrates the two-phase execution (retrieval + mutation) with retry logic.
|
|
34
|
-
* It creates fresh UOW instances for each attempt.
|
|
35
|
-
*
|
|
36
|
-
* @param callbacks - Object containing retrieve, mutate, and onSuccess callbacks
|
|
37
|
-
* @param options - Configuration including UOW factory, retry policy, and abort signal
|
|
38
|
-
* @returns Promise resolving to the execution result
|
|
39
|
-
*
|
|
40
|
-
* @example
|
|
41
|
-
* ```ts
|
|
42
|
-
* const result = await executeUnitOfWork(
|
|
43
|
-
* {
|
|
44
|
-
* retrieve: (uow) => uow.find("users", (b) => b.whereIndex("primary")),
|
|
45
|
-
* mutate: (uow, [users]) => {
|
|
46
|
-
* const user = users[0];
|
|
47
|
-
* uow.update("users", user.id, (b) => b.set({ balance: newBalance }));
|
|
48
|
-
* },
|
|
49
|
-
* onSuccess: async ({ results, mutationResult }) => {
|
|
50
|
-
* console.log("Update successful!");
|
|
51
|
-
* }
|
|
52
|
-
* },
|
|
53
|
-
* {
|
|
54
|
-
* createUnitOfWork: () => queryEngine.createUnitOfWork(),
|
|
55
|
-
* retryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 3 })
|
|
56
|
-
* }
|
|
57
|
-
* );
|
|
58
|
-
* ```
|
|
81
|
+
* Execute a single TxResult's callbacks after retrieve phase completes.
|
|
82
|
+
* This processes retrieveSuccess, mutate, and success callbacks in order.
|
|
59
83
|
*/
|
|
60
|
-
async function
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (
|
|
67
|
-
|
|
68
|
-
|
|
84
|
+
async function processTxResultAfterRetrieve(txResult, baseUow) {
|
|
85
|
+
const internal = txResult._internal;
|
|
86
|
+
const callbacks = internal.callbacks;
|
|
87
|
+
const retrieveResults = await internal.retrievePhase;
|
|
88
|
+
const serviceResults = [];
|
|
89
|
+
if (internal.serviceCalls) for (const serviceCall of internal.serviceCalls) {
|
|
90
|
+
if (serviceCall === void 0) {
|
|
91
|
+
serviceResults.push(void 0);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const serviceCallInternal = serviceCall._internal;
|
|
95
|
+
if (serviceCallInternal.retrieveSuccessResult !== void 0 && !(Array.isArray(serviceCallInternal.retrieveSuccessResult) && serviceCallInternal.retrieveSuccessResult.length === 0 && serviceCallInternal.callbacks.mutate)) serviceResults.push(serviceCallInternal.retrieveSuccessResult);
|
|
96
|
+
else if (serviceCallInternal.mutateResult !== void 0) serviceResults.push(serviceCallInternal.mutateResult);
|
|
97
|
+
else serviceResults.push(serviceCallInternal.retrieveSuccessResult);
|
|
98
|
+
}
|
|
99
|
+
if (callbacks.retrieveSuccess) internal.retrieveSuccessResult = callbacks.retrieveSuccess(retrieveResults, serviceResults);
|
|
100
|
+
else internal.retrieveSuccessResult = retrieveResults;
|
|
101
|
+
if (callbacks.mutate) {
|
|
102
|
+
const mutateCtx = {
|
|
103
|
+
uow: internal.schema ? baseUow.forSchema(internal.schema) : void 0,
|
|
104
|
+
retrieveResult: internal.retrieveSuccessResult,
|
|
105
|
+
serviceIntermediateResult: serviceResults
|
|
69
106
|
};
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
nonce
|
|
89
|
-
});
|
|
90
|
-
return {
|
|
91
|
-
success: true,
|
|
92
|
-
results,
|
|
93
|
-
mutationResult: awaitedMutationResult,
|
|
94
|
-
createdIds,
|
|
95
|
-
nonce
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
if (!retryPolicy.shouldRetry(attempt, void 0, signal)) return {
|
|
99
|
-
success: false,
|
|
100
|
-
reason: "conflict"
|
|
101
|
-
};
|
|
102
|
-
const delayMs = retryPolicy.getDelayMs(attempt);
|
|
103
|
-
if (delayMs > 0) await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
104
|
-
attempt++;
|
|
105
|
-
} catch (error) {
|
|
106
|
-
return {
|
|
107
|
-
success: false,
|
|
108
|
-
reason: "error",
|
|
109
|
-
error
|
|
110
|
-
};
|
|
107
|
+
internal.mutateResult = callbacks.mutate(mutateCtx);
|
|
108
|
+
}
|
|
109
|
+
if (internal.typedUow) internal.typedUow.signalReadyForMutation();
|
|
110
|
+
else internal.restrictedUow.signalReadyForMutation();
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Execute a single TxResult's success callback after mutations complete.
|
|
114
|
+
*/
|
|
115
|
+
async function processTxResultAfterMutate(txResult) {
|
|
116
|
+
const internal = txResult._internal;
|
|
117
|
+
const callbacks = internal.callbacks;
|
|
118
|
+
const serviceIntermediateResults = [];
|
|
119
|
+
const serviceFinalResults = [];
|
|
120
|
+
if (internal.serviceCalls) for (const serviceCall of internal.serviceCalls) {
|
|
121
|
+
if (serviceCall === void 0) {
|
|
122
|
+
serviceIntermediateResults.push(void 0);
|
|
123
|
+
serviceFinalResults.push(void 0);
|
|
124
|
+
continue;
|
|
111
125
|
}
|
|
126
|
+
const serviceCallInternal = serviceCall._internal;
|
|
127
|
+
if (serviceCallInternal.retrieveSuccessResult !== void 0 && !(Array.isArray(serviceCallInternal.retrieveSuccessResult) && serviceCallInternal.retrieveSuccessResult.length === 0 && serviceCallInternal.callbacks.mutate)) serviceIntermediateResults.push(serviceCallInternal.retrieveSuccessResult);
|
|
128
|
+
else if (serviceCallInternal.mutateResult !== void 0) serviceIntermediateResults.push(serviceCallInternal.mutateResult);
|
|
129
|
+
else serviceIntermediateResults.push(serviceCallInternal.retrieveSuccessResult);
|
|
130
|
+
serviceFinalResults.push(serviceCallInternal.finalResult);
|
|
112
131
|
}
|
|
132
|
+
if (callbacks.success) {
|
|
133
|
+
const successCtx = {
|
|
134
|
+
retrieveResult: internal.retrieveSuccessResult,
|
|
135
|
+
mutateResult: internal.mutateResult,
|
|
136
|
+
serviceResult: serviceFinalResults,
|
|
137
|
+
serviceIntermediateResult: serviceIntermediateResults
|
|
138
|
+
};
|
|
139
|
+
internal.finalResult = callbacks.success(successCtx);
|
|
140
|
+
} else if (callbacks.mutate) internal.finalResult = await awaitPromisesInObject(internal.mutateResult);
|
|
141
|
+
else if (callbacks.retrieveSuccess || callbacks.retrieve) internal.finalResult = internal.retrieveSuccessResult;
|
|
142
|
+
else internal.finalResult = serviceFinalResults;
|
|
143
|
+
return internal.finalResult;
|
|
113
144
|
}
|
|
114
145
|
/**
|
|
115
|
-
* Execute a
|
|
146
|
+
* Execute a transaction with the unified TxResult pattern.
|
|
116
147
|
*
|
|
117
|
-
* This
|
|
118
|
-
* a context object with forSchema, executeRetrieve, and executeMutate methods. The user can
|
|
119
|
-
* create schema-specific UOWs via forSchema, then call executeRetrieve() and executeMutate()
|
|
120
|
-
* to execute the retrieval and mutation phases. The entire callback is re-executed on optimistic
|
|
121
|
-
* concurrency conflicts, ensuring retries work properly.
|
|
148
|
+
* This is the handler-level function that actually executes TxResults with retry support.
|
|
122
149
|
*
|
|
123
|
-
* @param
|
|
150
|
+
* @param callbacks - Transaction callbacks (serviceCalls, retrieve, retrieveSuccess, mutate, success)
|
|
124
151
|
* @param options - Configuration including UOW factory, retry policy, and abort signal
|
|
125
|
-
* @returns Promise resolving to the
|
|
126
|
-
* @throws Error if retries are exhausted or callback throws an error
|
|
152
|
+
* @returns Promise resolving to the result determined by return type priority
|
|
127
153
|
*
|
|
128
154
|
* @example
|
|
129
155
|
* ```ts
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* await executeRetrieve();
|
|
137
|
-
*
|
|
138
|
-
* const profileId = uow.create("profiles", { userId });
|
|
139
|
-
*
|
|
140
|
-
* // Execute mutation phase
|
|
141
|
-
* await executeMutate();
|
|
142
|
-
*
|
|
143
|
-
* return { userId, profileId };
|
|
144
|
-
* },
|
|
145
|
-
* {
|
|
146
|
-
* createUnitOfWork: () => db.createUnitOfWork(),
|
|
147
|
-
* retryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 5 })
|
|
148
|
-
* }
|
|
149
|
-
* );
|
|
150
|
-
* ```
|
|
156
|
+
* // Simple retrieve + transform
|
|
157
|
+
* const user = await executeTx({
|
|
158
|
+
* retrieve: (ctx) => ctx.forSchema(usersSchema).find("users", ...),
|
|
159
|
+
* retrieveSuccess: ([users]) => users[0] ?? null,
|
|
160
|
+
* }, { createUnitOfWork });
|
|
161
|
+
* @internal Used by HandlerTxBuilder.execute()
|
|
151
162
|
*/
|
|
152
|
-
async function
|
|
153
|
-
const retryPolicy = options.retryPolicy ?? new ExponentialBackoffRetryPolicy({
|
|
154
|
-
maxRetries: 5,
|
|
155
|
-
initialDelayMs: 10,
|
|
156
|
-
maxDelayMs: 100
|
|
157
|
-
});
|
|
163
|
+
async function executeTx(callbacks, options) {
|
|
158
164
|
const signal = options.signal;
|
|
159
165
|
let attempt = 0;
|
|
160
166
|
while (true) {
|
|
161
|
-
if (signal?.aborted) throw new Error("
|
|
167
|
+
if (signal?.aborted) throw new Error("Transaction execution aborted");
|
|
168
|
+
let retryPolicy;
|
|
162
169
|
try {
|
|
163
170
|
const baseUow = options.createUnitOfWork();
|
|
164
|
-
|
|
171
|
+
const context = {
|
|
165
172
|
forSchema: (schema, hooks) => {
|
|
166
173
|
return baseUow.forSchema(schema, hooks);
|
|
167
174
|
},
|
|
168
|
-
|
|
169
|
-
await baseUow.executeRetrieve();
|
|
170
|
-
},
|
|
171
|
-
executeMutate: async () => {
|
|
172
|
-
if (baseUow.state === "executed") return;
|
|
173
|
-
if (baseUow.state === "building-retrieval") await baseUow.executeRetrieve();
|
|
174
|
-
if (options.onBeforeMutate) options.onBeforeMutate(baseUow);
|
|
175
|
-
if (!(await baseUow.executeMutations()).success) throw new ConcurrencyConflictError();
|
|
176
|
-
if (options.onSuccess) await options.onSuccess(baseUow);
|
|
177
|
-
},
|
|
178
|
-
nonce: baseUow.nonce,
|
|
175
|
+
idempotencyKey: baseUow.idempotencyKey,
|
|
179
176
|
currentAttempt: attempt
|
|
180
|
-
}
|
|
177
|
+
};
|
|
178
|
+
let serviceCalls;
|
|
179
|
+
if (callbacks.serviceCalls) serviceCalls = callbacks.serviceCalls();
|
|
180
|
+
const typedUowFromRetrieve = callbacks.retrieve?.(context);
|
|
181
|
+
const allServiceCallTxResults = serviceCalls ? collectAllTxResults([...serviceCalls]) : [];
|
|
182
|
+
if (!(baseUow.getRetrievalOperations().length > 0)) {
|
|
183
|
+
if (options.retryPolicy) throw new Error("Retry policy is only supported when the transaction includes retrieve operations.");
|
|
184
|
+
retryPolicy = new NoRetryPolicy();
|
|
185
|
+
} else retryPolicy = options.retryPolicy ?? new ExponentialBackoffRetryPolicy({
|
|
186
|
+
maxRetries: 5,
|
|
187
|
+
initialDelayMs: 10,
|
|
188
|
+
maxDelayMs: 100
|
|
189
|
+
});
|
|
190
|
+
await baseUow.executeRetrieve();
|
|
191
|
+
const retrieveResult = typedUowFromRetrieve ? await typedUowFromRetrieve.retrievalPhase : [];
|
|
192
|
+
for (const txResult of allServiceCallTxResults) await processTxResultAfterRetrieve(txResult, baseUow);
|
|
193
|
+
const serviceResults = [];
|
|
194
|
+
if (serviceCalls) for (const serviceCall of serviceCalls) {
|
|
195
|
+
if (serviceCall === void 0) {
|
|
196
|
+
serviceResults.push(void 0);
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
const serviceCallInternal = serviceCall._internal;
|
|
200
|
+
if (serviceCallInternal.retrieveSuccessResult !== void 0 && !(Array.isArray(serviceCallInternal.retrieveSuccessResult) && serviceCallInternal.retrieveSuccessResult.length === 0 && serviceCallInternal.callbacks.mutate)) serviceResults.push(serviceCallInternal.retrieveSuccessResult);
|
|
201
|
+
else if (serviceCallInternal.mutateResult !== void 0) serviceResults.push(serviceCallInternal.mutateResult);
|
|
202
|
+
else serviceResults.push(serviceCallInternal.retrieveSuccessResult);
|
|
203
|
+
}
|
|
204
|
+
let retrieveSuccessResult;
|
|
205
|
+
if (callbacks.retrieveSuccess) retrieveSuccessResult = callbacks.retrieveSuccess(retrieveResult, serviceResults);
|
|
206
|
+
else retrieveSuccessResult = retrieveResult;
|
|
207
|
+
let mutateResult;
|
|
208
|
+
if (callbacks.mutate) {
|
|
209
|
+
const mutateCtx = {
|
|
210
|
+
...context,
|
|
211
|
+
retrieveResult: retrieveSuccessResult,
|
|
212
|
+
serviceIntermediateResult: serviceResults
|
|
213
|
+
};
|
|
214
|
+
mutateResult = callbacks.mutate(mutateCtx);
|
|
215
|
+
}
|
|
216
|
+
if (options.onBeforeMutate) options.onBeforeMutate(baseUow);
|
|
217
|
+
if (!(await baseUow.executeMutations()).success) throw new ConcurrencyConflictError();
|
|
218
|
+
for (const txResult of allServiceCallTxResults) await processTxResultAfterMutate(txResult);
|
|
219
|
+
const serviceFinalResults = [];
|
|
220
|
+
if (serviceCalls) for (const serviceCall of serviceCalls) {
|
|
221
|
+
if (serviceCall === void 0) {
|
|
222
|
+
serviceFinalResults.push(void 0);
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
serviceFinalResults.push(serviceCall._internal.finalResult);
|
|
226
|
+
}
|
|
227
|
+
let finalResult;
|
|
228
|
+
if (callbacks.success) {
|
|
229
|
+
const successCtx = {
|
|
230
|
+
retrieveResult: retrieveSuccessResult,
|
|
231
|
+
mutateResult,
|
|
232
|
+
serviceResult: serviceFinalResults,
|
|
233
|
+
serviceIntermediateResult: serviceResults
|
|
234
|
+
};
|
|
235
|
+
finalResult = callbacks.success(successCtx);
|
|
236
|
+
} else if (callbacks.mutate) finalResult = await awaitPromisesInObject(mutateResult);
|
|
237
|
+
else if (callbacks.retrieveSuccess || callbacks.retrieve) finalResult = retrieveSuccessResult;
|
|
238
|
+
else finalResult = serviceFinalResults;
|
|
239
|
+
if (options.onAfterMutate) await options.onAfterMutate(baseUow);
|
|
240
|
+
return await awaitPromisesInObject(finalResult);
|
|
181
241
|
} catch (error) {
|
|
182
|
-
if (signal?.aborted) throw new Error("
|
|
242
|
+
if (signal?.aborted) throw new Error("Transaction execution aborted");
|
|
183
243
|
if (!(error instanceof ConcurrencyConflictError)) throw error;
|
|
244
|
+
if (!retryPolicy) throw error;
|
|
184
245
|
if (!retryPolicy.shouldRetry(attempt, error, signal)) {
|
|
185
|
-
if (signal?.aborted) throw new Error("
|
|
186
|
-
throw new
|
|
246
|
+
if (signal?.aborted) throw new Error("Transaction execution aborted");
|
|
247
|
+
throw new ConcurrencyConflictError();
|
|
187
248
|
}
|
|
188
249
|
const delayMs = retryPolicy.getDelayMs(attempt);
|
|
189
250
|
if (delayMs > 0) await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
@@ -192,138 +253,250 @@ async function executeRestrictedUnitOfWork(callback, options) {
|
|
|
192
253
|
}
|
|
193
254
|
}
|
|
194
255
|
/**
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
256
|
+
* Error thrown when a Unit of Work execution fails due to optimistic concurrency conflict.
|
|
257
|
+
* This error triggers automatic retry behavior in executeTx.
|
|
258
|
+
*/
|
|
259
|
+
var ConcurrencyConflictError = class extends Error {
|
|
260
|
+
constructor(message = "Optimistic concurrency conflict detected") {
|
|
261
|
+
super(message);
|
|
262
|
+
this.name = "ConcurrencyConflictError";
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
/**
|
|
266
|
+
* Await promises in an object 1 level deep
|
|
267
|
+
*/
|
|
268
|
+
async function awaitPromisesInObject(obj) {
|
|
269
|
+
if (obj === null || obj === void 0) return obj;
|
|
270
|
+
if (typeof obj !== "object") return obj;
|
|
271
|
+
if (obj instanceof Promise) return await obj;
|
|
272
|
+
if (Array.isArray(obj)) return await Promise.all(obj.map((item) => item instanceof Promise ? item : Promise.resolve(item)));
|
|
273
|
+
if (obj.constructor !== Object) return obj;
|
|
274
|
+
const result = {};
|
|
275
|
+
const entries = Object.entries(obj);
|
|
276
|
+
const awaitedEntries = await Promise.all(entries.map(async ([key, value]) => {
|
|
277
|
+
return [key, value instanceof Promise ? await value : value];
|
|
278
|
+
}));
|
|
279
|
+
for (const [key, value] of awaitedEntries) result[key] = value;
|
|
280
|
+
return result;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Builder for service-level transactions.
|
|
284
|
+
* Uses a fluent API to build up transaction callbacks with proper type inference.
|
|
201
285
|
*
|
|
202
286
|
* @example
|
|
203
287
|
* ```ts
|
|
204
|
-
*
|
|
205
|
-
* () => [
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
288
|
+
* return serviceTx(schema)
|
|
289
|
+
* .withServiceCalls(() => [otherService.getData()])
|
|
290
|
+
* .retrieve((uow) => uow.find("users", ...))
|
|
291
|
+
* .transformRetrieve(([users], serviceResult) => users[0])
|
|
292
|
+
* .mutate(({ uow, retrieveResult, serviceIntermediateResult }) =>
|
|
293
|
+
* uow.create("records", { ... })
|
|
294
|
+
* )
|
|
295
|
+
* .transform(({ mutateResult, serviceResult, serviceIntermediateResult }) => ({ id: mutateResult }))
|
|
296
|
+
* .build();
|
|
211
297
|
* ```
|
|
212
298
|
*/
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
maxDelayMs: 100
|
|
218
|
-
});
|
|
219
|
-
const signal = options.signal;
|
|
220
|
-
let attempt = 0;
|
|
221
|
-
while (true) {
|
|
222
|
-
if (signal?.aborted) throw new Error("Unit of Work execution aborted");
|
|
223
|
-
try {
|
|
224
|
-
const baseUow = options.createUnitOfWork();
|
|
225
|
-
const services = servicesFactory();
|
|
226
|
-
await baseUow.executeRetrieve();
|
|
227
|
-
if (options.onBeforeMutate) options.onBeforeMutate(baseUow);
|
|
228
|
-
if (!(await baseUow.executeMutations()).success) throw new ConcurrencyConflictError();
|
|
229
|
-
if (options.onSuccess) await options.onSuccess(baseUow);
|
|
230
|
-
return await Promise.all(services);
|
|
231
|
-
} catch (error) {
|
|
232
|
-
if (signal?.aborted) throw new Error("Unit of Work execution aborted");
|
|
233
|
-
if (!(error instanceof ConcurrencyConflictError)) throw error;
|
|
234
|
-
if (!retryPolicy.shouldRetry(attempt, error, signal)) {
|
|
235
|
-
if (signal?.aborted) throw new Error("Unit of Work execution aborted");
|
|
236
|
-
throw new Error("Unit of Work execution failed: optimistic concurrency conflict", { cause: error });
|
|
237
|
-
}
|
|
238
|
-
const delayMs = retryPolicy.getDelayMs(attempt);
|
|
239
|
-
if (delayMs > 0) await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
240
|
-
attempt++;
|
|
241
|
-
}
|
|
299
|
+
var ServiceTxBuilder = class ServiceTxBuilder {
|
|
300
|
+
#state;
|
|
301
|
+
constructor(state) {
|
|
302
|
+
this.#state = state;
|
|
242
303
|
}
|
|
243
|
-
|
|
304
|
+
/**
|
|
305
|
+
* Add dependencies to execute before this transaction.
|
|
306
|
+
*/
|
|
307
|
+
withServiceCalls(fn) {
|
|
308
|
+
return new ServiceTxBuilder({
|
|
309
|
+
...this.#state,
|
|
310
|
+
withServiceCallsFn: fn
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Add retrieval operations to the transaction.
|
|
315
|
+
*/
|
|
316
|
+
retrieve(fn) {
|
|
317
|
+
return new ServiceTxBuilder({
|
|
318
|
+
...this.#state,
|
|
319
|
+
retrieveFn: fn,
|
|
320
|
+
transformRetrieveFn: void 0
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Transform retrieve results before passing to mutate.
|
|
325
|
+
*/
|
|
326
|
+
transformRetrieve(fn) {
|
|
327
|
+
return new ServiceTxBuilder({
|
|
328
|
+
...this.#state,
|
|
329
|
+
transformRetrieveFn: fn
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Add mutation operations based on retrieve results.
|
|
334
|
+
*/
|
|
335
|
+
mutate(fn) {
|
|
336
|
+
return new ServiceTxBuilder({
|
|
337
|
+
...this.#state,
|
|
338
|
+
mutateFn: fn
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Add final transformation after mutations complete.
|
|
343
|
+
*/
|
|
344
|
+
transform(fn) {
|
|
345
|
+
return new ServiceTxBuilder({
|
|
346
|
+
...this.#state,
|
|
347
|
+
transformFn: fn
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Build and return the TxResult.
|
|
352
|
+
*/
|
|
353
|
+
build() {
|
|
354
|
+
const state = this.#state;
|
|
355
|
+
const callbacks = {
|
|
356
|
+
serviceCalls: state.withServiceCallsFn,
|
|
357
|
+
retrieve: state.retrieveFn,
|
|
358
|
+
retrieveSuccess: state.transformRetrieveFn,
|
|
359
|
+
mutate: state.mutateFn ? (ctx) => {
|
|
360
|
+
return state.mutateFn({
|
|
361
|
+
uow: ctx.uow,
|
|
362
|
+
retrieveResult: ctx.retrieveResult,
|
|
363
|
+
serviceIntermediateResult: ctx.serviceIntermediateResult
|
|
364
|
+
});
|
|
365
|
+
} : void 0,
|
|
366
|
+
success: state.transformFn ? (ctx) => {
|
|
367
|
+
return state.transformFn({
|
|
368
|
+
retrieveResult: ctx.retrieveResult,
|
|
369
|
+
mutateResult: ctx.mutateResult,
|
|
370
|
+
serviceResult: ctx.serviceResult,
|
|
371
|
+
serviceIntermediateResult: ctx.serviceIntermediateResult
|
|
372
|
+
});
|
|
373
|
+
} : void 0
|
|
374
|
+
};
|
|
375
|
+
return createServiceTx(state.schema, callbacks, state.baseUow);
|
|
376
|
+
}
|
|
377
|
+
};
|
|
244
378
|
/**
|
|
245
|
-
*
|
|
246
|
-
* Callbacks are synchronous only to prevent accidentally awaiting services in wrong place.
|
|
247
|
-
*
|
|
248
|
-
* @param callbacks - Object containing retrieve and mutate callbacks
|
|
249
|
-
* @param options - Configuration including UOW factory, retry policy, and abort signal
|
|
250
|
-
* @returns Promise resolving to the mutation result with promises awaited 1 level deep
|
|
379
|
+
* Create a new ServiceTxBuilder for the given schema.
|
|
251
380
|
*/
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
381
|
+
function createServiceTxBuilder(schema, baseUow, hooks) {
|
|
382
|
+
return new ServiceTxBuilder({
|
|
383
|
+
schema,
|
|
384
|
+
baseUow,
|
|
385
|
+
hooks
|
|
257
386
|
});
|
|
258
|
-
const signal = options.signal;
|
|
259
|
-
let attempt = 0;
|
|
260
|
-
while (true) {
|
|
261
|
-
if (signal?.aborted) throw new Error("Unit of Work execution aborted");
|
|
262
|
-
try {
|
|
263
|
-
const baseUow = options.createUnitOfWork();
|
|
264
|
-
const context = { forSchema: (schema, hooks) => {
|
|
265
|
-
return baseUow.forSchema(schema, hooks);
|
|
266
|
-
} };
|
|
267
|
-
let retrieveResult;
|
|
268
|
-
if (callbacks.retrieve) retrieveResult = callbacks.retrieve(context);
|
|
269
|
-
else retrieveResult = void 0;
|
|
270
|
-
await baseUow.executeRetrieve();
|
|
271
|
-
let mutationResult;
|
|
272
|
-
if (callbacks.mutate) mutationResult = callbacks.mutate(context, retrieveResult);
|
|
273
|
-
else mutationResult = retrieveResult;
|
|
274
|
-
const awaitedMutationResult = await awaitPromisesInObject(mutationResult);
|
|
275
|
-
if (options.onBeforeMutate) options.onBeforeMutate(baseUow);
|
|
276
|
-
if (!(await baseUow.executeMutations()).success) throw new ConcurrencyConflictError();
|
|
277
|
-
if (options.onSuccess) await options.onSuccess(baseUow);
|
|
278
|
-
return awaitedMutationResult;
|
|
279
|
-
} catch (error) {
|
|
280
|
-
if (signal?.aborted) throw new Error("Unit of Work execution aborted");
|
|
281
|
-
if (!(error instanceof ConcurrencyConflictError)) throw error;
|
|
282
|
-
if (!retryPolicy.shouldRetry(attempt, error, signal)) {
|
|
283
|
-
if (signal?.aborted) throw new Error("Unit of Work execution aborted");
|
|
284
|
-
throw new Error("Unit of Work execution failed: optimistic concurrency conflict", { cause: error });
|
|
285
|
-
}
|
|
286
|
-
const delayMs = retryPolicy.getDelayMs(attempt);
|
|
287
|
-
if (delayMs > 0) await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
288
|
-
attempt++;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
387
|
}
|
|
292
388
|
/**
|
|
293
|
-
*
|
|
294
|
-
*
|
|
389
|
+
* Builder for handler-level transactions.
|
|
390
|
+
* Uses a fluent API to build up transaction callbacks with proper type inference.
|
|
295
391
|
*
|
|
296
|
-
* @
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
*
|
|
392
|
+
* @example
|
|
393
|
+
* ```ts
|
|
394
|
+
* const result = await handlerTx()
|
|
395
|
+
* .withServiceCalls(() => [userService.getUser(id)])
|
|
396
|
+
* .mutate(({ forSchema, idempotencyKey, currentAttempt, serviceIntermediateResult }) => {
|
|
397
|
+
* return forSchema(ordersSchema).create("orders", { ... });
|
|
398
|
+
* })
|
|
399
|
+
* .transform(({ mutateResult, serviceResult }) => ({ ... }))
|
|
400
|
+
* .execute();
|
|
401
|
+
* ```
|
|
300
402
|
*/
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
if (callbacks.retrieve) retrievalUow = callbacks.retrieve(typedUow);
|
|
306
|
-
else retrievalUow = typedUow;
|
|
307
|
-
} catch (error) {
|
|
308
|
-
typedUow.signalReadyForRetrieval();
|
|
309
|
-
typedUow.signalReadyForMutation();
|
|
310
|
-
throw error;
|
|
403
|
+
var HandlerTxBuilder = class HandlerTxBuilder {
|
|
404
|
+
#state;
|
|
405
|
+
constructor(state) {
|
|
406
|
+
this.#state = state;
|
|
311
407
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
408
|
+
/**
|
|
409
|
+
* Add dependencies to execute before this transaction.
|
|
410
|
+
*/
|
|
411
|
+
withServiceCalls(fn) {
|
|
412
|
+
return new HandlerTxBuilder({
|
|
413
|
+
...this.#state,
|
|
414
|
+
withServiceCallsFn: fn
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Add retrieval operations to the transaction.
|
|
419
|
+
* Return a TypedUnitOfWork from forSchema().find() to get typed results.
|
|
420
|
+
*/
|
|
421
|
+
retrieve(fn) {
|
|
422
|
+
return new HandlerTxBuilder({
|
|
423
|
+
...this.#state,
|
|
424
|
+
retrieveFn: fn,
|
|
425
|
+
transformRetrieveFn: void 0
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Transform retrieve results before passing to mutate.
|
|
430
|
+
*/
|
|
431
|
+
transformRetrieve(fn) {
|
|
432
|
+
return new HandlerTxBuilder({
|
|
433
|
+
...this.#state,
|
|
434
|
+
transformRetrieveFn: fn
|
|
435
|
+
});
|
|
321
436
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
437
|
+
/**
|
|
438
|
+
* Add mutation operations based on retrieve results.
|
|
439
|
+
*/
|
|
440
|
+
mutate(fn) {
|
|
441
|
+
return new HandlerTxBuilder({
|
|
442
|
+
...this.#state,
|
|
443
|
+
mutateFn: fn
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Add final transformation after mutations complete.
|
|
448
|
+
*/
|
|
449
|
+
transform(fn) {
|
|
450
|
+
return new HandlerTxBuilder({
|
|
451
|
+
...this.#state,
|
|
452
|
+
transformFn: fn
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Execute the transaction and return the result.
|
|
457
|
+
*/
|
|
458
|
+
execute() {
|
|
459
|
+
const state = this.#state;
|
|
460
|
+
return executeTx({
|
|
461
|
+
serviceCalls: state.withServiceCallsFn,
|
|
462
|
+
retrieve: state.retrieveFn ? (context) => {
|
|
463
|
+
return state.retrieveFn({
|
|
464
|
+
forSchema: context.forSchema,
|
|
465
|
+
idempotencyKey: context.idempotencyKey,
|
|
466
|
+
currentAttempt: context.currentAttempt
|
|
467
|
+
});
|
|
468
|
+
} : void 0,
|
|
469
|
+
retrieveSuccess: state.transformRetrieveFn,
|
|
470
|
+
mutate: state.mutateFn ? (ctx) => {
|
|
471
|
+
return state.mutateFn({
|
|
472
|
+
forSchema: ctx.forSchema,
|
|
473
|
+
idempotencyKey: ctx.idempotencyKey,
|
|
474
|
+
currentAttempt: ctx.currentAttempt,
|
|
475
|
+
retrieveResult: ctx.retrieveResult,
|
|
476
|
+
serviceIntermediateResult: ctx.serviceIntermediateResult
|
|
477
|
+
});
|
|
478
|
+
} : void 0,
|
|
479
|
+
success: state.transformFn ? (ctx) => {
|
|
480
|
+
return state.transformFn({
|
|
481
|
+
retrieveResult: ctx.retrieveResult,
|
|
482
|
+
mutateResult: ctx.mutateResult,
|
|
483
|
+
serviceResult: ctx.serviceResult,
|
|
484
|
+
serviceIntermediateResult: ctx.serviceIntermediateResult
|
|
485
|
+
});
|
|
486
|
+
} : void 0
|
|
487
|
+
}, state.options);
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
/**
|
|
491
|
+
* Create a new HandlerTxBuilder with the given options.
|
|
492
|
+
*/
|
|
493
|
+
function createHandlerTxBuilder(options, hooks) {
|
|
494
|
+
return new HandlerTxBuilder({
|
|
495
|
+
options,
|
|
496
|
+
hooks
|
|
497
|
+
});
|
|
325
498
|
}
|
|
326
499
|
|
|
327
500
|
//#endregion
|
|
328
|
-
export {
|
|
501
|
+
export { ConcurrencyConflictError, HandlerTxBuilder, ServiceTxBuilder, createHandlerTxBuilder, createServiceTxBuilder };
|
|
329
502
|
//# sourceMappingURL=execute-unit-of-work.js.map
|