@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
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
Relation,
|
|
8
8
|
} from "../../schema/create";
|
|
9
9
|
import { FragnoId } from "../../schema/create";
|
|
10
|
+
import { generateId } from "../../schema/generate-id";
|
|
10
11
|
import type { Condition, ConditionBuilder } from "../condition-builder";
|
|
11
12
|
import type {
|
|
12
13
|
SelectClause,
|
|
@@ -160,7 +161,7 @@ export type RetrievalOperation<
|
|
|
160
161
|
| {
|
|
161
162
|
type: "find";
|
|
162
163
|
schema: TSchema;
|
|
163
|
-
namespace?: string;
|
|
164
|
+
namespace?: string | null;
|
|
164
165
|
table: TTable;
|
|
165
166
|
indexName: string;
|
|
166
167
|
options: FindOptions<TTable, SelectClause<TTable>>;
|
|
@@ -170,7 +171,7 @@ export type RetrievalOperation<
|
|
|
170
171
|
| {
|
|
171
172
|
type: "count";
|
|
172
173
|
schema: TSchema;
|
|
173
|
-
namespace?: string;
|
|
174
|
+
namespace?: string | null;
|
|
174
175
|
table: TTable;
|
|
175
176
|
indexName: string;
|
|
176
177
|
options: Pick<FindOptions<TTable>, "where" | "useIndex">;
|
|
@@ -186,7 +187,7 @@ export type MutationOperation<
|
|
|
186
187
|
| {
|
|
187
188
|
type: "update";
|
|
188
189
|
schema: TSchema;
|
|
189
|
-
namespace?: string;
|
|
190
|
+
namespace?: string | null;
|
|
190
191
|
table: TTable["name"];
|
|
191
192
|
id: FragnoId | string;
|
|
192
193
|
checkVersion: boolean;
|
|
@@ -195,7 +196,7 @@ export type MutationOperation<
|
|
|
195
196
|
| {
|
|
196
197
|
type: "create";
|
|
197
198
|
schema: TSchema;
|
|
198
|
-
namespace?: string;
|
|
199
|
+
namespace?: string | null;
|
|
199
200
|
table: TTable["name"];
|
|
200
201
|
values: TableToInsertValues<TTable>;
|
|
201
202
|
generatedExternalId: string;
|
|
@@ -203,7 +204,7 @@ export type MutationOperation<
|
|
|
203
204
|
| {
|
|
204
205
|
type: "delete";
|
|
205
206
|
schema: TSchema;
|
|
206
|
-
namespace?: string;
|
|
207
|
+
namespace?: string | null;
|
|
207
208
|
table: TTable["name"];
|
|
208
209
|
id: FragnoId | string;
|
|
209
210
|
checkVersion: boolean;
|
|
@@ -211,7 +212,7 @@ export type MutationOperation<
|
|
|
211
212
|
| {
|
|
212
213
|
type: "check";
|
|
213
214
|
schema: TSchema;
|
|
214
|
-
namespace?: string;
|
|
215
|
+
namespace?: string | null;
|
|
215
216
|
table: TTable["name"];
|
|
216
217
|
id: FragnoId;
|
|
217
218
|
};
|
|
@@ -221,6 +222,14 @@ export type MutationOperation<
|
|
|
221
222
|
*/
|
|
222
223
|
export interface CompiledMutation<TOutput> {
|
|
223
224
|
query: TOutput;
|
|
225
|
+
/**
|
|
226
|
+
* Original mutation operation for execution metadata (e.g., outbox payloads).
|
|
227
|
+
*/
|
|
228
|
+
operation?: MutationOperation<AnySchema>;
|
|
229
|
+
/**
|
|
230
|
+
* Idempotency key for the Unit of Work that produced this mutation.
|
|
231
|
+
*/
|
|
232
|
+
uowId?: string;
|
|
224
233
|
/**
|
|
225
234
|
* The type of mutation operation (create, update, delete, or check).
|
|
226
235
|
*/
|
|
@@ -262,13 +271,9 @@ export type MutationResult =
|
|
|
262
271
|
* Executor interface for Unit of Work operations
|
|
263
272
|
*/
|
|
264
273
|
export interface UOWExecutor<TOutput, TRawResult = unknown> {
|
|
265
|
-
/**
|
|
266
|
-
* Execute the retrieval phase - all queries run in a single transaction for snapshot isolation
|
|
267
|
-
*/
|
|
268
274
|
executeRetrievalPhase(retrievalBatch: TOutput[]): Promise<TRawResult[]>;
|
|
269
275
|
|
|
270
276
|
/**
|
|
271
|
-
* Execute the mutation phase - all queries run in a transaction with version checks
|
|
272
277
|
* Returns success status indicating if mutations completed without conflicts,
|
|
273
278
|
* and internal IDs for create operations (null if database doesn't support RETURNING)
|
|
274
279
|
*/
|
|
@@ -835,7 +840,7 @@ export function buildJoinIndexed<TTable extends AnyTable, TJoinOut>(
|
|
|
835
840
|
|
|
836
841
|
builder[name] = (builderFn?: (b: JoinFindBuilder<AnyTable>) => JoinFindBuilder<AnyTable>) => {
|
|
837
842
|
// Create join builder for this relation's table
|
|
838
|
-
const joinBuilder = new JoinFindBuilder(relation.table.
|
|
843
|
+
const joinBuilder = new JoinFindBuilder(relation.table.name, relation.table);
|
|
839
844
|
if (builderFn) {
|
|
840
845
|
builderFn(joinBuilder);
|
|
841
846
|
}
|
|
@@ -903,7 +908,7 @@ export interface IUnitOfWork {
|
|
|
903
908
|
// Getters (schema-agnostic)
|
|
904
909
|
readonly state: UOWState;
|
|
905
910
|
readonly name: string | undefined;
|
|
906
|
-
readonly
|
|
911
|
+
readonly idempotencyKey: string;
|
|
907
912
|
readonly retrievalPhase: Promise<unknown[]>;
|
|
908
913
|
readonly mutationPhase: Promise<void>;
|
|
909
914
|
|
|
@@ -936,7 +941,7 @@ export interface IUnitOfWork {
|
|
|
936
941
|
): TypedUnitOfWork<TOtherSchema, [], any, TOtherHooks>;
|
|
937
942
|
|
|
938
943
|
// Schema registration (for cross-fragment operations like hooks)
|
|
939
|
-
registerSchema(schema: AnySchema, namespace: string): void;
|
|
944
|
+
registerSchema(schema: AnySchema, namespace: string | null): void;
|
|
940
945
|
|
|
941
946
|
// Hook triggering (schema-agnostic, string-based hook names)
|
|
942
947
|
triggerHook(hookName: string, payload: unknown, options?: TriggerHookOptions): void;
|
|
@@ -954,11 +959,50 @@ export interface IUnitOfWork {
|
|
|
954
959
|
export interface IUnitOfWorkRestricted
|
|
955
960
|
extends Omit<IUnitOfWork, "executeRetrieve" | "executeMutations"> {}
|
|
956
961
|
|
|
962
|
+
export type UOWInstrumentationPhase =
|
|
963
|
+
| "beforeRetrieve"
|
|
964
|
+
| "afterRetrieve"
|
|
965
|
+
| "beforeMutate"
|
|
966
|
+
| "afterMutate";
|
|
967
|
+
|
|
968
|
+
export type UOWInstrumentationInjection =
|
|
969
|
+
| { type: "conflict"; reason?: string }
|
|
970
|
+
| { type: "error"; error: Error };
|
|
971
|
+
|
|
972
|
+
export type UOWInstrumentationContext = {
|
|
973
|
+
phase: UOWInstrumentationPhase;
|
|
974
|
+
uowName?: string;
|
|
975
|
+
idempotencyKey: string;
|
|
976
|
+
retrievalOpsCount: number;
|
|
977
|
+
mutationOpsCount: number;
|
|
978
|
+
uow: IUnitOfWork;
|
|
979
|
+
};
|
|
980
|
+
|
|
981
|
+
export type UOWInstrumentation = {
|
|
982
|
+
beforeRetrieve?: (
|
|
983
|
+
ctx: UOWInstrumentationContext,
|
|
984
|
+
) => void | Promise<void> | UOWInstrumentationInjection;
|
|
985
|
+
afterRetrieve?: (
|
|
986
|
+
ctx: UOWInstrumentationContext,
|
|
987
|
+
) => void | Promise<void> | UOWInstrumentationInjection;
|
|
988
|
+
beforeMutate?: (
|
|
989
|
+
ctx: UOWInstrumentationContext,
|
|
990
|
+
) => void | Promise<void> | UOWInstrumentationInjection;
|
|
991
|
+
afterMutate?: (
|
|
992
|
+
ctx: UOWInstrumentationContext,
|
|
993
|
+
) => void | Promise<void> | UOWInstrumentationInjection;
|
|
994
|
+
};
|
|
995
|
+
|
|
996
|
+
export type UOWInstrumentationFinalizer = {
|
|
997
|
+
afterRetrieve?: (ctx: UOWInstrumentationContext) => void | Promise<void>;
|
|
998
|
+
afterMutate?: (ctx: UOWInstrumentationContext) => void | Promise<void>;
|
|
999
|
+
};
|
|
1000
|
+
|
|
957
1001
|
export function createUnitOfWork(
|
|
958
1002
|
compiler: UOWCompiler<unknown>,
|
|
959
1003
|
executor: UOWExecutor<unknown, unknown>,
|
|
960
1004
|
decoder: UOWDecoder<unknown>,
|
|
961
|
-
schemaNamespaceMap?: WeakMap<AnySchema, string>,
|
|
1005
|
+
schemaNamespaceMap?: WeakMap<AnySchema, string | null>,
|
|
962
1006
|
name?: string,
|
|
963
1007
|
): UnitOfWork {
|
|
964
1008
|
return new UnitOfWork(compiler, executor, decoder, name, undefined, schemaNamespaceMap);
|
|
@@ -967,7 +1011,17 @@ export function createUnitOfWork(
|
|
|
967
1011
|
export interface UnitOfWorkConfig {
|
|
968
1012
|
dryRun?: boolean;
|
|
969
1013
|
onQuery?: (query: unknown) => void;
|
|
970
|
-
|
|
1014
|
+
idempotencyKey?: string;
|
|
1015
|
+
instrumentation?: UOWInstrumentation;
|
|
1016
|
+
instrumentationFinalizer?: UOWInstrumentationFinalizer;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
function isUowInstrumentationInjection(value: unknown): value is UOWInstrumentationInjection {
|
|
1020
|
+
if (!value || typeof value !== "object") {
|
|
1021
|
+
return false;
|
|
1022
|
+
}
|
|
1023
|
+
const injection = value as UOWInstrumentationInjection;
|
|
1024
|
+
return injection.type === "conflict" || injection.type === "error";
|
|
971
1025
|
}
|
|
972
1026
|
|
|
973
1027
|
/**
|
|
@@ -1199,7 +1253,7 @@ class UOWChildCoordinator<TRawInput> {
|
|
|
1199
1253
|
export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
|
|
1200
1254
|
#name?: string;
|
|
1201
1255
|
#config?: UnitOfWorkConfig;
|
|
1202
|
-
#
|
|
1256
|
+
#idempotencyKey: string;
|
|
1203
1257
|
|
|
1204
1258
|
#state: UOWState = "building-retrieval";
|
|
1205
1259
|
|
|
@@ -1210,7 +1264,7 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
|
|
|
1210
1264
|
#compiler: UOWCompiler<unknown>;
|
|
1211
1265
|
#executor: UOWExecutor<unknown, TRawInput>;
|
|
1212
1266
|
#decoder: UOWDecoder<TRawInput>;
|
|
1213
|
-
#schemaNamespaceMap: WeakMap<AnySchema, string>;
|
|
1267
|
+
#schemaNamespaceMap: WeakMap<AnySchema, string | null>;
|
|
1214
1268
|
|
|
1215
1269
|
#retrievalResults?: unknown[];
|
|
1216
1270
|
#createdInternalIds: (bigint | null)[] = [];
|
|
@@ -1235,7 +1289,7 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
|
|
|
1235
1289
|
decoder: UOWDecoder<TRawInput>,
|
|
1236
1290
|
name?: string,
|
|
1237
1291
|
config?: UnitOfWorkConfig,
|
|
1238
|
-
schemaNamespaceMap?: WeakMap<AnySchema, string>,
|
|
1292
|
+
schemaNamespaceMap?: WeakMap<AnySchema, string | null>,
|
|
1239
1293
|
) {
|
|
1240
1294
|
this.#compiler = compiler;
|
|
1241
1295
|
this.#executor = executor;
|
|
@@ -1243,7 +1297,62 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
|
|
|
1243
1297
|
this.#schemaNamespaceMap = schemaNamespaceMap ?? new WeakMap();
|
|
1244
1298
|
this.#name = name;
|
|
1245
1299
|
this.#config = config;
|
|
1246
|
-
this.#
|
|
1300
|
+
this.#idempotencyKey = config?.idempotencyKey ?? crypto.randomUUID();
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
#createInstrumentationContext(phase: UOWInstrumentationPhase): UOWInstrumentationContext {
|
|
1304
|
+
return {
|
|
1305
|
+
phase,
|
|
1306
|
+
uowName: this.#name,
|
|
1307
|
+
idempotencyKey: this.#idempotencyKey,
|
|
1308
|
+
retrievalOpsCount: this.#retrievalOps.length,
|
|
1309
|
+
mutationOpsCount: this.#mutationOps.length,
|
|
1310
|
+
uow: this,
|
|
1311
|
+
};
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
async #runInstrumentation(
|
|
1315
|
+
phase: UOWInstrumentationPhase,
|
|
1316
|
+
): Promise<UOWInstrumentationInjection | null> {
|
|
1317
|
+
const hook = this.#config?.instrumentation?.[phase];
|
|
1318
|
+
if (!hook) {
|
|
1319
|
+
return null;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
const result = await hook(this.#createInstrumentationContext(phase));
|
|
1323
|
+
if (isUowInstrumentationInjection(result)) {
|
|
1324
|
+
return result;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
return null;
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
async #runInstrumentationFinalizer(phase: "afterRetrieve" | "afterMutate"): Promise<void> {
|
|
1331
|
+
const hook = this.#config?.instrumentationFinalizer?.[phase];
|
|
1332
|
+
if (!hook) {
|
|
1333
|
+
return;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
await hook(this.#createInstrumentationContext(phase));
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
#handleRetrieveInjection(injection: UOWInstrumentationInjection): never {
|
|
1340
|
+
if (injection.type === "error") {
|
|
1341
|
+
throw injection.error;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
throw new Error(injection.reason ?? "Injected conflict");
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
#handleMutationInjection(injection: UOWInstrumentationInjection): { success: false } | never {
|
|
1348
|
+
if (injection.type === "error") {
|
|
1349
|
+
throw injection.error;
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
this.#state = "executed";
|
|
1353
|
+
this.#createdInternalIds.length = 0;
|
|
1354
|
+
this.#mutationPhaseDeferred.resolve();
|
|
1355
|
+
return { success: false };
|
|
1247
1356
|
}
|
|
1248
1357
|
|
|
1249
1358
|
/**
|
|
@@ -1251,7 +1360,7 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
|
|
|
1251
1360
|
* This is used for internal fragments like hooks that need to create
|
|
1252
1361
|
* records in a different schema during the same transaction.
|
|
1253
1362
|
*/
|
|
1254
|
-
registerSchema(schema: AnySchema, namespace: string): void {
|
|
1363
|
+
registerSchema(schema: AnySchema, namespace: string | null): void {
|
|
1255
1364
|
this.#schemaNamespaceMap.set(schema, namespace);
|
|
1256
1365
|
}
|
|
1257
1366
|
|
|
@@ -1293,7 +1402,7 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
|
|
|
1293
1402
|
this.#executor,
|
|
1294
1403
|
this.#decoder,
|
|
1295
1404
|
this.#name,
|
|
1296
|
-
{ ...this.#config,
|
|
1405
|
+
{ ...this.#config, idempotencyKey: this.#idempotencyKey },
|
|
1297
1406
|
this.#schemaNamespaceMap,
|
|
1298
1407
|
);
|
|
1299
1408
|
child.#coordinator.setAsRestricted(this, this.#coordinator);
|
|
@@ -1394,8 +1503,8 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
|
|
|
1394
1503
|
return this.#name;
|
|
1395
1504
|
}
|
|
1396
1505
|
|
|
1397
|
-
get
|
|
1398
|
-
return this.#
|
|
1506
|
+
get idempotencyKey(): string {
|
|
1507
|
+
return this.#idempotencyKey;
|
|
1399
1508
|
}
|
|
1400
1509
|
|
|
1401
1510
|
/**
|
|
@@ -1429,13 +1538,25 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
|
|
|
1429
1538
|
);
|
|
1430
1539
|
}
|
|
1431
1540
|
|
|
1541
|
+
let afterRan = false;
|
|
1542
|
+
let failed = false;
|
|
1432
1543
|
try {
|
|
1433
1544
|
// Wait for all children to signal readiness
|
|
1434
1545
|
await this.#coordinator.retrievalReadinessPromise;
|
|
1435
1546
|
|
|
1547
|
+
const beforeInjection = await this.#runInstrumentation("beforeRetrieve");
|
|
1548
|
+
if (beforeInjection) {
|
|
1549
|
+
return this.#handleRetrieveInjection(beforeInjection);
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1436
1552
|
if (this.#retrievalOps.length === 0) {
|
|
1437
1553
|
this.#state = "building-mutation";
|
|
1438
1554
|
const emptyResults: unknown[] = [];
|
|
1555
|
+
afterRan = true;
|
|
1556
|
+
const afterInjection = await this.#runInstrumentation("afterRetrieve");
|
|
1557
|
+
if (afterInjection) {
|
|
1558
|
+
return this.#handleRetrieveInjection(afterInjection);
|
|
1559
|
+
}
|
|
1439
1560
|
this.#retrievalPhaseDeferred.resolve(emptyResults);
|
|
1440
1561
|
return emptyResults;
|
|
1441
1562
|
}
|
|
@@ -1453,6 +1574,11 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
|
|
|
1453
1574
|
if (this.#config?.dryRun) {
|
|
1454
1575
|
this.#state = "executed";
|
|
1455
1576
|
const emptyResults: unknown[] = [];
|
|
1577
|
+
afterRan = true;
|
|
1578
|
+
const afterInjection = await this.#runInstrumentation("afterRetrieve");
|
|
1579
|
+
if (afterInjection) {
|
|
1580
|
+
return this.#handleRetrieveInjection(afterInjection);
|
|
1581
|
+
}
|
|
1456
1582
|
this.#retrievalPhaseDeferred.resolve(emptyResults);
|
|
1457
1583
|
return emptyResults;
|
|
1458
1584
|
}
|
|
@@ -1465,12 +1591,33 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
|
|
|
1465
1591
|
this.#retrievalResults = results;
|
|
1466
1592
|
this.#state = "building-mutation";
|
|
1467
1593
|
|
|
1594
|
+
afterRan = true;
|
|
1595
|
+
const afterInjection = await this.#runInstrumentation("afterRetrieve");
|
|
1596
|
+
if (afterInjection) {
|
|
1597
|
+
return this.#handleRetrieveInjection(afterInjection);
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1468
1600
|
this.#retrievalPhaseDeferred.resolve(this.#retrievalResults);
|
|
1469
1601
|
|
|
1470
1602
|
return this.#retrievalResults;
|
|
1471
1603
|
} catch (error) {
|
|
1472
1604
|
this.#retrievalError = error instanceof Error ? error : new Error(String(error));
|
|
1605
|
+
failed = true;
|
|
1473
1606
|
throw error;
|
|
1607
|
+
} finally {
|
|
1608
|
+
try {
|
|
1609
|
+
await this.#runInstrumentationFinalizer("afterRetrieve");
|
|
1610
|
+
} catch {
|
|
1611
|
+
// Ignore finalizer errors when unwinding failures.
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
if (!afterRan && failed) {
|
|
1615
|
+
try {
|
|
1616
|
+
await this.#runInstrumentation("afterRetrieve");
|
|
1617
|
+
} catch {
|
|
1618
|
+
// Ignore after-retrieve hook errors when unwinding failures.
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1474
1621
|
}
|
|
1475
1622
|
}
|
|
1476
1623
|
|
|
@@ -1487,15 +1634,23 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
|
|
|
1487
1634
|
throw new Error(`Cannot execute mutations from state ${this.#state}.`);
|
|
1488
1635
|
}
|
|
1489
1636
|
|
|
1637
|
+
let afterRan = false;
|
|
1638
|
+
let failed = false;
|
|
1490
1639
|
try {
|
|
1491
1640
|
// Wait for all children to signal readiness
|
|
1492
1641
|
await this.#coordinator.mutationReadinessPromise;
|
|
1493
1642
|
|
|
1643
|
+
const beforeInjection = await this.#runInstrumentation("beforeMutate");
|
|
1644
|
+
if (beforeInjection) {
|
|
1645
|
+
return this.#handleMutationInjection(beforeInjection);
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1494
1648
|
// Compile mutation operations using single compiler
|
|
1495
1649
|
const mutationBatch: CompiledMutation<unknown>[] = [];
|
|
1496
1650
|
for (const op of this.#mutationOps) {
|
|
1497
1651
|
const compiled = this.#compiler.compileMutationOperation(op);
|
|
1498
1652
|
if (compiled !== null) {
|
|
1653
|
+
compiled.uowId = this.#idempotencyKey;
|
|
1499
1654
|
this.#config?.onQuery?.(compiled);
|
|
1500
1655
|
mutationBatch.push(compiled);
|
|
1501
1656
|
}
|
|
@@ -1503,6 +1658,11 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
|
|
|
1503
1658
|
|
|
1504
1659
|
if (this.#config?.dryRun) {
|
|
1505
1660
|
this.#state = "executed";
|
|
1661
|
+
afterRan = true;
|
|
1662
|
+
const afterInjection = await this.#runInstrumentation("afterMutate");
|
|
1663
|
+
if (afterInjection) {
|
|
1664
|
+
return this.#handleMutationInjection(afterInjection);
|
|
1665
|
+
}
|
|
1506
1666
|
this.#mutationPhaseDeferred.resolve();
|
|
1507
1667
|
return {
|
|
1508
1668
|
success: true,
|
|
@@ -1519,6 +1679,12 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
|
|
|
1519
1679
|
this.#createdInternalIds.push(...result.createdInternalIds);
|
|
1520
1680
|
}
|
|
1521
1681
|
|
|
1682
|
+
afterRan = true;
|
|
1683
|
+
const afterInjection = await this.#runInstrumentation("afterMutate");
|
|
1684
|
+
if (afterInjection) {
|
|
1685
|
+
return this.#handleMutationInjection(afterInjection);
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1522
1688
|
// Resolve the mutation phase promise to unblock waiting service methods
|
|
1523
1689
|
this.#mutationPhaseDeferred.resolve();
|
|
1524
1690
|
|
|
@@ -1527,7 +1693,22 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
|
|
|
1527
1693
|
};
|
|
1528
1694
|
} catch (error) {
|
|
1529
1695
|
this.#mutationError = error instanceof Error ? error : new Error(String(error));
|
|
1696
|
+
failed = true;
|
|
1530
1697
|
throw error;
|
|
1698
|
+
} finally {
|
|
1699
|
+
try {
|
|
1700
|
+
await this.#runInstrumentationFinalizer("afterMutate");
|
|
1701
|
+
} catch {
|
|
1702
|
+
// Ignore finalizer errors when unwinding failures.
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
if (!afterRan && failed) {
|
|
1706
|
+
try {
|
|
1707
|
+
await this.#runInstrumentation("afterMutate");
|
|
1708
|
+
} catch {
|
|
1709
|
+
// Ignore after-mutate hook errors when unwinding failures.
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1531
1712
|
}
|
|
1532
1713
|
}
|
|
1533
1714
|
|
|
@@ -1626,6 +1807,7 @@ export class UnitOfWork<const TRawInput = unknown> implements IUnitOfWork {
|
|
|
1626
1807
|
for (const op of this.#mutationOps) {
|
|
1627
1808
|
const compiled = compiler.compileMutationOperation(op);
|
|
1628
1809
|
if (compiled !== null) {
|
|
1810
|
+
compiled.uowId = this.#idempotencyKey;
|
|
1629
1811
|
mutationBatch.push(compiled);
|
|
1630
1812
|
}
|
|
1631
1813
|
}
|
|
@@ -1651,12 +1833,12 @@ export class TypedUnitOfWork<
|
|
|
1651
1833
|
> implements IUnitOfWork
|
|
1652
1834
|
{
|
|
1653
1835
|
#schema: TSchema;
|
|
1654
|
-
#namespace?: string;
|
|
1836
|
+
#namespace?: string | null;
|
|
1655
1837
|
#uow: UnitOfWork<TRawInput>;
|
|
1656
1838
|
#operationIndices: number[] = [];
|
|
1657
1839
|
#cachedRetrievalPhase?: Promise<TRetrievalResults>;
|
|
1658
1840
|
|
|
1659
|
-
constructor(schema: TSchema, namespace: string | undefined, uow: UnitOfWork<TRawInput>) {
|
|
1841
|
+
constructor(schema: TSchema, namespace: string | null | undefined, uow: UnitOfWork<TRawInput>) {
|
|
1660
1842
|
this.#schema = schema;
|
|
1661
1843
|
this.#namespace = namespace;
|
|
1662
1844
|
this.#uow = uow;
|
|
@@ -1674,8 +1856,8 @@ export class TypedUnitOfWork<
|
|
|
1674
1856
|
return this.#uow.name;
|
|
1675
1857
|
}
|
|
1676
1858
|
|
|
1677
|
-
get
|
|
1678
|
-
return this.#uow.
|
|
1859
|
+
get idempotencyKey(): string {
|
|
1860
|
+
return this.#uow.idempotencyKey;
|
|
1679
1861
|
}
|
|
1680
1862
|
|
|
1681
1863
|
get state() {
|
|
@@ -1749,7 +1931,7 @@ export class TypedUnitOfWork<
|
|
|
1749
1931
|
return this.#uow.forSchema<TOtherSchema, TOtherHooks>(schema, hooks);
|
|
1750
1932
|
}
|
|
1751
1933
|
|
|
1752
|
-
registerSchema(schema: AnySchema, namespace: string): void {
|
|
1934
|
+
registerSchema(schema: AnySchema, namespace: string | null): void {
|
|
1753
1935
|
this.#uow.registerSchema(schema, namespace);
|
|
1754
1936
|
}
|
|
1755
1937
|
|
|
@@ -1962,6 +2144,22 @@ export class TypedUnitOfWork<
|
|
|
1962
2144
|
return this as any;
|
|
1963
2145
|
}
|
|
1964
2146
|
|
|
2147
|
+
/**
|
|
2148
|
+
* Generate a new ID for a table without creating a record.
|
|
2149
|
+
* This is useful when you need to reference an ID before actually creating the record,
|
|
2150
|
+
* or when you need to pass the ID to external services.
|
|
2151
|
+
*
|
|
2152
|
+
* @example
|
|
2153
|
+
* ```ts
|
|
2154
|
+
* const userId = uow.generateId("users");
|
|
2155
|
+
* // Use userId in related records or pass to external services
|
|
2156
|
+
* uow.create("users", { id: userId, name: "John" });
|
|
2157
|
+
* ```
|
|
2158
|
+
*/
|
|
2159
|
+
generateId<TableName extends keyof TSchema["tables"] & string>(tableName: TableName): FragnoId {
|
|
2160
|
+
return generateId(this.#schema, tableName);
|
|
2161
|
+
}
|
|
2162
|
+
|
|
1965
2163
|
create<TableName extends keyof TSchema["tables"] & string>(
|
|
1966
2164
|
tableName: TableName,
|
|
1967
2165
|
values: TableToInsertValues<TSchema["tables"][TableName]>,
|
|
@@ -1976,7 +2174,7 @@ export class TypedUnitOfWork<
|
|
|
1976
2174
|
let updatedValues = values;
|
|
1977
2175
|
|
|
1978
2176
|
// Check if ID value is provided in values
|
|
1979
|
-
const providedIdValue = (values as Record<string, unknown>)[idColumn.
|
|
2177
|
+
const providedIdValue = (values as Record<string, unknown>)[idColumn.name];
|
|
1980
2178
|
|
|
1981
2179
|
if (providedIdValue !== undefined) {
|
|
1982
2180
|
// Extract string from FragnoId or use string directly
|
|
@@ -1994,7 +2192,7 @@ export class TypedUnitOfWork<
|
|
|
1994
2192
|
const generated = idColumn.generateDefaultValue();
|
|
1995
2193
|
if (generated === undefined) {
|
|
1996
2194
|
throw new Error(
|
|
1997
|
-
`No ID value provided and ID column ${idColumn.
|
|
2195
|
+
`No ID value provided and ID column ${idColumn.name} has no default generator`,
|
|
1998
2196
|
);
|
|
1999
2197
|
}
|
|
2000
2198
|
externalId = generated as string;
|
|
@@ -2002,7 +2200,7 @@ export class TypedUnitOfWork<
|
|
|
2002
2200
|
// Add the generated ID to values so it's used in the insert
|
|
2003
2201
|
updatedValues = {
|
|
2004
2202
|
...values,
|
|
2005
|
-
[idColumn.
|
|
2203
|
+
[idColumn.name]: externalId,
|
|
2006
2204
|
} as TableToInsertValues<TSchema["tables"][TableName]>;
|
|
2007
2205
|
}
|
|
2008
2206
|
|
|
@@ -4,11 +4,12 @@ import { decodeResult } from "./value-decoding";
|
|
|
4
4
|
import {
|
|
5
5
|
SQLocalDriverConfig,
|
|
6
6
|
NodePostgresDriverConfig,
|
|
7
|
+
PGLiteDriverConfig,
|
|
7
8
|
MySQL2DriverConfig,
|
|
8
9
|
} from "../adapters/generic-sql/driver-config";
|
|
9
10
|
|
|
10
11
|
describe("decodeResult", () => {
|
|
11
|
-
const testSchema = schema((s) => {
|
|
12
|
+
const testSchema = schema("test", (s) => {
|
|
12
13
|
return s
|
|
13
14
|
.addTable("users", (t) => {
|
|
14
15
|
return t
|
|
@@ -40,6 +41,7 @@ describe("decodeResult", () => {
|
|
|
40
41
|
|
|
41
42
|
const sqliteConfig = new SQLocalDriverConfig();
|
|
42
43
|
const postgresqlConfig = new NodePostgresDriverConfig();
|
|
44
|
+
const pgliteConfig = new PGLiteDriverConfig();
|
|
43
45
|
const mysqlConfig = new MySQL2DriverConfig();
|
|
44
46
|
|
|
45
47
|
describe("basic decoding", () => {
|
|
@@ -105,6 +107,15 @@ describe("decodeResult", () => {
|
|
|
105
107
|
|
|
106
108
|
expect(result["createdAt"]).toBe(date);
|
|
107
109
|
});
|
|
110
|
+
|
|
111
|
+
it("should normalize Date values from pglite timestamp parsing", () => {
|
|
112
|
+
const localDate = new Date("2024-01-15T10:30:00");
|
|
113
|
+
const expected = new Date(localDate.getTime() - localDate.getTimezoneOffset() * 60_000);
|
|
114
|
+
const result = decodeResult({ createdAt: localDate }, usersTable, pgliteConfig);
|
|
115
|
+
|
|
116
|
+
assert.instanceOf(result["createdAt"], Date);
|
|
117
|
+
expect((result["createdAt"] as Date).toISOString()).toBe(expected.toISOString());
|
|
118
|
+
});
|
|
108
119
|
});
|
|
109
120
|
|
|
110
121
|
describe("nullable columns", () => {
|
|
@@ -206,7 +217,7 @@ describe("decodeResult", () => {
|
|
|
206
217
|
});
|
|
207
218
|
|
|
208
219
|
it("should handle multiple relations in same result", () => {
|
|
209
|
-
const schemaWithMultipleRelations = schema((s) => {
|
|
220
|
+
const schemaWithMultipleRelations = schema("schemawithmultiplerelations", (s) => {
|
|
210
221
|
return s
|
|
211
222
|
.addTable("users", (t) => {
|
|
212
223
|
return t.addColumn("id", idColumn()).addColumn("name", column("string"));
|
|
@@ -2,6 +2,8 @@ import type { AnyTable } from "../schema/create";
|
|
|
2
2
|
import { createSQLSerializer } from "./serialize/create-sql-serializer";
|
|
3
3
|
import { FragnoId, FragnoReference } from "../schema/create";
|
|
4
4
|
import type { DriverConfig } from "../adapters/generic-sql/driver-config";
|
|
5
|
+
import type { SQLiteStorageMode } from "../adapters/generic-sql/sqlite-storage";
|
|
6
|
+
import type { NamingResolver } from "../naming/sql-naming";
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* Decodes a database result record to application format.
|
|
@@ -15,6 +17,7 @@ import type { DriverConfig } from "../adapters/generic-sql/driver-config";
|
|
|
15
17
|
* @param result - The raw database result record
|
|
16
18
|
* @param table - The table schema definition containing column and relation information
|
|
17
19
|
* @param driverConfig - The driver configuration containing database type information
|
|
20
|
+
* @param sqliteStorageMode - Optional SQLite storage mode override
|
|
18
21
|
* @returns A record in application format with deserialized values
|
|
19
22
|
*
|
|
20
23
|
* @example
|
|
@@ -31,11 +34,14 @@ export function decodeResult(
|
|
|
31
34
|
result: Record<string, unknown>,
|
|
32
35
|
table: AnyTable,
|
|
33
36
|
driverConfig: DriverConfig,
|
|
37
|
+
sqliteStorageMode?: SQLiteStorageMode,
|
|
38
|
+
resolver?: NamingResolver,
|
|
34
39
|
): Record<string, unknown> {
|
|
35
|
-
const serializer = createSQLSerializer(driverConfig);
|
|
40
|
+
const serializer = createSQLSerializer(driverConfig, sqliteStorageMode);
|
|
36
41
|
const output: Record<string, unknown> = {};
|
|
37
42
|
// First pass: collect all column values
|
|
38
43
|
const columnValues: Record<string, unknown> = {};
|
|
44
|
+
const columnMap = resolver ? resolver.getColumnNameMap(table) : undefined;
|
|
39
45
|
|
|
40
46
|
// Collect all relation data (including nested) keyed by relation name
|
|
41
47
|
const relationData: Record<string, Record<string, unknown>> = {};
|
|
@@ -46,13 +52,14 @@ export function decodeResult(
|
|
|
46
52
|
|
|
47
53
|
// Direct column (no colon)
|
|
48
54
|
if (colonIndex === -1) {
|
|
49
|
-
const
|
|
55
|
+
const logicalName = columnMap?.[k] ?? k;
|
|
56
|
+
const col = table.columns[logicalName];
|
|
50
57
|
if (!col) {
|
|
51
58
|
continue;
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
// Store all column values (including hidden ones for FragnoId creation)
|
|
55
|
-
columnValues[
|
|
62
|
+
columnValues[logicalName] = serializer.deserialize(value, col);
|
|
56
63
|
continue;
|
|
57
64
|
}
|
|
58
65
|
|
|
@@ -78,7 +85,13 @@ export function decodeResult(
|
|
|
78
85
|
}
|
|
79
86
|
|
|
80
87
|
// Recursively decode the relation data
|
|
81
|
-
output[relationName] = decodeResult(
|
|
88
|
+
output[relationName] = decodeResult(
|
|
89
|
+
relationData[relationName],
|
|
90
|
+
relation.table,
|
|
91
|
+
driverConfig,
|
|
92
|
+
sqliteStorageMode,
|
|
93
|
+
resolver,
|
|
94
|
+
);
|
|
82
95
|
}
|
|
83
96
|
|
|
84
97
|
// Second pass: create output with FragnoId objects where appropriate
|