@fragno-dev/db 0.1.14 → 0.2.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 +242 -139
- package/CHANGELOG.md +47 -0
- package/README.md +123 -8
- package/dist/adapters/adapters.d.ts +19 -5
- 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 +6 -19
- package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-adapter.js +7 -47
- package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -1
- package/dist/adapters/drizzle/generate.d.ts +7 -1
- package/dist/adapters/drizzle/generate.d.ts.map +1 -1
- package/dist/adapters/drizzle/generate.js +46 -45
- package/dist/adapters/drizzle/generate.js.map +1 -1
- package/dist/adapters/generic-sql/driver-config.d.ts +74 -0
- package/dist/adapters/generic-sql/driver-config.d.ts.map +1 -0
- package/dist/adapters/generic-sql/driver-config.js +94 -0
- package/dist/adapters/generic-sql/driver-config.js.map +1 -0
- package/dist/adapters/generic-sql/generic-sql-adapter.d.ts +43 -0
- package/dist/adapters/generic-sql/generic-sql-adapter.d.ts.map +1 -0
- package/dist/adapters/generic-sql/generic-sql-adapter.js +87 -0
- package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -0
- package/dist/adapters/generic-sql/generic-sql-uow-executor.js +67 -0
- package/dist/adapters/generic-sql/generic-sql-uow-executor.js.map +1 -0
- package/dist/adapters/generic-sql/migration/cold-kysely.js +33 -0
- package/dist/adapters/generic-sql/migration/cold-kysely.js.map +1 -0
- package/dist/adapters/generic-sql/migration/dialect/mysql.js +60 -0
- package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -0
- package/dist/adapters/generic-sql/migration/dialect/postgres.js +59 -0
- package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -0
- package/dist/adapters/generic-sql/migration/dialect/sqlite.js +96 -0
- package/dist/adapters/generic-sql/migration/dialect/sqlite.js.map +1 -0
- package/dist/adapters/generic-sql/migration/executor.d.ts +15 -0
- package/dist/adapters/generic-sql/migration/executor.d.ts.map +1 -0
- package/dist/adapters/generic-sql/migration/executor.js +18 -0
- package/dist/adapters/generic-sql/migration/executor.js.map +1 -0
- package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts +66 -0
- package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -0
- package/dist/adapters/generic-sql/migration/prepared-migrations.js +68 -0
- package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -0
- package/dist/adapters/generic-sql/migration/sql-generator.js +212 -0
- package/dist/adapters/generic-sql/migration/sql-generator.js.map +1 -0
- package/dist/adapters/generic-sql/query/create-sql-query-compiler.js +32 -0
- package/dist/adapters/generic-sql/query/create-sql-query-compiler.js.map +1 -0
- package/dist/adapters/generic-sql/query/cursor-utils.js +37 -0
- package/dist/adapters/generic-sql/query/cursor-utils.js.map +1 -0
- package/dist/adapters/generic-sql/query/dialect/mysql.js +33 -0
- package/dist/adapters/generic-sql/query/dialect/mysql.js.map +1 -0
- package/dist/adapters/generic-sql/query/dialect/postgres.js +32 -0
- package/dist/adapters/generic-sql/query/dialect/postgres.js.map +1 -0
- package/dist/adapters/generic-sql/query/dialect/sqlite.js +32 -0
- package/dist/adapters/generic-sql/query/dialect/sqlite.js.map +1 -0
- package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js +152 -0
- package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js.map +1 -0
- package/dist/adapters/generic-sql/query/select-builder.js +69 -0
- package/dist/adapters/generic-sql/query/select-builder.js.map +1 -0
- package/dist/adapters/generic-sql/query/sql-query-compiler.js +145 -0
- package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -0
- package/dist/adapters/generic-sql/query/where-builder.js +129 -0
- package/dist/adapters/generic-sql/query/where-builder.js.map +1 -0
- package/dist/adapters/generic-sql/result-interpreter.js +74 -0
- package/dist/adapters/generic-sql/result-interpreter.js.map +1 -0
- package/dist/adapters/generic-sql/uow-decoder.js +105 -0
- package/dist/adapters/generic-sql/uow-decoder.js.map +1 -0
- package/dist/adapters/generic-sql/uow-encoder.js +93 -0
- package/dist/adapters/generic-sql/uow-encoder.js.map +1 -0
- package/dist/adapters/kysely/kysely-adapter.d.ts +5 -16
- package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
- package/dist/adapters/kysely/kysely-adapter.js +6 -159
- package/dist/adapters/kysely/kysely-adapter.js.map +1 -1
- package/dist/adapters/{drizzle/drizzle-query.js → shared/from-unit-of-work-compiler.js} +48 -62
- package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -0
- package/dist/adapters/{kysely/kysely-shared.d.ts → shared/table-name-mapper.d.ts} +3 -2
- package/dist/adapters/shared/table-name-mapper.d.ts.map +1 -0
- package/dist/adapters/shared/table-name-mapper.js +43 -0
- package/dist/adapters/shared/table-name-mapper.js.map +1 -0
- package/dist/adapters/shared/uow-operation-compiler.js +105 -0
- package/dist/adapters/shared/uow-operation-compiler.js.map +1 -0
- package/dist/db-fragment-definition-builder.d.ts +186 -0
- package/dist/db-fragment-definition-builder.d.ts.map +1 -0
- package/dist/db-fragment-definition-builder.js +207 -0
- package/dist/db-fragment-definition-builder.js.map +1 -0
- package/dist/fragments/internal-fragment.d.ts +53 -0
- package/dist/fragments/internal-fragment.d.ts.map +1 -0
- package/dist/fragments/internal-fragment.js +111 -0
- package/dist/fragments/internal-fragment.js.map +1 -0
- package/dist/hooks/hooks.d.ts +51 -0
- package/dist/hooks/hooks.d.ts.map +1 -0
- package/dist/hooks/hooks.js +88 -0
- package/dist/hooks/hooks.js.map +1 -0
- package/dist/migration-engine/generation-engine.d.ts +0 -2
- package/dist/migration-engine/generation-engine.d.ts.map +1 -1
- package/dist/migration-engine/generation-engine.js +38 -56
- package/dist/migration-engine/generation-engine.js.map +1 -1
- package/dist/mod.d.ts +35 -23
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +48 -45
- package/dist/mod.js.map +1 -1
- package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js +165 -0
- package/dist/node_modules/.pnpm/rou3@0.7.10/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 +525 -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/column-defaults.js +27 -0
- package/dist/query/column-defaults.js.map +1 -0
- package/dist/query/cursor.d.ts +14 -6
- package/dist/query/cursor.d.ts.map +1 -1
- package/dist/query/cursor.js +16 -7
- package/dist/query/cursor.js.map +1 -1
- package/dist/query/orm/orm.d.ts +1 -1
- package/dist/query/orm/orm.js.map +1 -1
- package/dist/query/serialize/create-sql-serializer.js +30 -0
- package/dist/query/serialize/create-sql-serializer.js.map +1 -0
- package/dist/query/serialize/dialect/mysql-serializer.js +87 -0
- package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -0
- package/dist/query/serialize/dialect/postgres-serializer.js +80 -0
- package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -0
- package/dist/query/serialize/dialect/sqlite-serializer.js +93 -0
- package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -0
- package/dist/query/serialize/sql-serializer.js +67 -0
- package/dist/query/serialize/sql-serializer.js.map +1 -0
- package/dist/query/{query.d.ts → simple-query-interface.d.ts} +6 -6
- package/dist/query/simple-query-interface.d.ts.map +1 -0
- package/dist/query/unit-of-work/execute-unit-of-work.d.ts +133 -0
- package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -0
- package/dist/query/unit-of-work/execute-unit-of-work.js +197 -0
- package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -0
- package/dist/query/unit-of-work/retry-policy.d.ts +88 -0
- package/dist/query/unit-of-work/retry-policy.d.ts.map +1 -0
- package/dist/query/unit-of-work/retry-policy.js +61 -0
- package/dist/query/unit-of-work/retry-policy.js.map +1 -0
- package/dist/query/{unit-of-work.d.ts → unit-of-work/unit-of-work.d.ts} +145 -58
- package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -0
- package/dist/query/{unit-of-work.js → unit-of-work/unit-of-work.js} +435 -198
- package/dist/query/unit-of-work/unit-of-work.js.map +1 -0
- package/dist/query/value-decoding.js +71 -0
- package/dist/query/value-decoding.js.map +1 -0
- package/dist/query/value-encoding.js +124 -0
- package/dist/query/value-encoding.js.map +1 -0
- package/dist/schema/create.d.ts +3 -0
- package/dist/schema/create.d.ts.map +1 -1
- package/dist/schema/create.js +4 -0
- package/dist/schema/create.js.map +1 -1
- package/dist/schema/type-conversion/create-sql-type-mapper.js +29 -0
- package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -0
- package/dist/schema/type-conversion/dialect/mysql.js +57 -0
- package/dist/schema/type-conversion/dialect/mysql.js.map +1 -0
- package/dist/schema/type-conversion/dialect/postgres.js +56 -0
- package/dist/schema/type-conversion/dialect/postgres.js.map +1 -0
- package/dist/schema/type-conversion/dialect/sqlite.js +52 -0
- package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -0
- package/dist/schema/type-conversion/type-mapping.js +63 -0
- package/dist/schema/type-conversion/type-mapping.js.map +1 -0
- package/dist/sql-driver/connection/connection-provider.d.ts +13 -0
- package/dist/sql-driver/connection/connection-provider.d.ts.map +1 -0
- package/dist/sql-driver/connection/connection-provider.js +19 -0
- package/dist/sql-driver/connection/connection-provider.js.map +1 -0
- package/dist/sql-driver/connection/single-connection-provider.js +23 -0
- package/dist/sql-driver/connection/single-connection-provider.js.map +1 -0
- package/dist/sql-driver/dialect-adapter/dialect-adapter.d.ts +7 -0
- package/dist/sql-driver/dialect-adapter/dialect-adapter.d.ts.map +1 -0
- package/dist/sql-driver/dialects/dialects.d.ts +2 -0
- package/dist/sql-driver/dialects/dialects.js +3 -0
- package/dist/sql-driver/dialects/durable-object-dialect.d.ts +72 -0
- package/dist/sql-driver/dialects/durable-object-dialect.d.ts.map +1 -0
- package/dist/sql-driver/dialects/durable-object-dialect.js +130 -0
- package/dist/sql-driver/dialects/durable-object-dialect.js.map +1 -0
- package/dist/sql-driver/driver/runtime-driver.d.ts +23 -0
- package/dist/sql-driver/driver/runtime-driver.d.ts.map +1 -0
- package/dist/sql-driver/driver/runtime-driver.js +56 -0
- package/dist/sql-driver/driver/runtime-driver.js.map +1 -0
- package/dist/sql-driver/query-executor/default-query-executor.js +26 -0
- package/dist/sql-driver/query-executor/default-query-executor.js.map +1 -0
- package/dist/sql-driver/query-executor/plugin.d.ts +17 -0
- package/dist/sql-driver/query-executor/plugin.d.ts.map +1 -0
- package/dist/sql-driver/query-executor/query-executor-base.js +25 -0
- package/dist/sql-driver/query-executor/query-executor-base.js.map +1 -0
- package/dist/sql-driver/query-executor/query-executor.d.ts +36 -0
- package/dist/sql-driver/query-executor/query-executor.d.ts.map +1 -0
- package/dist/sql-driver/sql-driver-adapter.d.ts +29 -0
- package/dist/sql-driver/sql-driver-adapter.d.ts.map +1 -0
- package/dist/sql-driver/sql-driver-adapter.js +68 -0
- package/dist/sql-driver/sql-driver-adapter.js.map +1 -0
- package/dist/sql-driver/sql-driver.d.ts +38 -0
- package/dist/sql-driver/sql-driver.d.ts.map +1 -0
- package/dist/sql-driver/sql-driver.js +1 -0
- package/dist/sql-driver/sql.js +50 -0
- package/dist/sql-driver/sql.js.map +1 -0
- package/dist/with-database.d.ts +32 -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 +43 -9
- package/src/adapters/adapters.ts +23 -4
- package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +140 -185
- package/src/adapters/drizzle/{drizzle-adapter-sqlite.test.ts → drizzle-adapter-sqlite3.test.ts} +187 -55
- package/src/adapters/drizzle/drizzle-adapter.ts +14 -93
- package/src/adapters/drizzle/generate.test.ts +102 -269
- package/src/adapters/drizzle/generate.ts +89 -63
- package/src/adapters/drizzle/migrate-drizzle.test.ts +19 -0
- package/src/adapters/drizzle/shared.ts +0 -34
- package/src/adapters/drizzle/test-utils.ts +36 -5
- package/src/adapters/generic-sql/README.md +14 -0
- package/src/adapters/generic-sql/driver-config.ts +144 -0
- package/src/adapters/generic-sql/generic-sql-adapter.test.ts +50 -0
- package/src/adapters/generic-sql/generic-sql-adapter.ts +146 -0
- package/src/adapters/generic-sql/generic-sql-uow-executor.ts +130 -0
- package/src/adapters/generic-sql/migration/cold-kysely.ts +55 -0
- package/src/adapters/{kysely/migration/execute-mysql.test.ts → generic-sql/migration/dialect/mysql.test.ts} +342 -484
- package/src/adapters/generic-sql/migration/dialect/mysql.ts +104 -0
- package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +1008 -0
- package/src/adapters/generic-sql/migration/dialect/postgres.ts +113 -0
- package/src/adapters/{kysely/migration/execute-sqlite.test.ts → generic-sql/migration/dialect/sqlite.test.ts} +307 -510
- package/src/adapters/generic-sql/migration/dialect/sqlite.ts +189 -0
- package/src/adapters/generic-sql/migration/executor.ts +33 -0
- package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +661 -0
- package/src/adapters/generic-sql/migration/prepared-migrations.ts +214 -0
- package/src/adapters/generic-sql/migration/sql-generator.ts +413 -0
- package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +36 -0
- package/src/adapters/generic-sql/query/cursor-utils.ts +56 -0
- package/src/adapters/generic-sql/query/dialect/mysql.ts +34 -0
- package/src/adapters/generic-sql/query/dialect/postgres.ts +32 -0
- package/src/adapters/generic-sql/query/dialect/sqlite.ts +32 -0
- package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +1568 -0
- package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +314 -0
- package/src/adapters/generic-sql/query/select-builder.test.ts +256 -0
- package/src/adapters/generic-sql/query/select-builder.ts +137 -0
- package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +195 -0
- package/src/adapters/generic-sql/query/sql-query-compiler.ts +367 -0
- package/src/adapters/generic-sql/query/where-builder.test.ts +744 -0
- package/src/adapters/generic-sql/query/where-builder.ts +211 -0
- package/src/adapters/generic-sql/result-interpreter.ts +102 -0
- package/src/adapters/generic-sql/test/generic-drizzle-adapter-sqlite3.test.ts +899 -0
- package/src/adapters/generic-sql/uow-decoder.test.ts +399 -0
- package/src/adapters/generic-sql/uow-decoder.ts +152 -0
- package/src/adapters/generic-sql/uow-encoder.test.ts +183 -0
- package/src/adapters/generic-sql/uow-encoder.ts +131 -0
- package/src/adapters/kysely/kysely-adapter-pglite.test.ts +90 -96
- package/src/adapters/kysely/kysely-adapter-sqlocal.test.ts +215 -0
- package/src/adapters/kysely/kysely-adapter.ts +10 -242
- package/src/adapters/{drizzle/drizzle-query.ts → shared/from-unit-of-work-compiler.ts} +111 -106
- package/src/adapters/shared/table-name-mapper.ts +50 -0
- package/src/adapters/shared/uow-operation-compiler.ts +211 -0
- package/src/db-fragment-definition-builder.test.ts +887 -0
- package/src/db-fragment-definition-builder.ts +737 -0
- package/src/db-fragment-instantiator.test.ts +543 -0
- package/src/db-fragment-integration.test.ts +406 -0
- package/src/fragments/internal-fragment.test.ts +549 -0
- package/src/fragments/internal-fragment.ts +249 -0
- package/src/hooks/hooks.test.ts +575 -0
- package/src/hooks/hooks.ts +179 -0
- package/src/migration-engine/generation-engine.test.ts +60 -27
- package/src/migration-engine/generation-engine.ts +99 -92
- package/src/mod.ts +139 -78
- package/src/query/column-defaults.ts +49 -0
- package/src/query/cursor.test.ts +147 -3
- package/src/query/cursor.ts +25 -8
- package/src/query/orm/orm.ts +1 -1
- package/src/query/query-type.test.ts +9 -9
- package/src/query/serialize/create-sql-serializer.ts +34 -0
- package/src/query/serialize/dialect/mysql-serializer.ts +142 -0
- package/src/query/serialize/dialect/postgres-serializer.ts +129 -0
- package/src/query/serialize/dialect/sqlite-serializer.test.ts +251 -0
- package/src/query/serialize/dialect/sqlite-serializer.ts +156 -0
- package/src/query/serialize/sql-serializer.ts +143 -0
- package/src/query/{query.ts → simple-query-interface.ts} +4 -4
- package/src/query/unit-of-work/execute-unit-of-work.test.ts +1310 -0
- package/src/query/unit-of-work/execute-unit-of-work.ts +504 -0
- package/src/query/unit-of-work/retry-policy.test.ts +217 -0
- package/src/query/unit-of-work/retry-policy.ts +141 -0
- package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +831 -0
- package/src/query/{unit-of-work-types.test.ts → unit-of-work/unit-of-work-types.test.ts} +7 -5
- package/src/query/unit-of-work/unit-of-work.test.ts +1716 -0
- package/src/query/{unit-of-work.ts → unit-of-work/unit-of-work.ts} +716 -420
- package/src/query/{result-transform.test.ts → value-decoding.test.ts} +45 -298
- package/src/query/value-decoding.ts +113 -0
- package/src/query/value-encoding.test.ts +390 -0
- package/src/query/value-encoding.ts +168 -0
- package/src/schema/create.test.ts +5 -1
- package/src/schema/create.ts +5 -0
- package/src/schema/serialize.test.ts +165 -407
- package/src/schema/type-conversion/create-sql-type-mapper.ts +28 -0
- package/src/schema/type-conversion/dialect/mysql.ts +64 -0
- package/src/schema/type-conversion/dialect/postgres.ts +62 -0
- package/src/schema/type-conversion/dialect/sqlite.ts +63 -0
- package/src/schema/type-conversion/type-mapping.test.ts +137 -0
- package/src/schema/type-conversion/type-mapping.ts +153 -0
- package/src/shared/connection-pool.ts +5 -5
- package/src/sql-driver/better-sqlite3.test.ts +126 -0
- package/src/sql-driver/connection/connection-provider.ts +27 -0
- package/src/sql-driver/connection/single-connection-provider.ts +42 -0
- package/src/sql-driver/dialect-adapter/dialect-adapter.ts +9 -0
- package/src/sql-driver/dialect-adapter/sqlite-dialect-adapter.ts +7 -0
- package/src/sql-driver/dialects/dialects.ts +1 -0
- package/src/sql-driver/dialects/durable-object-dialect.ts +260 -0
- package/src/sql-driver/driver/runtime-driver.ts +91 -0
- package/src/sql-driver/query-executor/default-query-executor.ts +38 -0
- package/src/sql-driver/query-executor/plugin.ts +22 -0
- package/src/sql-driver/query-executor/query-executor-base.ts +53 -0
- package/src/sql-driver/query-executor/query-executor.ts +44 -0
- package/src/sql-driver/sql-driver-adapter.ts +96 -0
- package/src/sql-driver/sql-driver.ts +53 -0
- package/src/sql-driver/sql.ts +57 -0
- package/src/sql-driver/sqlocal.test.ts +117 -0
- package/src/with-database.ts +152 -0
- package/tsdown.config.ts +8 -2
- package/dist/adapters/drizzle/drizzle-connection-pool.js +0 -40
- package/dist/adapters/drizzle/drizzle-connection-pool.js.map +0 -1
- package/dist/adapters/drizzle/drizzle-query.d.ts +0 -23
- package/dist/adapters/drizzle/drizzle-query.d.ts.map +0 -1
- package/dist/adapters/drizzle/drizzle-query.js.map +0 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts +0 -10
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map +0 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.js +0 -315
- package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +0 -1
- package/dist/adapters/drizzle/drizzle-uow-decoder.js +0 -116
- package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +0 -1
- package/dist/adapters/drizzle/drizzle-uow-executor.js +0 -149
- package/dist/adapters/drizzle/drizzle-uow-executor.js.map +0 -1
- package/dist/adapters/drizzle/join-column-utils.js +0 -28
- package/dist/adapters/drizzle/join-column-utils.js.map +0 -1
- package/dist/adapters/drizzle/shared.d.ts +0 -14
- package/dist/adapters/drizzle/shared.d.ts.map +0 -1
- package/dist/adapters/drizzle/shared.js +0 -35
- package/dist/adapters/drizzle/shared.js.map +0 -1
- package/dist/adapters/kysely/kysely-connection-pool.js +0 -41
- package/dist/adapters/kysely/kysely-connection-pool.js.map +0 -1
- package/dist/adapters/kysely/kysely-query-builder.js +0 -321
- package/dist/adapters/kysely/kysely-query-builder.js.map +0 -1
- package/dist/adapters/kysely/kysely-query-compiler.js +0 -66
- package/dist/adapters/kysely/kysely-query-compiler.js.map +0 -1
- package/dist/adapters/kysely/kysely-query.d.ts +0 -22
- package/dist/adapters/kysely/kysely-query.d.ts.map +0 -1
- package/dist/adapters/kysely/kysely-query.js +0 -223
- package/dist/adapters/kysely/kysely-query.js.map +0 -1
- package/dist/adapters/kysely/kysely-shared.d.ts.map +0 -1
- package/dist/adapters/kysely/kysely-shared.js +0 -18
- package/dist/adapters/kysely/kysely-shared.js.map +0 -1
- package/dist/adapters/kysely/kysely-uow-compiler.js +0 -170
- package/dist/adapters/kysely/kysely-uow-compiler.js.map +0 -1
- package/dist/adapters/kysely/kysely-uow-executor.js +0 -89
- package/dist/adapters/kysely/kysely-uow-executor.js.map +0 -1
- package/dist/adapters/kysely/migration/execute-base.js +0 -128
- package/dist/adapters/kysely/migration/execute-base.js.map +0 -1
- package/dist/adapters/kysely/migration/execute-factory.js +0 -34
- package/dist/adapters/kysely/migration/execute-factory.js.map +0 -1
- package/dist/adapters/kysely/migration/execute-mssql.js +0 -112
- package/dist/adapters/kysely/migration/execute-mssql.js.map +0 -1
- package/dist/adapters/kysely/migration/execute-mysql.js +0 -93
- package/dist/adapters/kysely/migration/execute-mysql.js.map +0 -1
- package/dist/adapters/kysely/migration/execute-postgres.js +0 -104
- package/dist/adapters/kysely/migration/execute-postgres.js.map +0 -1
- package/dist/adapters/kysely/migration/execute-sqlite.js +0 -123
- package/dist/adapters/kysely/migration/execute-sqlite.js.map +0 -1
- package/dist/adapters/kysely/migration/execute.js +0 -34
- package/dist/adapters/kysely/migration/execute.js.map +0 -1
- 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/migration-engine/create.d.ts +0 -37
- package/dist/migration-engine/create.d.ts.map +0 -1
- package/dist/migration-engine/create.js +0 -58
- package/dist/migration-engine/create.js.map +0 -1
- package/dist/migration-engine/shared.d.ts +0 -112
- package/dist/migration-engine/shared.d.ts.map +0 -1
- package/dist/query/query.d.ts.map +0 -1
- package/dist/query/result-transform.js +0 -168
- package/dist/query/result-transform.js.map +0 -1
- package/dist/query/unit-of-work.d.ts.map +0 -1
- package/dist/query/unit-of-work.js.map +0 -1
- package/dist/schema/serialize.js +0 -106
- package/dist/schema/serialize.js.map +0 -1
- package/dist/shared/settings-schema.js +0 -36
- package/dist/shared/settings-schema.js.map +0 -1
- package/src/adapters/drizzle/drizzle-adapter.test.ts +0 -170
- package/src/adapters/drizzle/drizzle-connection-pool.ts +0 -66
- package/src/adapters/drizzle/drizzle-query.test.ts +0 -499
- package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +0 -1383
- package/src/adapters/drizzle/drizzle-uow-compiler.ts +0 -636
- package/src/adapters/drizzle/drizzle-uow-decoder.ts +0 -218
- package/src/adapters/drizzle/drizzle-uow-executor.ts +0 -276
- package/src/adapters/drizzle/join-column-utils.test.ts +0 -79
- package/src/adapters/drizzle/join-column-utils.ts +0 -39
- package/src/adapters/kysely/kysely-connection-pool.ts +0 -70
- package/src/adapters/kysely/kysely-query-builder.test.ts +0 -1344
- package/src/adapters/kysely/kysely-query-builder.ts +0 -666
- package/src/adapters/kysely/kysely-query-compiler.ts +0 -132
- package/src/adapters/kysely/kysely-query.test.ts +0 -498
- package/src/adapters/kysely/kysely-query.ts +0 -390
- package/src/adapters/kysely/kysely-shared.ts +0 -23
- package/src/adapters/kysely/kysely-uow-compiler.test.ts +0 -998
- package/src/adapters/kysely/kysely-uow-compiler.ts +0 -318
- package/src/adapters/kysely/kysely-uow-executor.ts +0 -145
- package/src/adapters/kysely/kysely-uow-joins.test.ts +0 -811
- package/src/adapters/kysely/migration/execute-base.ts +0 -256
- package/src/adapters/kysely/migration/execute-factory.ts +0 -53
- package/src/adapters/kysely/migration/execute-mssql.ts +0 -250
- package/src/adapters/kysely/migration/execute-mysql.ts +0 -211
- package/src/adapters/kysely/migration/execute-postgres.test.ts +0 -2657
- package/src/adapters/kysely/migration/execute-postgres.ts +0 -234
- package/src/adapters/kysely/migration/execute-sqlite.ts +0 -247
- package/src/adapters/kysely/migration/execute.ts +0 -50
- package/src/adapters/kysely/migration/kysely-migrator.test.ts +0 -261
- 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/result-transform.ts +0 -271
- package/src/query/unit-of-work-multi-schema.test.ts +0 -64
- package/src/query/unit-of-work.test.ts +0 -943
- package/src/schema/serialize.ts +0 -396
- 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
- /package/dist/query/{query.js → simple-query-interface.js} +0 -0
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import type {
|
|
2
|
+
AnySchema,
|
|
3
|
+
AnyTable,
|
|
4
|
+
Index,
|
|
5
|
+
IdColumn,
|
|
6
|
+
AnyColumn,
|
|
7
|
+
Relation,
|
|
8
|
+
} from "../../schema/create";
|
|
9
|
+
import { FragnoId } from "../../schema/create";
|
|
10
|
+
import type { Condition, ConditionBuilder } from "../condition-builder";
|
|
4
11
|
import type {
|
|
5
12
|
SelectClause,
|
|
6
13
|
TableToInsertValues,
|
|
@@ -8,12 +15,13 @@ import type {
|
|
|
8
15
|
SelectResult,
|
|
9
16
|
ExtractSelect,
|
|
10
17
|
ExtractJoinOut,
|
|
11
|
-
} from "
|
|
12
|
-
import { buildCondition } from "
|
|
13
|
-
import type { CompiledJoin } from "
|
|
14
|
-
import type { CursorResult } from "
|
|
15
|
-
import { Cursor } from "
|
|
16
|
-
import type { Prettify } from "
|
|
18
|
+
} from "../simple-query-interface";
|
|
19
|
+
import { buildCondition } from "../condition-builder";
|
|
20
|
+
import type { CompiledJoin } from "../orm/orm";
|
|
21
|
+
import type { CursorResult } from "../cursor";
|
|
22
|
+
import { Cursor } from "../cursor";
|
|
23
|
+
import type { Prettify } from "../../util/types";
|
|
24
|
+
import type { TriggeredHook, TriggerHookOptions, HooksMap, HookPayload } from "../../hooks/hooks";
|
|
17
25
|
|
|
18
26
|
/**
|
|
19
27
|
* Builder for updateMany operations that supports both whereIndex and set chaining
|
|
@@ -157,6 +165,7 @@ export type RetrievalOperation<
|
|
|
157
165
|
indexName: string;
|
|
158
166
|
options: FindOptions<TTable, SelectClause<TTable>>;
|
|
159
167
|
withCursor?: boolean;
|
|
168
|
+
withSingleResult?: boolean;
|
|
160
169
|
}
|
|
161
170
|
| {
|
|
162
171
|
type: "count";
|
|
@@ -198,6 +207,13 @@ export type MutationOperation<
|
|
|
198
207
|
table: TTable["name"];
|
|
199
208
|
id: FragnoId | string;
|
|
200
209
|
checkVersion: boolean;
|
|
210
|
+
}
|
|
211
|
+
| {
|
|
212
|
+
type: "check";
|
|
213
|
+
schema: TSchema;
|
|
214
|
+
namespace?: string;
|
|
215
|
+
table: TTable["name"];
|
|
216
|
+
id: FragnoId;
|
|
201
217
|
};
|
|
202
218
|
|
|
203
219
|
/**
|
|
@@ -205,12 +221,22 @@ export type MutationOperation<
|
|
|
205
221
|
*/
|
|
206
222
|
export interface CompiledMutation<TOutput> {
|
|
207
223
|
query: TOutput;
|
|
224
|
+
/**
|
|
225
|
+
* The type of mutation operation (create, update, delete, or check).
|
|
226
|
+
*/
|
|
227
|
+
op: "create" | "update" | "delete" | "check";
|
|
208
228
|
/**
|
|
209
229
|
* Number of rows this operation must affect for the transaction to succeed.
|
|
210
230
|
* If actual affected rows doesn't match, it indicates a version conflict.
|
|
211
231
|
* null means don't check affected rows (e.g., for create operations).
|
|
212
232
|
*/
|
|
213
|
-
expectedAffectedRows:
|
|
233
|
+
expectedAffectedRows: bigint | null;
|
|
234
|
+
/**
|
|
235
|
+
* Number of rows this SELECT query must return for the transaction to succeed.
|
|
236
|
+
* Used for check operations to verify version without modifying data.
|
|
237
|
+
* null means this is not a SELECT query that needs row count validation.
|
|
238
|
+
*/
|
|
239
|
+
expectedReturnedRows: number | null;
|
|
214
240
|
}
|
|
215
241
|
|
|
216
242
|
/**
|
|
@@ -263,7 +289,7 @@ export interface UOWDecoder<TRawInput = unknown> {
|
|
|
263
289
|
* @param operations - Array of retrieval operations that produced these results
|
|
264
290
|
* @returns Decoded results in application format
|
|
265
291
|
*/
|
|
266
|
-
(rawResults: TRawInput[], operations: RetrievalOperation<AnySchema>[]): unknown[];
|
|
292
|
+
decode(rawResults: TRawInput[], operations: RetrievalOperation<AnySchema>[]): unknown[];
|
|
267
293
|
}
|
|
268
294
|
|
|
269
295
|
/**
|
|
@@ -405,8 +431,12 @@ export class FindBuilder<
|
|
|
405
431
|
|
|
406
432
|
/**
|
|
407
433
|
* Set the number of results per page
|
|
434
|
+
* @throws {RangeError} If size is not a positive integer
|
|
408
435
|
*/
|
|
409
436
|
pageSize(size: number): this {
|
|
437
|
+
if (!Number.isInteger(size) || size <= 0) {
|
|
438
|
+
throw new RangeError(`pageSize must be a positive integer, received: ${size}`);
|
|
439
|
+
}
|
|
410
440
|
this.#pageSizeValue = size;
|
|
411
441
|
return this;
|
|
412
442
|
}
|
|
@@ -705,8 +735,12 @@ export class JoinFindBuilder<
|
|
|
705
735
|
|
|
706
736
|
/**
|
|
707
737
|
* Set the number of results to return
|
|
738
|
+
* @throws {RangeError} If size is not a positive integer
|
|
708
739
|
*/
|
|
709
740
|
pageSize(size: number): this {
|
|
741
|
+
if (!Number.isInteger(size) || size <= 0) {
|
|
742
|
+
throw new RangeError(`pageSize must be a positive integer, received: ${size}`);
|
|
743
|
+
}
|
|
710
744
|
this.#pageSizeValue = size;
|
|
711
745
|
return this;
|
|
712
746
|
}
|
|
@@ -862,13 +896,14 @@ export function buildJoinIndexed<TTable extends AnyTable, TJoinOut>(
|
|
|
862
896
|
}
|
|
863
897
|
|
|
864
898
|
/**
|
|
865
|
-
*
|
|
866
|
-
* This allows UOW instances to be passed between
|
|
899
|
+
* Full Unit of Work interface with all operations including execution.
|
|
900
|
+
* This allows UOW instances to be passed between different contexts that use different schemas.
|
|
867
901
|
*/
|
|
868
|
-
export interface
|
|
902
|
+
export interface IUnitOfWork {
|
|
869
903
|
// Getters (schema-agnostic)
|
|
870
904
|
readonly state: UOWState;
|
|
871
905
|
readonly name: string | undefined;
|
|
906
|
+
readonly nonce: string;
|
|
872
907
|
readonly retrievalPhase: Promise<unknown[]>;
|
|
873
908
|
readonly mutationPhase: Promise<void>;
|
|
874
909
|
|
|
@@ -881,30 +916,249 @@ export interface IUnitOfWorkBase {
|
|
|
881
916
|
getMutationOperations(): ReadonlyArray<MutationOperation<AnySchema>>;
|
|
882
917
|
getCreatedIds(): FragnoId[];
|
|
883
918
|
|
|
919
|
+
// Parent-child relationships
|
|
920
|
+
restrict(): IUnitOfWork;
|
|
921
|
+
|
|
922
|
+
// Reset for retry support
|
|
923
|
+
reset(): void;
|
|
924
|
+
|
|
884
925
|
// Schema-specific view (for cross-schema operations)
|
|
885
|
-
|
|
926
|
+
// The optional hooks parameter is for type inference only - pass your hooks map
|
|
927
|
+
// to get proper typing for triggerHook. The value is not used at runtime.
|
|
928
|
+
forSchema<TOtherSchema extends AnySchema, TOtherHooks extends HooksMap = {}>(
|
|
886
929
|
schema: TOtherSchema,
|
|
930
|
+
hooks?: TOtherHooks,
|
|
887
931
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
888
|
-
):
|
|
932
|
+
): TypedUnitOfWork<TOtherSchema, [], any, TOtherHooks>;
|
|
933
|
+
|
|
934
|
+
// Schema registration (for cross-fragment operations like hooks)
|
|
935
|
+
registerSchema(schema: AnySchema, namespace: string): void;
|
|
936
|
+
|
|
937
|
+
// Hook triggering (schema-agnostic, string-based hook names)
|
|
938
|
+
triggerHook(hookName: string, payload: unknown, options?: TriggerHookOptions): void;
|
|
939
|
+
|
|
940
|
+
getTriggeredHooks(): readonly TriggeredHook[];
|
|
889
941
|
}
|
|
890
942
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
943
|
+
/**
|
|
944
|
+
* Restricted UOW interface without execute methods.
|
|
945
|
+
* Useful when you want to allow building operations but not executing them,
|
|
946
|
+
* to prevent deadlocks or enforce execution control at a higher level.
|
|
947
|
+
*
|
|
948
|
+
* Note: This is just a marker interface. Restriction is enforced by the UnitOfWork class itself.
|
|
949
|
+
*/
|
|
950
|
+
export interface IUnitOfWorkRestricted
|
|
951
|
+
extends Omit<IUnitOfWork, "executeRetrieve" | "executeMutations"> {}
|
|
952
|
+
|
|
953
|
+
export function createUnitOfWork(
|
|
897
954
|
compiler: UOWCompiler<unknown>,
|
|
898
|
-
executor: UOWExecutor<unknown,
|
|
899
|
-
decoder: UOWDecoder<
|
|
955
|
+
executor: UOWExecutor<unknown, unknown>,
|
|
956
|
+
decoder: UOWDecoder<unknown>,
|
|
957
|
+
schemaNamespaceMap?: WeakMap<AnySchema, string>,
|
|
900
958
|
name?: string,
|
|
901
|
-
): UnitOfWork
|
|
902
|
-
return new UnitOfWork(
|
|
959
|
+
): UnitOfWork {
|
|
960
|
+
return new UnitOfWork(compiler, executor, decoder, name, undefined, schemaNamespaceMap);
|
|
903
961
|
}
|
|
904
962
|
|
|
905
963
|
export interface UnitOfWorkConfig {
|
|
906
964
|
dryRun?: boolean;
|
|
907
965
|
onQuery?: (query: unknown) => void;
|
|
966
|
+
nonce?: string;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
/**
|
|
970
|
+
* Encapsulates a promise with its resolver/rejecter functions.
|
|
971
|
+
* Simplifies management of deferred promises with built-in error handling.
|
|
972
|
+
*/
|
|
973
|
+
class DeferredPromise<T> {
|
|
974
|
+
#resolve?: (value: T) => void;
|
|
975
|
+
#reject?: (error: Error) => void;
|
|
976
|
+
#promise: Promise<T>;
|
|
977
|
+
|
|
978
|
+
constructor() {
|
|
979
|
+
const { promise, resolve, reject } = Promise.withResolvers<T>();
|
|
980
|
+
this.#promise = promise;
|
|
981
|
+
this.#resolve = resolve;
|
|
982
|
+
this.#reject = reject;
|
|
983
|
+
// Attach no-op error handler to prevent unhandled rejection warnings
|
|
984
|
+
this.#promise.catch(() => {});
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
get promise(): Promise<T> {
|
|
988
|
+
return this.#promise;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
resolve(value: T): void {
|
|
992
|
+
this.#resolve?.(value);
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
reject(error: Error): void {
|
|
996
|
+
this.#reject?.(error);
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
/**
|
|
1000
|
+
* Reset to a new promise
|
|
1001
|
+
*/
|
|
1002
|
+
reset(): void {
|
|
1003
|
+
const { promise, resolve, reject } = Promise.withResolvers<T>();
|
|
1004
|
+
this.#promise = promise;
|
|
1005
|
+
this.#resolve = resolve;
|
|
1006
|
+
this.#reject = reject;
|
|
1007
|
+
// Attach no-op error handler to prevent unhandled rejection warnings
|
|
1008
|
+
this.#promise.catch(() => {});
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
/**
|
|
1013
|
+
* Tracks readiness signals from a group of children.
|
|
1014
|
+
* Maintains a promise that resolves when all registered children have signaled.
|
|
1015
|
+
*/
|
|
1016
|
+
class ReadinessTracker {
|
|
1017
|
+
#expectedCount = 0;
|
|
1018
|
+
#signalCount = 0;
|
|
1019
|
+
#resolve?: () => void;
|
|
1020
|
+
#promise: Promise<void> = Promise.resolve();
|
|
1021
|
+
|
|
1022
|
+
get promise(): Promise<void> {
|
|
1023
|
+
return this.#promise;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
/**
|
|
1027
|
+
* Register that we're expecting a signal from a child
|
|
1028
|
+
*/
|
|
1029
|
+
registerChild(): void {
|
|
1030
|
+
if (this.#expectedCount === 0) {
|
|
1031
|
+
// First child - create new promise
|
|
1032
|
+
const { promise, resolve } = Promise.withResolvers<void>();
|
|
1033
|
+
this.#promise = promise;
|
|
1034
|
+
this.#resolve = resolve;
|
|
1035
|
+
}
|
|
1036
|
+
this.#expectedCount++;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
/**
|
|
1040
|
+
* Signal that one child is ready
|
|
1041
|
+
*/
|
|
1042
|
+
signal(): void {
|
|
1043
|
+
this.#signalCount++;
|
|
1044
|
+
if (this.#signalCount >= this.#expectedCount && this.#resolve) {
|
|
1045
|
+
this.#resolve();
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
/**
|
|
1050
|
+
* Reset to initial state
|
|
1051
|
+
*/
|
|
1052
|
+
reset(): void {
|
|
1053
|
+
this.#expectedCount = 0;
|
|
1054
|
+
this.#signalCount = 0;
|
|
1055
|
+
this.#resolve = undefined;
|
|
1056
|
+
this.#promise = Promise.resolve();
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
/**
|
|
1061
|
+
* Manages parent-child relationships and readiness coordination for Unit of Work instances.
|
|
1062
|
+
* This allows parent UOWs to wait for all child UOWs to signal readiness before executing phases.
|
|
1063
|
+
*/
|
|
1064
|
+
class UOWChildCoordinator<TRawInput> {
|
|
1065
|
+
#parent: UnitOfWork<TRawInput> | null = null;
|
|
1066
|
+
#parentCoordinator: UOWChildCoordinator<TRawInput> | null = null;
|
|
1067
|
+
#children: Set<UnitOfWork<TRawInput>> = new Set();
|
|
1068
|
+
#isRestricted = false;
|
|
1069
|
+
|
|
1070
|
+
#retrievalTracker = new ReadinessTracker();
|
|
1071
|
+
#mutationTracker = new ReadinessTracker();
|
|
1072
|
+
|
|
1073
|
+
get isRestricted(): boolean {
|
|
1074
|
+
return this.#isRestricted;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
get parent(): UnitOfWork<TRawInput> | null {
|
|
1078
|
+
return this.#parent;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
get children(): ReadonlySet<UnitOfWork<TRawInput>> {
|
|
1082
|
+
return this.#children;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
get retrievalReadinessPromise(): Promise<void> {
|
|
1086
|
+
return this.#retrievalTracker.promise;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
get mutationReadinessPromise(): Promise<void> {
|
|
1090
|
+
return this.#mutationTracker.promise;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
/**
|
|
1094
|
+
* Mark this UOW as a restricted child of the given parent
|
|
1095
|
+
*/
|
|
1096
|
+
setAsRestricted(
|
|
1097
|
+
parent: UnitOfWork<TRawInput>,
|
|
1098
|
+
parentCoordinator: UOWChildCoordinator<TRawInput>,
|
|
1099
|
+
): void {
|
|
1100
|
+
this.#parent = parent;
|
|
1101
|
+
this.#parentCoordinator = parentCoordinator;
|
|
1102
|
+
this.#isRestricted = true;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
/**
|
|
1106
|
+
* Register a child UOW
|
|
1107
|
+
*/
|
|
1108
|
+
addChild(child: UnitOfWork<TRawInput>): void {
|
|
1109
|
+
this.#children.add(child);
|
|
1110
|
+
this.#retrievalTracker.registerChild();
|
|
1111
|
+
this.#mutationTracker.registerChild();
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
/**
|
|
1115
|
+
* Signal that this child is ready for retrieval phase execution.
|
|
1116
|
+
* Only valid for restricted (child) UOWs.
|
|
1117
|
+
*/
|
|
1118
|
+
signalReadyForRetrieval(): void {
|
|
1119
|
+
if (!this.#parentCoordinator) {
|
|
1120
|
+
throw new Error("signalReadyForRetrieval() can only be called on restricted child UOWs");
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
this.#parentCoordinator.notifyChildReadyForRetrieval();
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
/**
|
|
1127
|
+
* Signal that this child is ready for mutation phase execution.
|
|
1128
|
+
* Only valid for restricted (child) UOWs.
|
|
1129
|
+
*/
|
|
1130
|
+
signalReadyForMutation(): void {
|
|
1131
|
+
if (!this.#parentCoordinator) {
|
|
1132
|
+
throw new Error("signalReadyForMutation() can only be called on restricted child UOWs");
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
this.#parentCoordinator.notifyChildReadyForMutation();
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
/**
|
|
1139
|
+
* Notify this coordinator that a child is ready for retrieval (internal use).
|
|
1140
|
+
* Called by child UOWs when they signal readiness.
|
|
1141
|
+
*/
|
|
1142
|
+
notifyChildReadyForRetrieval(): void {
|
|
1143
|
+
this.#retrievalTracker.signal();
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
/**
|
|
1147
|
+
* Notify this coordinator that a child is ready for mutation (internal use).
|
|
1148
|
+
* Called by child UOWs when they signal readiness.
|
|
1149
|
+
*/
|
|
1150
|
+
notifyChildReadyForMutation(): void {
|
|
1151
|
+
this.#mutationTracker.signal();
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
/**
|
|
1155
|
+
* Reset coordination state for retry support
|
|
1156
|
+
*/
|
|
1157
|
+
reset(): void {
|
|
1158
|
+
this.#children.clear();
|
|
1159
|
+
this.#retrievalTracker.reset();
|
|
1160
|
+
this.#mutationTracker.reset();
|
|
1161
|
+
}
|
|
908
1162
|
}
|
|
909
1163
|
|
|
910
1164
|
/**
|
|
@@ -914,19 +1168,22 @@ export interface UnitOfWorkConfig {
|
|
|
914
1168
|
* 1. Retrieval phase: Read operations to fetch entities with their versions
|
|
915
1169
|
* 2. Mutation phase: Write operations that check versions before committing
|
|
916
1170
|
*
|
|
1171
|
+
* This is the untyped base storage. Use TypedUnitOfWork for type-safe operations.
|
|
1172
|
+
*
|
|
917
1173
|
* @example
|
|
918
1174
|
* ```ts
|
|
919
1175
|
* const uow = queryEngine.createUnitOfWork("update-user-balance");
|
|
1176
|
+
* const typedUow = uow.forSchema(mySchema);
|
|
920
1177
|
*
|
|
921
1178
|
* // Retrieval phase
|
|
922
|
-
*
|
|
1179
|
+
* typedUow.find("users", (b) => b.whereIndex("primary", (eb) => eb("id", "=", userId)));
|
|
923
1180
|
*
|
|
924
1181
|
* // Execute retrieval and transition to mutation phase
|
|
925
1182
|
* const [users] = await uow.executeRetrieve();
|
|
926
1183
|
*
|
|
927
1184
|
* // Mutation phase with version check
|
|
928
1185
|
* const user = users[0];
|
|
929
|
-
*
|
|
1186
|
+
* typedUow.update("users", user.id, (b) => b.set({ balance: newBalance }).check());
|
|
930
1187
|
*
|
|
931
1188
|
* // Execute mutations
|
|
932
1189
|
* const { success } = await uow.executeMutations();
|
|
@@ -935,39 +1192,40 @@ export interface UnitOfWorkConfig {
|
|
|
935
1192
|
* }
|
|
936
1193
|
* ```
|
|
937
1194
|
*/
|
|
938
|
-
export class UnitOfWork<
|
|
939
|
-
const TSchema extends AnySchema,
|
|
940
|
-
const TRetrievalResults extends unknown[] = [],
|
|
941
|
-
const TRawInput = unknown,
|
|
942
|
-
> implements IUnitOfWorkBase
|
|
943
|
-
{
|
|
944
|
-
#schema: TSchema;
|
|
945
|
-
|
|
1195
|
+
export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
|
|
946
1196
|
#name?: string;
|
|
947
1197
|
#config?: UnitOfWorkConfig;
|
|
1198
|
+
#nonce: string;
|
|
948
1199
|
|
|
949
1200
|
#state: UOWState = "building-retrieval";
|
|
950
1201
|
|
|
951
|
-
// Operations can
|
|
1202
|
+
// Operations can come from any schema
|
|
952
1203
|
#retrievalOps: RetrievalOperation<AnySchema>[] = [];
|
|
953
1204
|
#mutationOps: MutationOperation<AnySchema>[] = [];
|
|
954
1205
|
|
|
955
1206
|
#compiler: UOWCompiler<unknown>;
|
|
956
1207
|
#executor: UOWExecutor<unknown, TRawInput>;
|
|
957
1208
|
#decoder: UOWDecoder<TRawInput>;
|
|
958
|
-
#schemaNamespaceMap
|
|
1209
|
+
#schemaNamespaceMap: WeakMap<AnySchema, string>;
|
|
959
1210
|
|
|
960
|
-
#retrievalResults?:
|
|
1211
|
+
#retrievalResults?: unknown[];
|
|
961
1212
|
#createdInternalIds: (bigint | null)[] = [];
|
|
962
1213
|
|
|
963
1214
|
// Phase coordination promises
|
|
964
|
-
#
|
|
965
|
-
#
|
|
966
|
-
|
|
967
|
-
|
|
1215
|
+
#retrievalPhaseDeferred = new DeferredPromise<unknown[]>();
|
|
1216
|
+
#mutationPhaseDeferred = new DeferredPromise<void>();
|
|
1217
|
+
|
|
1218
|
+
// Error tracking
|
|
1219
|
+
#retrievalError: Error | null = null;
|
|
1220
|
+
#mutationError: Error | null = null;
|
|
1221
|
+
|
|
1222
|
+
// Child coordination
|
|
1223
|
+
#coordinator: UOWChildCoordinator<TRawInput> = new UOWChildCoordinator();
|
|
1224
|
+
|
|
1225
|
+
// Hook triggers
|
|
1226
|
+
#triggeredHooks: TriggeredHook[] = [];
|
|
968
1227
|
|
|
969
1228
|
constructor(
|
|
970
|
-
schema: TSchema,
|
|
971
1229
|
compiler: UOWCompiler<unknown>,
|
|
972
1230
|
executor: UOWExecutor<unknown, TRawInput>,
|
|
973
1231
|
decoder: UOWDecoder<TRawInput>,
|
|
@@ -975,381 +1233,233 @@ export class UnitOfWork<
|
|
|
975
1233
|
config?: UnitOfWorkConfig,
|
|
976
1234
|
schemaNamespaceMap?: WeakMap<AnySchema, string>,
|
|
977
1235
|
) {
|
|
978
|
-
this.#schema = schema;
|
|
979
1236
|
this.#compiler = compiler;
|
|
980
1237
|
this.#executor = executor;
|
|
981
1238
|
this.#decoder = decoder;
|
|
1239
|
+
this.#schemaNamespaceMap = schemaNamespaceMap ?? new WeakMap();
|
|
982
1240
|
this.#name = name;
|
|
983
1241
|
this.#config = config;
|
|
984
|
-
this.#
|
|
985
|
-
|
|
986
|
-
// Initialize phase coordination promises
|
|
987
|
-
this.#retrievalPhasePromise = new Promise<TRetrievalResults>((resolve) => {
|
|
988
|
-
this.#retrievalPhaseResolve = resolve;
|
|
989
|
-
});
|
|
990
|
-
this.#mutationPhasePromise = new Promise<void>((resolve) => {
|
|
991
|
-
this.#mutationPhaseResolve = resolve;
|
|
992
|
-
});
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
get schema(): TSchema {
|
|
996
|
-
return this.#schema;
|
|
1242
|
+
this.#nonce = config?.nonce ?? crypto.randomUUID();
|
|
997
1243
|
}
|
|
998
1244
|
|
|
999
|
-
|
|
1000
|
-
|
|
1245
|
+
/**
|
|
1246
|
+
* Register a schema with its namespace for cross-fragment operations.
|
|
1247
|
+
* This is used for internal fragments like hooks that need to create
|
|
1248
|
+
* records in a different schema during the same transaction.
|
|
1249
|
+
*/
|
|
1250
|
+
registerSchema(schema: AnySchema, namespace: string): void {
|
|
1251
|
+
this.#schemaNamespaceMap.set(schema, namespace);
|
|
1001
1252
|
}
|
|
1002
1253
|
|
|
1003
1254
|
/**
|
|
1004
|
-
* Get a schema-specific view of this UOW for type-safe operations
|
|
1005
|
-
* Returns a wrapper that
|
|
1255
|
+
* Get a schema-specific typed view of this UOW for type-safe operations.
|
|
1256
|
+
* Returns a wrapper that provides typed operations for the given schema.
|
|
1006
1257
|
* The namespace is automatically resolved from the schema-namespace map.
|
|
1258
|
+
* The optional hooks parameter is for type inference only - pass your hooks map
|
|
1259
|
+
* to get proper typing for triggerHook. The value is not used at runtime.
|
|
1007
1260
|
*/
|
|
1008
|
-
forSchema<TOtherSchema extends AnySchema>(
|
|
1261
|
+
forSchema<TOtherSchema extends AnySchema, TOtherHooks extends HooksMap = {}>(
|
|
1009
1262
|
schema: TOtherSchema,
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
const resolvedNamespace = this.#schemaNamespaceMap
|
|
1263
|
+
_hooks?: TOtherHooks,
|
|
1264
|
+
): TypedUnitOfWork<TOtherSchema, [], TRawInput, TOtherHooks> {
|
|
1265
|
+
const resolvedNamespace = this.#schemaNamespaceMap.get(schema);
|
|
1013
1266
|
|
|
1014
|
-
|
|
1015
|
-
// As operations are added, the types will accumulate correctly
|
|
1016
|
-
return new UnitOfWorkSchemaView(
|
|
1267
|
+
return new TypedUnitOfWork<TOtherSchema, [], TRawInput, TOtherHooks>(
|
|
1017
1268
|
schema,
|
|
1018
1269
|
resolvedNamespace,
|
|
1019
|
-
this
|
|
1270
|
+
this,
|
|
1020
1271
|
);
|
|
1021
1272
|
}
|
|
1022
1273
|
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1274
|
+
/**
|
|
1275
|
+
* Create a restricted child UOW that cannot execute phases.
|
|
1276
|
+
* The child shares the same operation storage but must signal readiness
|
|
1277
|
+
* before the parent can execute each phase.
|
|
1278
|
+
*/
|
|
1279
|
+
restrict(): UnitOfWork<TRawInput> {
|
|
1280
|
+
const child = new UnitOfWork(
|
|
1281
|
+
this.#compiler,
|
|
1282
|
+
this.#executor,
|
|
1283
|
+
this.#decoder,
|
|
1284
|
+
this.#name,
|
|
1285
|
+
{ ...this.#config, nonce: this.#nonce },
|
|
1286
|
+
this.#schemaNamespaceMap,
|
|
1287
|
+
);
|
|
1288
|
+
child.#coordinator.setAsRestricted(this, this.#coordinator);
|
|
1026
1289
|
|
|
1027
|
-
|
|
1028
|
-
|
|
1290
|
+
// Share state with parent
|
|
1291
|
+
child.#state = this.#state;
|
|
1292
|
+
child.#retrievalOps = this.#retrievalOps;
|
|
1293
|
+
child.#mutationOps = this.#mutationOps;
|
|
1294
|
+
child.#retrievalResults = this.#retrievalResults;
|
|
1295
|
+
child.#createdInternalIds = this.#createdInternalIds;
|
|
1296
|
+
child.#retrievalPhaseDeferred = this.#retrievalPhaseDeferred;
|
|
1297
|
+
child.#mutationPhaseDeferred = this.#mutationPhaseDeferred;
|
|
1298
|
+
child.#retrievalError = this.#retrievalError;
|
|
1299
|
+
child.#mutationError = this.#mutationError;
|
|
1300
|
+
child.#triggeredHooks = this.#triggeredHooks;
|
|
1301
|
+
|
|
1302
|
+
this.#coordinator.addChild(child);
|
|
1303
|
+
|
|
1304
|
+
// For synchronous usage (the common case), immediately signal readiness
|
|
1305
|
+
// This allows services called directly from handlers to work without explicit signaling
|
|
1306
|
+
child.signalReadyForRetrieval();
|
|
1307
|
+
child.signalReadyForMutation();
|
|
1308
|
+
|
|
1309
|
+
return child;
|
|
1029
1310
|
}
|
|
1030
1311
|
|
|
1031
1312
|
/**
|
|
1032
|
-
*
|
|
1033
|
-
*
|
|
1313
|
+
* Signal that this child is ready for retrieval phase execution.
|
|
1314
|
+
* Only valid for restricted (child) UOWs.
|
|
1034
1315
|
*/
|
|
1035
|
-
|
|
1036
|
-
|
|
1316
|
+
signalReadyForRetrieval(): void {
|
|
1317
|
+
this.#coordinator.signalReadyForRetrieval();
|
|
1037
1318
|
}
|
|
1038
1319
|
|
|
1039
1320
|
/**
|
|
1040
|
-
*
|
|
1041
|
-
*
|
|
1321
|
+
* Signal that this child is ready for mutation phase execution.
|
|
1322
|
+
* Only valid for restricted (child) UOWs.
|
|
1042
1323
|
*/
|
|
1043
|
-
|
|
1044
|
-
|
|
1324
|
+
signalReadyForMutation(): void {
|
|
1325
|
+
this.#coordinator.signalReadyForMutation();
|
|
1045
1326
|
}
|
|
1046
1327
|
|
|
1047
1328
|
/**
|
|
1048
|
-
*
|
|
1049
|
-
*
|
|
1329
|
+
* Reset the UOW to initial state for retry support.
|
|
1330
|
+
* Clears operations, resets state, and resets phase promises.
|
|
1050
1331
|
*/
|
|
1051
|
-
|
|
1052
|
-
if (this.#
|
|
1053
|
-
throw new Error(
|
|
1054
|
-
`Cannot execute retrieval from state ${this.#state}. Must be in building-retrieval state.`,
|
|
1055
|
-
);
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
if (this.#retrievalOps.length === 0) {
|
|
1059
|
-
this.#state = "building-mutation";
|
|
1060
|
-
const emptyResults = [] as unknown as TRetrievalResults;
|
|
1061
|
-
this.#retrievalPhaseResolve?.(emptyResults);
|
|
1062
|
-
return emptyResults;
|
|
1063
|
-
}
|
|
1064
|
-
|
|
1065
|
-
// Compile retrieval operations using single compiler
|
|
1066
|
-
const retrievalBatch: unknown[] = [];
|
|
1067
|
-
for (const op of this.#retrievalOps) {
|
|
1068
|
-
const compiled = this.#compiler.compileRetrievalOperation(op);
|
|
1069
|
-
if (compiled !== null) {
|
|
1070
|
-
this.#config?.onQuery?.(compiled);
|
|
1071
|
-
retrievalBatch.push(compiled);
|
|
1072
|
-
}
|
|
1332
|
+
reset(): void {
|
|
1333
|
+
if (this.#coordinator.isRestricted) {
|
|
1334
|
+
throw new Error("reset() cannot be called on restricted child UOWs");
|
|
1073
1335
|
}
|
|
1074
1336
|
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1337
|
+
// Clear operations
|
|
1338
|
+
this.#retrievalOps = [];
|
|
1339
|
+
this.#mutationOps = [];
|
|
1340
|
+
this.#retrievalResults = undefined;
|
|
1341
|
+
this.#createdInternalIds = [];
|
|
1079
1342
|
|
|
1080
|
-
//
|
|
1081
|
-
|
|
1343
|
+
// Reset state
|
|
1344
|
+
this.#state = "building-retrieval";
|
|
1345
|
+
this.#retrievalError = null;
|
|
1346
|
+
this.#mutationError = null;
|
|
1082
1347
|
|
|
1083
|
-
//
|
|
1084
|
-
|
|
1348
|
+
// Reset phase promises
|
|
1349
|
+
this.#retrievalPhaseDeferred.reset();
|
|
1350
|
+
this.#mutationPhaseDeferred.reset();
|
|
1085
1351
|
|
|
1086
|
-
//
|
|
1087
|
-
this.#
|
|
1088
|
-
this.#state = "building-mutation";
|
|
1352
|
+
// Reset child coordination
|
|
1353
|
+
this.#coordinator.reset();
|
|
1089
1354
|
|
|
1090
|
-
//
|
|
1091
|
-
this.#
|
|
1092
|
-
|
|
1093
|
-
return this.#retrievalResults;
|
|
1355
|
+
// Reset hooks
|
|
1356
|
+
this.#triggeredHooks = [];
|
|
1094
1357
|
}
|
|
1095
1358
|
|
|
1096
1359
|
/**
|
|
1097
|
-
*
|
|
1360
|
+
* Trigger a hook to be executed after the transaction commits.
|
|
1098
1361
|
*/
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
): UnitOfWork<
|
|
1105
|
-
TSchema,
|
|
1106
|
-
[
|
|
1107
|
-
...TRetrievalResults,
|
|
1108
|
-
SelectResult<
|
|
1109
|
-
TSchema["tables"][TTableName],
|
|
1110
|
-
ExtractJoinOut<TBuilderResult>,
|
|
1111
|
-
Extract<ExtractSelect<TBuilderResult>, SelectClause<TSchema["tables"][TTableName]>>
|
|
1112
|
-
>[],
|
|
1113
|
-
],
|
|
1114
|
-
TRawInput
|
|
1115
|
-
>;
|
|
1116
|
-
find<TTableName extends keyof TSchema["tables"] & string>(
|
|
1117
|
-
tableName: TTableName,
|
|
1118
|
-
): UnitOfWork<
|
|
1119
|
-
TSchema,
|
|
1120
|
-
[...TRetrievalResults, SelectResult<TSchema["tables"][TTableName], {}, true>[]],
|
|
1121
|
-
TRawInput
|
|
1122
|
-
>;
|
|
1123
|
-
find<TTableName extends keyof TSchema["tables"] & string, const TBuilderResult>(
|
|
1124
|
-
tableName: TTableName,
|
|
1125
|
-
builderFn?: (
|
|
1126
|
-
builder: Omit<FindBuilder<TSchema["tables"][TTableName]>, "build">,
|
|
1127
|
-
) => TBuilderResult,
|
|
1128
|
-
): UnitOfWork<
|
|
1129
|
-
TSchema,
|
|
1130
|
-
[
|
|
1131
|
-
...TRetrievalResults,
|
|
1132
|
-
SelectResult<
|
|
1133
|
-
TSchema["tables"][TTableName],
|
|
1134
|
-
ExtractJoinOut<TBuilderResult>,
|
|
1135
|
-
Extract<ExtractSelect<TBuilderResult>, SelectClause<TSchema["tables"][TTableName]>>
|
|
1136
|
-
>[],
|
|
1137
|
-
],
|
|
1138
|
-
TRawInput
|
|
1139
|
-
> {
|
|
1140
|
-
if (this.#state !== "building-retrieval") {
|
|
1141
|
-
throw new Error(
|
|
1142
|
-
`find() can only be called during retrieval phase. Current state: ${this.#state}`,
|
|
1143
|
-
);
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
|
-
const table = this.#schema.tables[tableName];
|
|
1147
|
-
if (!table) {
|
|
1148
|
-
throw new Error(`Table ${tableName} not found in schema`);
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
// Create builder, pass to callback (or use default), then extract configuration
|
|
1152
|
-
const builder = new FindBuilder(tableName, table as TSchema["tables"][TTableName]);
|
|
1153
|
-
if (builderFn) {
|
|
1154
|
-
builderFn(builder);
|
|
1155
|
-
} else {
|
|
1156
|
-
// Default to primary index with no filter
|
|
1157
|
-
builder.whereIndex("primary");
|
|
1158
|
-
}
|
|
1159
|
-
const { indexName, options, type } = builder.build();
|
|
1160
|
-
|
|
1161
|
-
this.#retrievalOps.push({
|
|
1162
|
-
type,
|
|
1163
|
-
schema: this.#schema,
|
|
1164
|
-
// Safe: we know the table is part of the schema from the find() method
|
|
1165
|
-
table: table as TSchema["tables"][TTableName],
|
|
1166
|
-
indexName,
|
|
1167
|
-
// Safe: we're storing the options for later compilation
|
|
1168
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1169
|
-
options: options as any,
|
|
1362
|
+
triggerHook(hookName: string, payload: unknown, options?: TriggerHookOptions): void {
|
|
1363
|
+
this.#triggeredHooks.push({
|
|
1364
|
+
hookName,
|
|
1365
|
+
payload,
|
|
1366
|
+
options,
|
|
1170
1367
|
});
|
|
1171
|
-
|
|
1172
|
-
// Safe: return type is correctly specified in the method signature
|
|
1173
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1174
|
-
return this as any;
|
|
1175
1368
|
}
|
|
1176
1369
|
|
|
1177
1370
|
/**
|
|
1178
|
-
*
|
|
1371
|
+
* Get all triggered hooks for this UOW.
|
|
1179
1372
|
*/
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
// We omit "build" because we don't want to expose it to the user
|
|
1184
|
-
builder: Omit<FindBuilder<TSchema["tables"][TTableName]>, "build">,
|
|
1185
|
-
) => TBuilderResult,
|
|
1186
|
-
): UnitOfWork<
|
|
1187
|
-
TSchema,
|
|
1188
|
-
[
|
|
1189
|
-
...TRetrievalResults,
|
|
1190
|
-
CursorResult<
|
|
1191
|
-
SelectResult<
|
|
1192
|
-
TSchema["tables"][TTableName],
|
|
1193
|
-
ExtractJoinOut<TBuilderResult>,
|
|
1194
|
-
Extract<ExtractSelect<TBuilderResult>, SelectClause<TSchema["tables"][TTableName]>>
|
|
1195
|
-
>
|
|
1196
|
-
>,
|
|
1197
|
-
],
|
|
1198
|
-
TRawInput
|
|
1199
|
-
> {
|
|
1200
|
-
if (this.#state !== "building-retrieval") {
|
|
1201
|
-
throw new Error(
|
|
1202
|
-
`findWithCursor() can only be called during retrieval phase. Current state: ${this.#state}`,
|
|
1203
|
-
);
|
|
1204
|
-
}
|
|
1373
|
+
getTriggeredHooks(): ReadonlyArray<TriggeredHook> {
|
|
1374
|
+
return this.#triggeredHooks;
|
|
1375
|
+
}
|
|
1205
1376
|
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
}
|
|
1377
|
+
get state(): UOWState {
|
|
1378
|
+
return this.#state;
|
|
1379
|
+
}
|
|
1210
1380
|
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
const { indexName, options, type } = builder.build();
|
|
1381
|
+
get name(): string | undefined {
|
|
1382
|
+
return this.#name;
|
|
1383
|
+
}
|
|
1215
1384
|
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
// Safe: we know the table is part of the schema from the findWithCursor() method
|
|
1220
|
-
table: table as TSchema["tables"][TTableName],
|
|
1221
|
-
indexName,
|
|
1222
|
-
// Safe: we're storing the options for later compilation
|
|
1223
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1224
|
-
options: options as any,
|
|
1225
|
-
withCursor: true,
|
|
1226
|
-
});
|
|
1385
|
+
get nonce(): string {
|
|
1386
|
+
return this.#nonce;
|
|
1387
|
+
}
|
|
1227
1388
|
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1389
|
+
/**
|
|
1390
|
+
* Promise that resolves when the retrieval phase is executed
|
|
1391
|
+
* Service methods can await this to coordinate multi-phase logic
|
|
1392
|
+
*/
|
|
1393
|
+
get retrievalPhase(): Promise<unknown[]> {
|
|
1394
|
+
return this.#retrievalPhaseDeferred.promise;
|
|
1231
1395
|
}
|
|
1232
1396
|
|
|
1233
1397
|
/**
|
|
1234
|
-
*
|
|
1235
|
-
*
|
|
1398
|
+
* Promise that resolves when the mutation phase is executed
|
|
1399
|
+
* Service methods can await this to coordinate multi-phase logic
|
|
1236
1400
|
*/
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
): FragnoId {
|
|
1241
|
-
if (this.#state === "executed") {
|
|
1242
|
-
throw new Error(`create() can only be called during mutation phase.`);
|
|
1243
|
-
}
|
|
1401
|
+
get mutationPhase(): Promise<void> {
|
|
1402
|
+
return this.#mutationPhaseDeferred.promise;
|
|
1403
|
+
}
|
|
1244
1404
|
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1405
|
+
/**
|
|
1406
|
+
* Execute the retrieval phase and transition to mutation phase
|
|
1407
|
+
* Returns all results from find operations
|
|
1408
|
+
*/
|
|
1409
|
+
async executeRetrieve(): Promise<unknown[]> {
|
|
1410
|
+
if (this.#coordinator.isRestricted) {
|
|
1411
|
+
throw new Error("executeRetrieve() cannot be called on restricted child UOWs");
|
|
1248
1412
|
}
|
|
1249
1413
|
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1414
|
+
if (this.#state !== "building-retrieval") {
|
|
1415
|
+
throw new Error(
|
|
1416
|
+
`Cannot execute retrieval from state ${this.#state}. Must be in building-retrieval state.`,
|
|
1417
|
+
);
|
|
1418
|
+
}
|
|
1253
1419
|
|
|
1254
|
-
|
|
1255
|
-
|
|
1420
|
+
try {
|
|
1421
|
+
// Wait for all children to signal readiness
|
|
1422
|
+
await this.#coordinator.retrievalReadinessPromise;
|
|
1256
1423
|
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
"externalId" in providedIdValue
|
|
1263
|
-
) {
|
|
1264
|
-
externalId = (providedIdValue as FragnoId).externalId;
|
|
1265
|
-
} else {
|
|
1266
|
-
externalId = providedIdValue as string;
|
|
1267
|
-
}
|
|
1268
|
-
} else {
|
|
1269
|
-
// Generate using the column's default configuration
|
|
1270
|
-
const generated = idColumn.generateDefaultValue();
|
|
1271
|
-
if (generated === undefined) {
|
|
1272
|
-
throw new Error(
|
|
1273
|
-
`No ID value provided and ID column ${idColumn.ormName} has no default generator`,
|
|
1274
|
-
);
|
|
1424
|
+
if (this.#retrievalOps.length === 0) {
|
|
1425
|
+
this.#state = "building-mutation";
|
|
1426
|
+
const emptyResults: unknown[] = [];
|
|
1427
|
+
this.#retrievalPhaseDeferred.resolve(emptyResults);
|
|
1428
|
+
return emptyResults;
|
|
1275
1429
|
}
|
|
1276
|
-
externalId = generated as string;
|
|
1277
1430
|
|
|
1278
|
-
//
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1431
|
+
// Compile retrieval operations using single compiler
|
|
1432
|
+
const retrievalBatch: unknown[] = [];
|
|
1433
|
+
for (const op of this.#retrievalOps) {
|
|
1434
|
+
const compiled = this.#compiler.compileRetrievalOperation(op);
|
|
1435
|
+
if (compiled !== null) {
|
|
1436
|
+
this.#config?.onQuery?.(compiled);
|
|
1437
|
+
retrievalBatch.push(compiled);
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1284
1440
|
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
});
|
|
1441
|
+
if (this.#config?.dryRun) {
|
|
1442
|
+
this.#state = "executed";
|
|
1443
|
+
const emptyResults: unknown[] = [];
|
|
1444
|
+
this.#retrievalPhaseDeferred.resolve(emptyResults);
|
|
1445
|
+
return emptyResults;
|
|
1446
|
+
}
|
|
1292
1447
|
|
|
1293
|
-
|
|
1294
|
-
}
|
|
1448
|
+
const rawResults = await this.#executor.executeRetrievalPhase(retrievalBatch);
|
|
1295
1449
|
|
|
1296
|
-
|
|
1297
|
-
* Add an update operation using a builder callback (mutation phase only)
|
|
1298
|
-
*/
|
|
1299
|
-
update<TableName extends keyof TSchema["tables"] & string>(
|
|
1300
|
-
table: TableName,
|
|
1301
|
-
id: FragnoId | string,
|
|
1302
|
-
builderFn: (
|
|
1303
|
-
// We omit "build" because we don't want to expose it to the user
|
|
1304
|
-
builder: Omit<UpdateBuilder<TSchema["tables"][TableName]>, "build">,
|
|
1305
|
-
) => Omit<UpdateBuilder<TSchema["tables"][TableName]>, "build"> | void,
|
|
1306
|
-
): void {
|
|
1307
|
-
if (this.#state === "executed") {
|
|
1308
|
-
throw new Error(`update() can only be called during mutation phase.`);
|
|
1309
|
-
}
|
|
1450
|
+
const results = this.#decoder.decode(rawResults, this.#retrievalOps);
|
|
1310
1451
|
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
const { id: opId, checkVersion, set } = builder.build();
|
|
1452
|
+
// Store results and transition to mutation phase
|
|
1453
|
+
this.#retrievalResults = results;
|
|
1454
|
+
this.#state = "building-mutation";
|
|
1315
1455
|
|
|
1316
|
-
|
|
1317
|
-
type: "update",
|
|
1318
|
-
schema: this.#schema,
|
|
1319
|
-
table,
|
|
1320
|
-
id: opId,
|
|
1321
|
-
checkVersion,
|
|
1322
|
-
set,
|
|
1323
|
-
});
|
|
1324
|
-
}
|
|
1456
|
+
this.#retrievalPhaseDeferred.resolve(this.#retrievalResults);
|
|
1325
1457
|
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
table: TableName,
|
|
1331
|
-
id: FragnoId | string,
|
|
1332
|
-
builderFn?: (
|
|
1333
|
-
// We omit "build" because we don't want to expose it to the user
|
|
1334
|
-
builder: Omit<DeleteBuilder, "build">,
|
|
1335
|
-
) => Omit<DeleteBuilder, "build"> | void,
|
|
1336
|
-
): void {
|
|
1337
|
-
if (this.#state === "executed") {
|
|
1338
|
-
throw new Error(`delete() can only be called during mutation phase.`);
|
|
1458
|
+
return this.#retrievalResults;
|
|
1459
|
+
} catch (error) {
|
|
1460
|
+
this.#retrievalError = error instanceof Error ? error : new Error(String(error));
|
|
1461
|
+
throw error;
|
|
1339
1462
|
}
|
|
1340
|
-
|
|
1341
|
-
// Create builder, optionally pass to callback, then extract configuration
|
|
1342
|
-
const builder = new DeleteBuilder(table, id);
|
|
1343
|
-
builderFn?.(builder);
|
|
1344
|
-
const { id: opId, checkVersion } = builder.build();
|
|
1345
|
-
|
|
1346
|
-
this.#mutationOps.push({
|
|
1347
|
-
type: "delete",
|
|
1348
|
-
schema: this.#schema,
|
|
1349
|
-
table,
|
|
1350
|
-
id: opId,
|
|
1351
|
-
checkVersion,
|
|
1352
|
-
});
|
|
1353
1463
|
}
|
|
1354
1464
|
|
|
1355
1465
|
/**
|
|
@@ -1357,41 +1467,54 @@ export class UnitOfWork<
|
|
|
1357
1467
|
* Returns success flag indicating if mutations completed without conflicts
|
|
1358
1468
|
*/
|
|
1359
1469
|
async executeMutations(): Promise<{ success: boolean }> {
|
|
1470
|
+
if (this.#coordinator.isRestricted) {
|
|
1471
|
+
throw new Error("executeMutations() cannot be called on restricted child UOWs");
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1360
1474
|
if (this.#state === "executed") {
|
|
1361
1475
|
throw new Error(`Cannot execute mutations from state ${this.#state}.`);
|
|
1362
1476
|
}
|
|
1363
1477
|
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1478
|
+
try {
|
|
1479
|
+
// Wait for all children to signal readiness
|
|
1480
|
+
await this.#coordinator.mutationReadinessPromise;
|
|
1481
|
+
|
|
1482
|
+
// Compile mutation operations using single compiler
|
|
1483
|
+
const mutationBatch: CompiledMutation<unknown>[] = [];
|
|
1484
|
+
for (const op of this.#mutationOps) {
|
|
1485
|
+
const compiled = this.#compiler.compileMutationOperation(op);
|
|
1486
|
+
if (compiled !== null) {
|
|
1487
|
+
this.#config?.onQuery?.(compiled);
|
|
1488
|
+
mutationBatch.push(compiled);
|
|
1489
|
+
}
|
|
1371
1490
|
}
|
|
1372
|
-
}
|
|
1373
1491
|
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1492
|
+
if (this.#config?.dryRun) {
|
|
1493
|
+
this.#state = "executed";
|
|
1494
|
+
this.#mutationPhaseDeferred.resolve();
|
|
1495
|
+
return {
|
|
1496
|
+
success: true,
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1380
1499
|
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1500
|
+
// Execute mutation phase
|
|
1501
|
+
const result = await this.#executor.executeMutationPhase(mutationBatch);
|
|
1502
|
+
this.#state = "executed";
|
|
1384
1503
|
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1504
|
+
if (result.success) {
|
|
1505
|
+
this.#createdInternalIds = result.createdInternalIds;
|
|
1506
|
+
}
|
|
1388
1507
|
|
|
1389
|
-
|
|
1390
|
-
|
|
1508
|
+
// Resolve the mutation phase promise to unblock waiting service methods
|
|
1509
|
+
this.#mutationPhaseDeferred.resolve();
|
|
1391
1510
|
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1511
|
+
return {
|
|
1512
|
+
success: result.success,
|
|
1513
|
+
};
|
|
1514
|
+
} catch (error) {
|
|
1515
|
+
this.#mutationError = error instanceof Error ? error : new Error(String(error));
|
|
1516
|
+
throw error;
|
|
1517
|
+
}
|
|
1395
1518
|
}
|
|
1396
1519
|
|
|
1397
1520
|
/**
|
|
@@ -1410,18 +1533,26 @@ export class UnitOfWork<
|
|
|
1410
1533
|
|
|
1411
1534
|
/**
|
|
1412
1535
|
* @internal
|
|
1413
|
-
* Add a retrieval operation (used by
|
|
1536
|
+
* Add a retrieval operation (used by TypedUnitOfWork)
|
|
1414
1537
|
*/
|
|
1415
1538
|
addRetrievalOperation(op: RetrievalOperation<AnySchema>): number {
|
|
1539
|
+
if (this.#state !== "building-retrieval") {
|
|
1540
|
+
throw new Error(
|
|
1541
|
+
`Cannot add retrieval operation in state ${this.#state}. Must be in building-retrieval state.`,
|
|
1542
|
+
);
|
|
1543
|
+
}
|
|
1416
1544
|
this.#retrievalOps.push(op);
|
|
1417
1545
|
return this.#retrievalOps.length - 1;
|
|
1418
1546
|
}
|
|
1419
1547
|
|
|
1420
1548
|
/**
|
|
1421
1549
|
* @internal
|
|
1422
|
-
* Add a mutation operation (used by
|
|
1550
|
+
* Add a mutation operation (used by TypedUnitOfWork)
|
|
1423
1551
|
*/
|
|
1424
1552
|
addMutationOperation(op: MutationOperation<AnySchema>): void {
|
|
1553
|
+
if (this.#state === "executed") {
|
|
1554
|
+
throw new Error(`Cannot add mutation operation in executed state.`);
|
|
1555
|
+
}
|
|
1425
1556
|
this.#mutationOps.push(op);
|
|
1426
1557
|
}
|
|
1427
1558
|
|
|
@@ -1494,28 +1625,27 @@ export class UnitOfWork<
|
|
|
1494
1625
|
}
|
|
1495
1626
|
|
|
1496
1627
|
/**
|
|
1497
|
-
* A
|
|
1498
|
-
* All operations are stored in the
|
|
1628
|
+
* A typed facade around a UnitOfWork that provides type-safe operations for a specific schema.
|
|
1629
|
+
* All operations are stored in the underlying UOW, but this facade ensures type safety and
|
|
1630
|
+
* filters retrieval results to only include operations added through this facade.
|
|
1499
1631
|
*/
|
|
1500
|
-
export class
|
|
1632
|
+
export class TypedUnitOfWork<
|
|
1501
1633
|
const TSchema extends AnySchema,
|
|
1502
1634
|
const TRetrievalResults extends unknown[] = [],
|
|
1503
1635
|
const TRawInput = unknown,
|
|
1504
|
-
|
|
1636
|
+
const THooks extends HooksMap = {},
|
|
1637
|
+
> implements IUnitOfWork
|
|
1505
1638
|
{
|
|
1506
1639
|
#schema: TSchema;
|
|
1507
1640
|
#namespace?: string;
|
|
1508
|
-
#
|
|
1641
|
+
#uow: UnitOfWork<TRawInput>;
|
|
1509
1642
|
#operationIndices: number[] = [];
|
|
1643
|
+
#cachedRetrievalPhase?: Promise<TRetrievalResults>;
|
|
1510
1644
|
|
|
1511
|
-
constructor(
|
|
1512
|
-
schema: TSchema,
|
|
1513
|
-
namespace: string | undefined,
|
|
1514
|
-
parent: UnitOfWork<AnySchema, unknown[], TRawInput>,
|
|
1515
|
-
) {
|
|
1645
|
+
constructor(schema: TSchema, namespace: string | undefined, uow: UnitOfWork<TRawInput>) {
|
|
1516
1646
|
this.#schema = schema;
|
|
1517
1647
|
this.#namespace = namespace;
|
|
1518
|
-
this.#
|
|
1648
|
+
this.#uow = uow;
|
|
1519
1649
|
}
|
|
1520
1650
|
|
|
1521
1651
|
get $results(): Prettify<TRetrievalResults> {
|
|
@@ -1527,43 +1657,86 @@ export class UnitOfWorkSchemaView<
|
|
|
1527
1657
|
}
|
|
1528
1658
|
|
|
1529
1659
|
get name(): string | undefined {
|
|
1530
|
-
return this.#
|
|
1660
|
+
return this.#uow.name;
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
get nonce(): string {
|
|
1664
|
+
return this.#uow.nonce;
|
|
1531
1665
|
}
|
|
1532
1666
|
|
|
1533
1667
|
get state() {
|
|
1534
|
-
return this.#
|
|
1668
|
+
return this.#uow.state;
|
|
1535
1669
|
}
|
|
1536
1670
|
|
|
1537
1671
|
get retrievalPhase(): Promise<TRetrievalResults> {
|
|
1538
|
-
//
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1672
|
+
// Cache the filtered promise to avoid recreating it on every access
|
|
1673
|
+
if (!this.#cachedRetrievalPhase) {
|
|
1674
|
+
this.#cachedRetrievalPhase = this.#uow.retrievalPhase.then((allResults) => {
|
|
1675
|
+
const allOperations = this.#uow.getRetrievalOperations();
|
|
1676
|
+
const filteredResults = this.#operationIndices.map((opIndex) => {
|
|
1677
|
+
const result = allResults[opIndex];
|
|
1678
|
+
const operation = allOperations[opIndex];
|
|
1679
|
+
// Transform array to single item for findFirst operations
|
|
1680
|
+
if (operation?.type === "find" && operation.withSingleResult) {
|
|
1681
|
+
return Array.isArray(result) ? (result[0] ?? null) : result;
|
|
1682
|
+
}
|
|
1683
|
+
return result;
|
|
1684
|
+
});
|
|
1685
|
+
return filteredResults as TRetrievalResults;
|
|
1686
|
+
});
|
|
1687
|
+
}
|
|
1688
|
+
return this.#cachedRetrievalPhase;
|
|
1543
1689
|
}
|
|
1544
1690
|
|
|
1545
1691
|
get mutationPhase(): Promise<void> {
|
|
1546
|
-
return this.#
|
|
1692
|
+
return this.#uow.mutationPhase;
|
|
1547
1693
|
}
|
|
1548
1694
|
|
|
1549
1695
|
getRetrievalOperations() {
|
|
1550
|
-
return this.#
|
|
1696
|
+
return this.#uow.getRetrievalOperations();
|
|
1551
1697
|
}
|
|
1552
1698
|
|
|
1553
1699
|
getMutationOperations() {
|
|
1554
|
-
return this.#
|
|
1700
|
+
return this.#uow.getMutationOperations();
|
|
1555
1701
|
}
|
|
1556
1702
|
|
|
1557
1703
|
getCreatedIds() {
|
|
1558
|
-
return this.#
|
|
1704
|
+
return this.#uow.getCreatedIds();
|
|
1559
1705
|
}
|
|
1560
1706
|
|
|
1561
|
-
async executeRetrieve(): Promise<
|
|
1562
|
-
return this.#
|
|
1707
|
+
async executeRetrieve(): Promise<TRetrievalResults> {
|
|
1708
|
+
return this.#uow.executeRetrieve() as Promise<TRetrievalResults>;
|
|
1563
1709
|
}
|
|
1564
1710
|
|
|
1565
1711
|
async executeMutations(): Promise<{ success: boolean }> {
|
|
1566
|
-
return this.#
|
|
1712
|
+
return this.#uow.executeMutations();
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
restrict(): IUnitOfWork {
|
|
1716
|
+
return this.#uow.restrict();
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
reset(): void {
|
|
1720
|
+
return this.#uow.reset();
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
forSchema<TOtherSchema extends AnySchema, TOtherHooks extends HooksMap = {}>(
|
|
1724
|
+
schema: TOtherSchema,
|
|
1725
|
+
hooks?: TOtherHooks,
|
|
1726
|
+
): TypedUnitOfWork<TOtherSchema, [], TRawInput, TOtherHooks> {
|
|
1727
|
+
return this.#uow.forSchema<TOtherSchema, TOtherHooks>(schema, hooks);
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
registerSchema(schema: AnySchema, namespace: string): void {
|
|
1731
|
+
this.#uow.registerSchema(schema, namespace);
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1734
|
+
compile<TOutput>(compiler: UOWCompiler<TOutput>): {
|
|
1735
|
+
name?: string;
|
|
1736
|
+
retrievalBatch: TOutput[];
|
|
1737
|
+
mutationBatch: CompiledMutation<TOutput>[];
|
|
1738
|
+
} {
|
|
1739
|
+
return this.#uow.compile(compiler);
|
|
1567
1740
|
}
|
|
1568
1741
|
|
|
1569
1742
|
find<TTableName extends keyof TSchema["tables"] & string, const TBuilderResult>(
|
|
@@ -1571,7 +1744,7 @@ export class UnitOfWorkSchemaView<
|
|
|
1571
1744
|
builderFn: (
|
|
1572
1745
|
builder: Omit<FindBuilder<TSchema["tables"][TTableName]>, "build">,
|
|
1573
1746
|
) => TBuilderResult,
|
|
1574
|
-
):
|
|
1747
|
+
): TypedUnitOfWork<
|
|
1575
1748
|
TSchema,
|
|
1576
1749
|
[
|
|
1577
1750
|
...TRetrievalResults,
|
|
@@ -1581,21 +1754,23 @@ export class UnitOfWorkSchemaView<
|
|
|
1581
1754
|
Extract<ExtractSelect<TBuilderResult>, SelectClause<TSchema["tables"][TTableName]>>
|
|
1582
1755
|
>[],
|
|
1583
1756
|
],
|
|
1584
|
-
TRawInput
|
|
1757
|
+
TRawInput,
|
|
1758
|
+
THooks
|
|
1585
1759
|
>;
|
|
1586
1760
|
find<TTableName extends keyof TSchema["tables"] & string>(
|
|
1587
1761
|
tableName: TTableName,
|
|
1588
|
-
):
|
|
1762
|
+
): TypedUnitOfWork<
|
|
1589
1763
|
TSchema,
|
|
1590
1764
|
[...TRetrievalResults, SelectResult<TSchema["tables"][TTableName], {}, true>[]],
|
|
1591
|
-
TRawInput
|
|
1765
|
+
TRawInput,
|
|
1766
|
+
THooks
|
|
1592
1767
|
>;
|
|
1593
1768
|
find<TTableName extends keyof TSchema["tables"] & string, const TBuilderResult>(
|
|
1594
1769
|
tableName: TTableName,
|
|
1595
1770
|
builderFn?: (
|
|
1596
1771
|
builder: Omit<FindBuilder<TSchema["tables"][TTableName]>, "build">,
|
|
1597
1772
|
) => TBuilderResult,
|
|
1598
|
-
):
|
|
1773
|
+
): TypedUnitOfWork<
|
|
1599
1774
|
TSchema,
|
|
1600
1775
|
[
|
|
1601
1776
|
...TRetrievalResults,
|
|
@@ -1605,7 +1780,8 @@ export class UnitOfWorkSchemaView<
|
|
|
1605
1780
|
Extract<ExtractSelect<TBuilderResult>, SelectClause<TSchema["tables"][TTableName]>>
|
|
1606
1781
|
>[],
|
|
1607
1782
|
],
|
|
1608
|
-
TRawInput
|
|
1783
|
+
TRawInput,
|
|
1784
|
+
THooks
|
|
1609
1785
|
> {
|
|
1610
1786
|
const table = this.#schema.tables[tableName];
|
|
1611
1787
|
if (!table) {
|
|
@@ -1620,7 +1796,7 @@ export class UnitOfWorkSchemaView<
|
|
|
1620
1796
|
}
|
|
1621
1797
|
const { indexName, options, type } = builder.build();
|
|
1622
1798
|
|
|
1623
|
-
const operationIndex = this.#
|
|
1799
|
+
const operationIndex = this.#uow.addRetrievalOperation({
|
|
1624
1800
|
type,
|
|
1625
1801
|
schema: this.#schema,
|
|
1626
1802
|
namespace: this.#namespace,
|
|
@@ -1638,12 +1814,90 @@ export class UnitOfWorkSchemaView<
|
|
|
1638
1814
|
return this as any;
|
|
1639
1815
|
}
|
|
1640
1816
|
|
|
1817
|
+
findFirst<TTableName extends keyof TSchema["tables"] & string, const TBuilderResult>(
|
|
1818
|
+
tableName: TTableName,
|
|
1819
|
+
builderFn: (
|
|
1820
|
+
builder: Omit<FindBuilder<TSchema["tables"][TTableName]>, "build">,
|
|
1821
|
+
) => TBuilderResult,
|
|
1822
|
+
): TypedUnitOfWork<
|
|
1823
|
+
TSchema,
|
|
1824
|
+
[
|
|
1825
|
+
...TRetrievalResults,
|
|
1826
|
+
SelectResult<
|
|
1827
|
+
TSchema["tables"][TTableName],
|
|
1828
|
+
ExtractJoinOut<TBuilderResult>,
|
|
1829
|
+
Extract<ExtractSelect<TBuilderResult>, SelectClause<TSchema["tables"][TTableName]>>
|
|
1830
|
+
> | null,
|
|
1831
|
+
],
|
|
1832
|
+
TRawInput,
|
|
1833
|
+
THooks
|
|
1834
|
+
>;
|
|
1835
|
+
findFirst<TTableName extends keyof TSchema["tables"] & string>(
|
|
1836
|
+
tableName: TTableName,
|
|
1837
|
+
): TypedUnitOfWork<
|
|
1838
|
+
TSchema,
|
|
1839
|
+
[...TRetrievalResults, SelectResult<TSchema["tables"][TTableName], {}, true> | null],
|
|
1840
|
+
TRawInput,
|
|
1841
|
+
THooks
|
|
1842
|
+
>;
|
|
1843
|
+
findFirst<TTableName extends keyof TSchema["tables"] & string, const TBuilderResult>(
|
|
1844
|
+
tableName: TTableName,
|
|
1845
|
+
builderFn?: (
|
|
1846
|
+
builder: Omit<FindBuilder<TSchema["tables"][TTableName]>, "build">,
|
|
1847
|
+
) => TBuilderResult,
|
|
1848
|
+
): TypedUnitOfWork<
|
|
1849
|
+
TSchema,
|
|
1850
|
+
[
|
|
1851
|
+
...TRetrievalResults,
|
|
1852
|
+
SelectResult<
|
|
1853
|
+
TSchema["tables"][TTableName],
|
|
1854
|
+
ExtractJoinOut<TBuilderResult>,
|
|
1855
|
+
Extract<ExtractSelect<TBuilderResult>, SelectClause<TSchema["tables"][TTableName]>>
|
|
1856
|
+
> | null,
|
|
1857
|
+
],
|
|
1858
|
+
TRawInput,
|
|
1859
|
+
THooks
|
|
1860
|
+
> {
|
|
1861
|
+
const table = this.#schema.tables[tableName];
|
|
1862
|
+
if (!table) {
|
|
1863
|
+
throw new Error(`Table ${tableName} not found in schema`);
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
const builder = new FindBuilder(tableName, table as TSchema["tables"][TTableName]);
|
|
1867
|
+
if (builderFn) {
|
|
1868
|
+
builderFn(builder);
|
|
1869
|
+
} else {
|
|
1870
|
+
builder.whereIndex("primary");
|
|
1871
|
+
}
|
|
1872
|
+
// Automatically set pageSize to 1 for findFirst
|
|
1873
|
+
builder.pageSize(1);
|
|
1874
|
+
const { indexName, options, type } = builder.build();
|
|
1875
|
+
|
|
1876
|
+
const operationIndex = this.#uow.addRetrievalOperation({
|
|
1877
|
+
type,
|
|
1878
|
+
schema: this.#schema,
|
|
1879
|
+
namespace: this.#namespace,
|
|
1880
|
+
table: table as TSchema["tables"][TTableName],
|
|
1881
|
+
indexName,
|
|
1882
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1883
|
+
options: options as any,
|
|
1884
|
+
withSingleResult: true,
|
|
1885
|
+
});
|
|
1886
|
+
|
|
1887
|
+
// Track which operation index belongs to this view
|
|
1888
|
+
this.#operationIndices.push(operationIndex);
|
|
1889
|
+
|
|
1890
|
+
// Safe: return type is correctly specified in the method signature
|
|
1891
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1892
|
+
return this as any;
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1641
1895
|
findWithCursor<TTableName extends keyof TSchema["tables"] & string, const TBuilderResult>(
|
|
1642
1896
|
tableName: TTableName,
|
|
1643
1897
|
builderFn: (
|
|
1644
1898
|
builder: Omit<FindBuilder<TSchema["tables"][TTableName]>, "build">,
|
|
1645
1899
|
) => TBuilderResult,
|
|
1646
|
-
):
|
|
1900
|
+
): TypedUnitOfWork<
|
|
1647
1901
|
TSchema,
|
|
1648
1902
|
[
|
|
1649
1903
|
...TRetrievalResults,
|
|
@@ -1655,7 +1909,8 @@ export class UnitOfWorkSchemaView<
|
|
|
1655
1909
|
>
|
|
1656
1910
|
>,
|
|
1657
1911
|
],
|
|
1658
|
-
TRawInput
|
|
1912
|
+
TRawInput,
|
|
1913
|
+
THooks
|
|
1659
1914
|
> {
|
|
1660
1915
|
const table = this.#schema.tables[tableName];
|
|
1661
1916
|
if (!table) {
|
|
@@ -1666,7 +1921,7 @@ export class UnitOfWorkSchemaView<
|
|
|
1666
1921
|
builderFn(builder);
|
|
1667
1922
|
const { indexName, options, type } = builder.build();
|
|
1668
1923
|
|
|
1669
|
-
const operationIndex = this.#
|
|
1924
|
+
const operationIndex = this.#uow.addRetrievalOperation({
|
|
1670
1925
|
type,
|
|
1671
1926
|
schema: this.#schema,
|
|
1672
1927
|
namespace: this.#namespace,
|
|
@@ -1729,7 +1984,7 @@ export class UnitOfWorkSchemaView<
|
|
|
1729
1984
|
} as TableToInsertValues<TSchema["tables"][TableName]>;
|
|
1730
1985
|
}
|
|
1731
1986
|
|
|
1732
|
-
this.#
|
|
1987
|
+
this.#uow.addMutationOperation({
|
|
1733
1988
|
type: "create",
|
|
1734
1989
|
schema: this.#schema,
|
|
1735
1990
|
namespace: this.#namespace,
|
|
@@ -1752,7 +2007,7 @@ export class UnitOfWorkSchemaView<
|
|
|
1752
2007
|
builderFn(builder);
|
|
1753
2008
|
const { id: opId, checkVersion, set } = builder.build();
|
|
1754
2009
|
|
|
1755
|
-
this.#
|
|
2010
|
+
this.#uow.addMutationOperation({
|
|
1756
2011
|
type: "update",
|
|
1757
2012
|
schema: this.#schema,
|
|
1758
2013
|
namespace: this.#namespace,
|
|
@@ -1772,7 +2027,7 @@ export class UnitOfWorkSchemaView<
|
|
|
1772
2027
|
builderFn?.(builder);
|
|
1773
2028
|
const { id: opId, checkVersion } = builder.build();
|
|
1774
2029
|
|
|
1775
|
-
this.#
|
|
2030
|
+
this.#uow.addMutationOperation({
|
|
1776
2031
|
type: "delete",
|
|
1777
2032
|
schema: this.#schema,
|
|
1778
2033
|
namespace: this.#namespace,
|
|
@@ -1782,10 +2037,51 @@ export class UnitOfWorkSchemaView<
|
|
|
1782
2037
|
});
|
|
1783
2038
|
}
|
|
1784
2039
|
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
2040
|
+
/**
|
|
2041
|
+
* Check that a record's version hasn't changed since retrieval.
|
|
2042
|
+
* This is useful for ensuring related records remain unchanged during a transaction.
|
|
2043
|
+
*
|
|
2044
|
+
* @param tableName - The table name
|
|
2045
|
+
* @param id - The FragnoId with version information (string IDs are not allowed)
|
|
2046
|
+
* @throws Error if the ID is a string without version information
|
|
2047
|
+
*
|
|
2048
|
+
* @example
|
|
2049
|
+
* ```ts
|
|
2050
|
+
* // Ensure both accounts haven't changed before creating a transfer
|
|
2051
|
+
* uow.check("accounts", fromAccount.id);
|
|
2052
|
+
* uow.check("accounts", toAccount.id);
|
|
2053
|
+
* uow.create("transactions", { fromAccountId, toAccountId, amount });
|
|
2054
|
+
* ```
|
|
2055
|
+
*/
|
|
2056
|
+
check<TableName extends keyof TSchema["tables"] & string>(
|
|
2057
|
+
tableName: TableName,
|
|
2058
|
+
id: FragnoId,
|
|
2059
|
+
): void {
|
|
2060
|
+
this.#uow.addMutationOperation({
|
|
2061
|
+
type: "check",
|
|
2062
|
+
schema: this.#schema,
|
|
2063
|
+
namespace: this.#namespace,
|
|
2064
|
+
table: tableName,
|
|
2065
|
+
id,
|
|
2066
|
+
});
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
get $hooks(): THooks {
|
|
2070
|
+
throw new Error("type only");
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
/**
|
|
2074
|
+
* Trigger a hook to be executed after the transaction commits.
|
|
2075
|
+
*/
|
|
2076
|
+
triggerHook<K extends keyof THooks & string>(
|
|
2077
|
+
hookName: K,
|
|
2078
|
+
payload: HookPayload<THooks[K]>,
|
|
2079
|
+
options?: TriggerHookOptions,
|
|
2080
|
+
): void {
|
|
2081
|
+
this.#uow.triggerHook(hookName, payload, options);
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
getTriggeredHooks(): ReadonlyArray<TriggeredHook> {
|
|
2085
|
+
return this.#uow.getTriggeredHooks();
|
|
1790
2086
|
}
|
|
1791
2087
|
}
|