@fragno-dev/db 0.3.0 → 0.4.1
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 +327 -160
- package/CHANGELOG.md +74 -0
- package/README.md +24 -0
- package/dist/adapters/adapters.d.ts +1 -1
- package/dist/adapters/adapters.d.ts.map +1 -1
- package/dist/adapters/adapters.js.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-adapter.d.ts +0 -3
- package/dist/adapters/generic-sql/generic-sql-adapter.d.ts.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-adapter.js +11 -12
- package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-uow-executor.js +46 -6
- package/dist/adapters/generic-sql/generic-sql-uow-executor.js.map +1 -1
- package/dist/adapters/generic-sql/migration/cold-kysely.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/mysql.js +1 -1
- package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/postgres.js +1 -1
- package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/sqlite.js +185 -19
- package/dist/adapters/generic-sql/migration/dialect/sqlite.js.map +1 -1
- package/dist/adapters/generic-sql/migration/executor.d.ts.map +1 -1
- package/dist/adapters/generic-sql/migration/executor.js +30 -3
- package/dist/adapters/generic-sql/migration/executor.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 +3 -3
- package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -1
- package/dist/adapters/generic-sql/migration/sql-generator.js +1 -1
- package/dist/adapters/generic-sql/migration/sql-generator.js.map +1 -1
- package/dist/adapters/generic-sql/query/create-sql-query-compiler.js +1 -1
- package/dist/adapters/generic-sql/query/create-sql-query-compiler.js.map +1 -1
- package/dist/adapters/generic-sql/query/cursor-utils.js.map +1 -1
- package/dist/adapters/generic-sql/query/db-now-sql.js +27 -0
- package/dist/adapters/generic-sql/query/db-now-sql.js.map +1 -0
- package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js +9 -6
- package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js.map +1 -1
- package/dist/adapters/generic-sql/query/select-builder.js.map +1 -1
- package/dist/adapters/generic-sql/query/sql-query-compiler.js +37 -9
- package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -1
- package/dist/adapters/generic-sql/query/where-builder.js +24 -20
- package/dist/adapters/generic-sql/query/where-builder.js.map +1 -1
- package/dist/adapters/generic-sql/uow-decoder.js +1 -1
- package/dist/adapters/generic-sql/uow-decoder.js.map +1 -1
- package/dist/adapters/generic-sql/uow-encoder.js +8 -9
- package/dist/adapters/generic-sql/uow-encoder.js.map +1 -1
- package/dist/adapters/in-memory/condition-evaluator.js +10 -6
- package/dist/adapters/in-memory/condition-evaluator.js.map +1 -1
- package/dist/adapters/in-memory/in-memory-adapter.d.ts.map +1 -1
- package/dist/adapters/in-memory/in-memory-adapter.js +45 -25
- package/dist/adapters/in-memory/in-memory-adapter.js.map +1 -1
- package/dist/adapters/in-memory/in-memory-uow.js +236 -13
- package/dist/adapters/in-memory/in-memory-uow.js.map +1 -1
- package/dist/adapters/in-memory/options.d.ts +2 -0
- package/dist/adapters/in-memory/options.d.ts.map +1 -1
- package/dist/adapters/in-memory/options.js +3 -2
- package/dist/adapters/in-memory/options.js.map +1 -1
- package/dist/adapters/in-memory/reference-resolution.js.map +1 -1
- package/dist/adapters/in-memory/store.js +1 -1
- package/dist/adapters/in-memory/store.js.map +1 -1
- package/dist/adapters/shared/from-unit-of-work-compiler.js +51 -24
- package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -1
- package/dist/adapters/shared/uow-operation-compiler.js.map +1 -1
- package/dist/browser/adapters/adapters.d.ts +61 -0
- package/dist/browser/adapters/adapters.d.ts.map +1 -0
- package/dist/browser/adapters/generic-sql/migration/executor.d.ts +15 -0
- package/dist/browser/adapters/generic-sql/migration/executor.d.ts.map +1 -0
- package/dist/browser/adapters/generic-sql/migration/prepared-migrations.d.ts +66 -0
- package/dist/browser/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -0
- package/dist/browser/adapters/generic-sql/sqlite-storage.d.ts +11 -0
- package/dist/browser/adapters/generic-sql/sqlite-storage.d.ts.map +1 -0
- package/dist/browser/adapters/in-memory/in-memory-adapter.d.ts +5 -0
- package/dist/browser/adapters/in-memory/index.d.ts +2 -0
- package/dist/browser/adapters/in-memory/options.d.ts +1 -0
- package/dist/browser/db-fragment-definition-builder.d.ts +237 -0
- package/dist/browser/db-fragment-definition-builder.d.ts.map +1 -0
- package/dist/browser/durable-hooks.d.ts +3 -0
- package/dist/browser/fragments/internal-fragment.d.ts +317 -0
- package/dist/browser/fragments/internal-fragment.d.ts.map +1 -0
- package/dist/browser/fragments/internal-fragment.schema.d.ts +1 -0
- package/dist/browser/hooks/durable-hooks-logger.d.ts +10 -0
- package/dist/browser/hooks/durable-hooks-logger.d.ts.map +1 -0
- package/dist/browser/hooks/hooks.d.ts +146 -0
- package/dist/browser/hooks/hooks.d.ts.map +1 -0
- package/dist/browser/id.js +1 -0
- package/dist/browser/internal/adapter-registry.d.ts +4 -0
- package/dist/browser/internal/outbox-state.d.ts +2 -0
- package/dist/browser/mod.d.ts +15 -0
- package/dist/browser/mod.d.ts.map +1 -0
- package/dist/browser/mod.js +17 -0
- package/dist/browser/mod.js.map +1 -0
- package/dist/browser/mod2.d.ts +48 -0
- package/dist/browser/mod2.d.ts.map +1 -0
- package/dist/browser/naming/sql-naming.d.ts +19 -0
- package/dist/browser/naming/sql-naming.d.ts.map +1 -0
- package/dist/browser/outbox/outbox.d.ts +21 -0
- package/dist/browser/outbox/outbox.d.ts.map +1 -0
- package/dist/browser/query/column-defaults.js +1 -0
- package/dist/browser/query/condition-builder.d.ts +44 -0
- package/dist/browser/query/condition-builder.d.ts.map +1 -0
- package/dist/browser/query/condition-builder.js +97 -0
- package/dist/browser/query/condition-builder.js.map +1 -0
- package/dist/browser/query/cursor.d.ts +105 -0
- package/dist/browser/query/cursor.d.ts.map +1 -0
- package/dist/browser/query/cursor.js +150 -0
- package/dist/browser/query/cursor.js.map +1 -0
- package/dist/browser/query/db-now.d.ts +22 -0
- package/dist/browser/query/db-now.d.ts.map +1 -0
- package/dist/browser/query/db-now.js +33 -0
- package/dist/browser/query/db-now.js.map +1 -0
- package/dist/browser/query/orm/orm.d.ts +18 -0
- package/dist/browser/query/orm/orm.d.ts.map +1 -0
- package/dist/browser/query/simple-query-interface.d.ts +108 -0
- package/dist/browser/query/simple-query-interface.d.ts.map +1 -0
- package/dist/browser/query/unit-of-work/execute-unit-of-work.d.ts +423 -0
- package/dist/browser/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -0
- package/dist/browser/query/unit-of-work/execute-unit-of-work.js +507 -0
- package/dist/browser/query/unit-of-work/execute-unit-of-work.js.map +1 -0
- package/dist/browser/query/unit-of-work/retry-policy.d.ts +23 -0
- package/dist/browser/query/unit-of-work/retry-policy.d.ts.map +1 -0
- package/dist/browser/query/unit-of-work/retry-policy.js +40 -0
- package/dist/browser/query/unit-of-work/retry-policy.js.map +1 -0
- package/dist/browser/query/unit-of-work/unit-of-work.d.ts +703 -0
- package/dist/browser/query/unit-of-work/unit-of-work.d.ts.map +1 -0
- package/dist/browser/query/unit-of-work/unit-of-work.js +1206 -0
- package/dist/browser/query/unit-of-work/unit-of-work.js.map +1 -0
- package/dist/browser/query/value-encoding.js +38 -0
- package/dist/browser/query/value-encoding.js.map +1 -0
- package/dist/browser/schema/create.d.ts +326 -0
- package/dist/browser/schema/create.d.ts.map +1 -0
- package/dist/browser/schema/create.js +89 -0
- package/dist/browser/schema/create.js.map +1 -0
- package/dist/browser/schema/generate-id.js +28 -0
- package/dist/browser/schema/generate-id.js.map +1 -0
- package/dist/browser/shared/providers.d.ts +6 -0
- package/dist/browser/shared/providers.d.ts.map +1 -0
- package/dist/browser/sql-driver/connection/connection-provider.d.ts +13 -0
- package/dist/browser/sql-driver/connection/connection-provider.d.ts.map +1 -0
- package/dist/browser/sql-driver/dialect-adapter/dialect-adapter.d.ts +7 -0
- package/dist/browser/sql-driver/dialect-adapter/dialect-adapter.d.ts.map +1 -0
- package/dist/browser/sql-driver/driver/runtime-driver.d.ts +23 -0
- package/dist/browser/sql-driver/driver/runtime-driver.d.ts.map +1 -0
- package/dist/browser/sql-driver/query-executor/plugin.d.ts +17 -0
- package/dist/browser/sql-driver/query-executor/plugin.d.ts.map +1 -0
- package/dist/browser/sql-driver/query-executor/query-executor.d.ts +36 -0
- package/dist/browser/sql-driver/query-executor/query-executor.d.ts.map +1 -0
- package/dist/browser/sql-driver/sql-driver-adapter.d.ts +29 -0
- package/dist/browser/sql-driver/sql-driver-adapter.d.ts.map +1 -0
- package/dist/browser/sql-driver/sql-driver.d.ts +38 -0
- package/dist/browser/sql-driver/sql-driver.d.ts.map +1 -0
- package/dist/browser/sync/commands.d.ts +15 -0
- package/dist/browser/sync/commands.d.ts.map +1 -0
- package/dist/browser/sync/commands.js +27 -0
- package/dist/browser/sync/commands.js.map +1 -0
- package/dist/browser/sync/types.d.ts +63 -0
- package/dist/browser/sync/types.d.ts.map +1 -0
- package/dist/browser/util/types.d.ts +8 -0
- package/dist/browser/util/types.d.ts.map +1 -0
- package/dist/browser/with-database.d.ts +29 -0
- package/dist/browser/with-database.d.ts.map +1 -0
- package/dist/client.d.ts +4 -0
- package/dist/client.js +5 -0
- package/dist/db-fragment-definition-builder.d.ts +85 -28
- package/dist/db-fragment-definition-builder.d.ts.map +1 -1
- package/dist/db-fragment-definition-builder.js +374 -46
- package/dist/db-fragment-definition-builder.js.map +1 -1
- package/dist/dispatchers/cloudflare-do/dispatcher.d.ts +20 -0
- package/dist/dispatchers/cloudflare-do/dispatcher.d.ts.map +1 -0
- package/dist/dispatchers/cloudflare-do/dispatcher.js +147 -0
- package/dist/dispatchers/cloudflare-do/dispatcher.js.map +1 -0
- package/dist/dispatchers/cloudflare-do/index.d.ts +5 -20
- package/dist/dispatchers/cloudflare-do/index.d.ts.map +1 -1
- package/dist/dispatchers/cloudflare-do/index.js +23 -55
- package/dist/dispatchers/cloudflare-do/index.js.map +1 -1
- package/dist/dispatchers/node/dispatcher.d.ts +14 -0
- package/dist/dispatchers/node/dispatcher.d.ts.map +1 -0
- package/dist/dispatchers/node/dispatcher.js +80 -0
- package/dist/dispatchers/node/dispatcher.js.map +1 -0
- package/dist/dispatchers/node/index.d.ts +5 -10
- package/dist/dispatchers/node/index.d.ts.map +1 -1
- package/dist/dispatchers/node/index.js +21 -53
- package/dist/dispatchers/node/index.js.map +1 -1
- package/dist/durable-hooks.d.ts +31 -0
- package/dist/durable-hooks.d.ts.map +1 -0
- package/dist/durable-hooks.js +23 -0
- package/dist/durable-hooks.js.map +1 -0
- package/dist/fragments/internal-fragment.d.ts +128 -27
- package/dist/fragments/internal-fragment.d.ts.map +1 -1
- package/dist/fragments/internal-fragment.js +125 -78
- package/dist/fragments/internal-fragment.js.map +1 -1
- package/dist/fragments/internal-fragment.routes.js +138 -3
- package/dist/fragments/internal-fragment.routes.js.map +1 -1
- package/dist/fragments/internal-fragment.schema.d.ts +7 -1
- package/dist/fragments/internal-fragment.schema.d.ts.map +1 -1
- package/dist/fragments/internal-fragment.schema.js +18 -1
- package/dist/fragments/internal-fragment.schema.js.map +1 -1
- package/dist/hooks/durable-hooks-logger.d.ts +10 -0
- package/dist/hooks/durable-hooks-logger.d.ts.map +1 -0
- package/dist/hooks/durable-hooks-logger.js +75 -0
- package/dist/hooks/durable-hooks-logger.js.map +1 -0
- package/dist/hooks/durable-hooks-processor.d.ts +1 -14
- package/dist/hooks/durable-hooks-processor.js +58 -10
- package/dist/hooks/durable-hooks-processor.js.map +1 -1
- package/dist/hooks/durable-hooks-runtime.js +44 -0
- package/dist/hooks/durable-hooks-runtime.js.map +1 -0
- package/dist/hooks/hooks.d.ts +60 -2
- package/dist/hooks/hooks.d.ts.map +1 -1
- package/dist/hooks/hooks.js +214 -53
- package/dist/hooks/hooks.js.map +1 -1
- package/dist/id.d.ts +2 -2
- package/dist/id.js +2 -2
- package/dist/internal/adapter-registry.d.ts +11 -0
- package/dist/internal/adapter-registry.d.ts.map +1 -0
- package/dist/internal/adapter-registry.js +135 -0
- package/dist/internal/adapter-registry.js.map +1 -0
- package/dist/internal/outbox-state.d.ts +2 -0
- package/dist/internal/outbox-state.js +26 -0
- package/dist/internal/outbox-state.js.map +1 -0
- package/dist/migration-engine/auto-from-schema.d.ts +33 -0
- package/dist/migration-engine/auto-from-schema.d.ts.map +1 -0
- package/dist/migration-engine/auto-from-schema.js +210 -27
- package/dist/migration-engine/auto-from-schema.js.map +1 -1
- package/dist/migration-engine/generation-engine.d.ts.map +1 -1
- package/dist/migration-engine/generation-engine.js +17 -5
- package/dist/migration-engine/generation-engine.js.map +1 -1
- package/dist/migration-engine/shared.d.ts +113 -0
- package/dist/migration-engine/shared.d.ts.map +1 -0
- package/dist/migration-engine/shared.js.map +1 -1
- package/dist/mod.d.ts +12 -11
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +10 -10
- package/dist/mod.js.map +1 -1
- package/dist/naming/sql-naming.d.ts.map +1 -1
- package/dist/naming/sql-naming.js.map +1 -1
- package/dist/outbox/outbox-builder.js.map +1 -1
- package/dist/outbox/outbox.d.ts +3 -1
- package/dist/outbox/outbox.d.ts.map +1 -1
- package/dist/outbox/outbox.js.map +1 -1
- package/dist/query/column-defaults.js.map +1 -1
- package/dist/query/condition-builder.d.ts +7 -1
- package/dist/query/condition-builder.d.ts.map +1 -1
- package/dist/query/condition-builder.js +5 -1
- package/dist/query/condition-builder.js.map +1 -1
- package/dist/query/cursor-client.d.ts +105 -0
- package/dist/query/cursor-client.d.ts.map +1 -0
- package/dist/query/cursor-client.js +165 -0
- package/dist/query/cursor-client.js.map +1 -0
- package/dist/query/cursor.d.ts.map +1 -1
- package/dist/query/cursor.js +7 -1
- package/dist/query/cursor.js.map +1 -1
- package/dist/query/db-now.d.ts +15 -1
- package/dist/query/db-now.d.ts.map +1 -1
- package/dist/query/db-now.js +30 -2
- package/dist/query/db-now.js.map +1 -1
- package/dist/query/orm/orm.js.map +1 -1
- package/dist/query/serialize/create-sql-serializer.js +2 -2
- package/dist/query/serialize/create-sql-serializer.js.map +1 -1
- package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -1
- package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -1
- package/dist/query/serialize/dialect/sqlite-serializer.js +6 -2
- package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -1
- package/dist/query/simple-query-interface.d.ts +7 -3
- package/dist/query/simple-query-interface.d.ts.map +1 -1
- package/dist/query/unit-of-work/execute-unit-of-work.d.ts +37 -2
- 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 +39 -18
- 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 +42 -16
- package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work/unit-of-work.js +50 -6
- package/dist/query/unit-of-work/unit-of-work.js.map +1 -1
- package/dist/query/value-decoding.js +8 -1
- package/dist/query/value-decoding.js.map +1 -1
- package/dist/query/value-encoding.js.map +1 -1
- package/dist/schema/create.d.ts +69 -25
- package/dist/schema/create.d.ts.map +1 -1
- package/dist/schema/create.js +91 -16
- package/dist/schema/create.js.map +1 -1
- package/dist/schema/type-conversion/create-sql-type-mapper.js +1 -1
- package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -1
- package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -1
- package/dist/schema/validator.d.ts.map +1 -1
- package/dist/schema/validator.js.map +1 -1
- package/dist/schema-output/drizzle.d.ts.map +1 -1
- package/dist/schema-output/drizzle.js +8 -6
- package/dist/schema-output/drizzle.js.map +1 -1
- package/dist/schema-output/prisma.d.ts.map +1 -1
- package/dist/schema-output/prisma.js +21 -10
- package/dist/schema-output/prisma.js.map +1 -1
- package/dist/sql-driver/dialects/durable-object-dialect.js +3 -9
- package/dist/sql-driver/dialects/durable-object-dialect.js.map +1 -1
- package/dist/sql-driver/query-executor/default-query-executor.js.map +1 -1
- package/dist/sql-driver/query-executor/query-executor-base.js.map +1 -1
- package/dist/sql-driver/sql-driver-adapter.js.map +1 -1
- package/dist/sql-driver/sql.js.map +1 -1
- package/dist/sync/commands.d.ts +15 -0
- package/dist/sync/commands.d.ts.map +1 -0
- package/dist/sync/commands.js +27 -0
- package/dist/sync/commands.js.map +1 -0
- package/dist/sync/index.d.ts +4 -0
- package/dist/sync/index.js +4 -0
- package/dist/sync/read-tracking.d.ts +25 -0
- package/dist/sync/read-tracking.d.ts.map +1 -0
- package/dist/sync/read-tracking.js +148 -0
- package/dist/sync/read-tracking.js.map +1 -0
- package/dist/sync/submit.js +213 -0
- package/dist/sync/submit.js.map +1 -0
- package/dist/sync/types.d.ts +63 -0
- package/dist/sync/types.d.ts.map +1 -0
- package/dist/util/default-database-adapter.js +6 -1
- package/dist/util/default-database-adapter.js.map +1 -1
- package/dist/with-database.d.ts +3 -6
- package/dist/with-database.d.ts.map +1 -1
- package/dist/with-database.js +7 -15
- package/dist/with-database.js.map +1 -1
- package/package.json +33 -41
- package/src/adapters/adapters.ts +5 -4
- package/src/adapters/drizzle/migrate-drizzle.test.ts +46 -9
- package/src/adapters/drizzle/migration-parity-drizzle-kit.test.ts +5 -3
- package/src/adapters/drizzle/test-utils.ts +2 -1
- package/src/adapters/generic-sql/generic-sql-adapter.test.ts +5 -3
- package/src/adapters/generic-sql/generic-sql-adapter.ts +21 -24
- package/src/adapters/generic-sql/generic-sql-uow-executor.test.ts +1 -0
- package/src/adapters/generic-sql/generic-sql-uow-executor.ts +81 -15
- package/src/adapters/generic-sql/migration/adapter-migration-parity.test.ts +4 -2
- package/src/adapters/generic-sql/migration/cold-kysely.ts +1 -0
- package/src/adapters/generic-sql/migration/dialect/mysql.test.ts +3 -2
- package/src/adapters/generic-sql/migration/dialect/mysql.ts +1 -0
- package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +5 -4
- package/src/adapters/generic-sql/migration/dialect/postgres.ts +2 -1
- package/src/adapters/generic-sql/migration/dialect/sqlite.test.ts +795 -3
- package/src/adapters/generic-sql/migration/dialect/sqlite.ts +385 -57
- package/src/adapters/generic-sql/migration/executor.test.ts +52 -0
- package/src/adapters/generic-sql/migration/executor.ts +47 -4
- package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +117 -14
- package/src/adapters/generic-sql/migration/prepared-migrations.ts +9 -8
- package/src/adapters/generic-sql/migration/sql-generator.ts +5 -3
- package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +3 -3
- package/src/adapters/generic-sql/query/cursor-utils.test.ts +3 -2
- package/src/adapters/generic-sql/query/cursor-utils.ts +1 -1
- package/src/adapters/generic-sql/query/db-now-sql.ts +49 -0
- package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +144 -8
- package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +16 -17
- package/src/adapters/generic-sql/query/select-builder.test.ts +1 -0
- package/src/adapters/generic-sql/query/select-builder.ts +2 -2
- package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +24 -5
- package/src/adapters/generic-sql/query/sql-query-compiler.ts +83 -13
- package/src/adapters/generic-sql/query/where-builder.test.ts +7 -5
- package/src/adapters/generic-sql/query/where-builder.ts +48 -29
- package/src/adapters/generic-sql/sql-adapter-pglite-migrations.test.ts +6 -15
- package/src/adapters/generic-sql/sql-adapter-pglite-pagination.test.ts +52 -7
- package/src/adapters/generic-sql/sql-adapter-pglite-queries.test.ts +9 -6
- package/src/adapters/generic-sql/sql-adapter-sqlite3-driver.test.ts +273 -5
- package/src/adapters/generic-sql/sql-adapter-sqlite3-uow.test.ts +123 -6
- package/src/adapters/generic-sql/sql-adapter-sqlocal.test.ts +4 -2
- package/src/adapters/generic-sql/uow-decoder.test.ts +4 -3
- package/src/adapters/generic-sql/uow-decoder.ts +3 -3
- package/src/adapters/generic-sql/uow-encoder.test.ts +4 -2
- package/src/adapters/generic-sql/uow-encoder.ts +14 -18
- package/src/adapters/in-memory/condition-evaluator.test.ts +2 -1
- package/src/adapters/in-memory/condition-evaluator.ts +9 -4
- package/src/adapters/in-memory/in-memory-adapter.ts +155 -44
- package/src/adapters/in-memory/in-memory-uow.mutations.test.ts +50 -2
- package/src/adapters/in-memory/in-memory-uow.retrieval.test.ts +158 -3
- package/src/adapters/in-memory/in-memory-uow.ts +402 -26
- package/src/adapters/in-memory/options.test.ts +1 -0
- package/src/adapters/in-memory/options.ts +5 -1
- package/src/adapters/in-memory/outbox.test.ts +361 -0
- package/src/adapters/in-memory/reference-resolution.test.ts +3 -2
- package/src/adapters/in-memory/reference-resolution.ts +2 -2
- package/src/adapters/in-memory/sorted-array-index.test.ts +1 -0
- package/src/adapters/in-memory/store.test.ts +1 -0
- package/src/adapters/in-memory/store.ts +3 -3
- package/src/adapters/in-memory/value-normalization.test.ts +1 -0
- package/src/adapters/prisma/prisma-adapter-sqlite3.test.ts +51 -7
- package/src/adapters/shared/from-unit-of-work-compiler.ts +156 -46
- package/src/adapters/shared/uow-operation-compiler.ts +3 -3
- package/src/browser/mod.ts +64 -0
- package/src/client.ts +19 -0
- package/src/db-fragment-definition-builder.test.ts +821 -47
- package/src/db-fragment-definition-builder.ts +857 -110
- package/src/db-fragment-instantiator.test.ts +114 -90
- package/src/db-fragment-integration.test.ts +9 -6
- package/src/dispatchers/cloudflare-do/dispatcher.ts +204 -0
- package/src/dispatchers/cloudflare-do/index.test.ts +145 -12
- package/src/dispatchers/cloudflare-do/index.ts +49 -90
- package/src/dispatchers/node/dispatcher.ts +112 -0
- package/src/dispatchers/node/index.test.ts +43 -14
- package/src/dispatchers/node/index.ts +38 -75
- package/src/durable-hooks.test.ts +80 -0
- package/src/durable-hooks.ts +67 -0
- package/src/fragments/internal-fragment.routes.test.ts +570 -0
- package/src/fragments/internal-fragment.routes.ts +297 -5
- package/src/fragments/internal-fragment.schema.ts +45 -1
- package/src/fragments/internal-fragment.test.ts +223 -251
- package/src/fragments/internal-fragment.ts +278 -154
- package/src/hooks/durable-hooks-logger.ts +126 -0
- package/src/hooks/durable-hooks-processor.pglite.test.ts +87 -0
- package/src/hooks/durable-hooks-processor.test.ts +179 -14
- package/src/hooks/durable-hooks-processor.ts +120 -14
- package/src/hooks/durable-hooks-runtime.test.ts +65 -0
- package/src/hooks/durable-hooks-runtime.ts +81 -0
- package/src/hooks/hooks.test.ts +314 -53
- package/src/hooks/hooks.ts +360 -81
- package/src/id.test.ts +34 -0
- package/src/id.ts +1 -3
- package/src/internal/adapter-registry.test.ts +93 -0
- package/src/internal/adapter-registry.ts +239 -0
- package/src/internal/outbox-state.ts +43 -0
- package/src/migration-engine/auto-from-schema.test.ts +93 -0
- package/src/migration-engine/auto-from-schema.ts +360 -42
- package/src/migration-engine/create.test.ts +2 -1
- package/src/migration-engine/create.ts +1 -1
- package/src/migration-engine/generation-engine.test.ts +66 -9
- package/src/migration-engine/generation-engine.ts +31 -10
- package/src/migration-engine/shared.ts +13 -0
- package/src/mod.ts +45 -27
- package/src/naming/sql-naming.ts +1 -0
- package/src/outbox/outbox-builder.ts +2 -2
- package/src/outbox/outbox.test.ts +216 -45
- package/src/outbox/outbox.ts +3 -1
- package/src/query/column-defaults.ts +1 -1
- package/src/query/condition-builder.test.ts +15 -0
- package/src/query/condition-builder.ts +7 -0
- package/src/query/cursor-client.test.ts +70 -0
- package/src/query/cursor-client.ts +263 -0
- package/src/query/cursor.test.ts +3 -2
- package/src/query/cursor.ts +15 -3
- package/src/query/db-now.ts +69 -2
- package/src/query/orm/orm.ts +2 -2
- package/src/query/query-type.test.ts +2 -1
- package/src/query/serialize/create-sql-serializer.ts +3 -3
- package/src/query/serialize/dialect/mysql-serializer.ts +1 -1
- package/src/query/serialize/dialect/postgres-serializer.ts +1 -1
- package/src/query/serialize/dialect/sqlite-serializer.test.ts +39 -2
- package/src/query/serialize/dialect/sqlite-serializer.ts +18 -5
- package/src/query/simple-query-interface.ts +10 -4
- package/src/query/unit-of-work/execute-unit-of-work.test.ts +347 -9
- package/src/query/unit-of-work/execute-unit-of-work.ts +63 -20
- package/src/query/unit-of-work/retry-policy.test.ts +1 -0
- package/src/query/unit-of-work/tx-builder.test.ts +73 -1
- package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +5 -4
- package/src/query/unit-of-work/unit-of-work-types.test.ts +41 -11
- package/src/query/unit-of-work/unit-of-work.test.ts +28 -2
- package/src/query/unit-of-work/unit-of-work.ts +105 -19
- package/src/query/value-decoding.test.ts +50 -2
- package/src/query/value-decoding.ts +17 -4
- package/src/query/value-encoding.test.ts +1 -0
- package/src/query/value-encoding.ts +1 -1
- package/src/schema/create.test.ts +164 -5
- package/src/schema/create.ts +222 -24
- package/src/schema/generate-id.test.ts +1 -0
- package/src/schema/serialize.test.ts +4 -3
- package/src/schema/type-conversion/create-sql-type-mapper.ts +1 -1
- package/src/schema/type-conversion/dialect/sqlite.ts +2 -2
- package/src/schema/type-conversion/type-mapping.test.ts +2 -1
- package/src/schema/validator.test.ts +4 -2
- package/src/schema/validator.ts +1 -0
- package/src/schema-output/drizzle.test.ts +72 -19
- package/src/schema-output/drizzle.ts +24 -18
- package/src/schema-output/prisma.test.ts +172 -14
- package/src/schema-output/prisma.ts +34 -14
- package/src/sql-driver/better-sqlite3.test.ts +5 -3
- package/src/sql-driver/dialects/durable-object-dialect.ts +3 -8
- package/src/sql-driver/query-executor/default-query-executor.ts +1 -1
- package/src/sql-driver/query-executor/query-executor-base.ts +1 -1
- package/src/sql-driver/query-executor/query-executor.ts +1 -1
- package/src/sql-driver/sql-driver-adapter.ts +2 -2
- package/src/sql-driver/sql.ts +2 -1
- package/src/sql-driver/sqlocal.test.ts +4 -2
- package/src/sync/commands.test.ts +39 -0
- package/src/sync/commands.ts +51 -0
- package/src/sync/conflict-checker.test.ts +450 -0
- package/src/sync/conflict-checker.ts +248 -0
- package/src/sync/index.ts +14 -0
- package/src/sync/plan.ts +9 -0
- package/src/sync/read-tracking.test.ts +177 -0
- package/src/sync/read-tracking.ts +287 -0
- package/src/sync/submit.test.ts +205 -0
- package/src/sync/submit.ts +328 -0
- package/src/sync/types.ts +80 -0
- package/src/util/default-database-adapter.ts +15 -2
- package/src/with-database.ts +20 -50
- package/tsconfig.json +1 -1
- package/tsdown.config.ts +38 -26
- package/vitest.config.ts +1 -0
- package/dist/hooks/durable-hooks-processor.d.ts.map +0 -1
- package/dist/node_modules/.pnpm/rou3@0.7.12/node_modules/rou3/dist/index.js +0 -168
- package/dist/node_modules/.pnpm/rou3@0.7.12/node_modules/rou3/dist/index.js.map +0 -1
- package/dist/packages/fragno/dist/api/bind-services.js +0 -20
- package/dist/packages/fragno/dist/api/bind-services.js.map +0 -1
- package/dist/packages/fragno/dist/api/error.js +0 -48
- package/dist/packages/fragno/dist/api/error.js.map +0 -1
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js +0 -321
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +0 -1
- package/dist/packages/fragno/dist/api/fragment-instantiator.js +0 -669
- package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +0 -1
- package/dist/packages/fragno/dist/api/fragno-response.js +0 -73
- package/dist/packages/fragno/dist/api/fragno-response.js.map +0 -1
- package/dist/packages/fragno/dist/api/internal/response-stream.js +0 -81
- package/dist/packages/fragno/dist/api/internal/response-stream.js.map +0 -1
- package/dist/packages/fragno/dist/api/internal/route.js +0 -10
- package/dist/packages/fragno/dist/api/internal/route.js.map +0 -1
- package/dist/packages/fragno/dist/api/mutable-request-state.js +0 -97
- package/dist/packages/fragno/dist/api/mutable-request-state.js.map +0 -1
- package/dist/packages/fragno/dist/api/request-context-storage.js +0 -43
- package/dist/packages/fragno/dist/api/request-context-storage.js.map +0 -1
- package/dist/packages/fragno/dist/api/request-input-context.js +0 -185
- package/dist/packages/fragno/dist/api/request-input-context.js.map +0 -1
- package/dist/packages/fragno/dist/api/request-middleware.js +0 -83
- package/dist/packages/fragno/dist/api/request-middleware.js.map +0 -1
- package/dist/packages/fragno/dist/api/request-output-context.js +0 -119
- package/dist/packages/fragno/dist/api/request-output-context.js.map +0 -1
- package/dist/packages/fragno/dist/api/route.js +0 -30
- package/dist/packages/fragno/dist/api/route.js.map +0 -1
- package/dist/packages/fragno/dist/internal/symbols.js +0 -10
- package/dist/packages/fragno/dist/internal/symbols.js.map +0 -1
- package/dist/packages/fragno/dist/internal/trace-context.js +0 -12
- package/dist/packages/fragno/dist/internal/trace-context.js.map +0 -1
|
@@ -1,24 +1,30 @@
|
|
|
1
|
-
import { describe, it, expect, expectTypeOf } from "vitest";
|
|
1
|
+
import { describe, it, expect, expectTypeOf, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { InMemoryAdapter } from "../../adapters/in-memory/in-memory-adapter";
|
|
4
|
+
import type { InternalFragmentInstance } from "../../fragments/internal-fragment";
|
|
5
|
+
import { internalSchema } from "../../fragments/internal-fragment.schema";
|
|
6
|
+
import { prepareHookMutations } from "../../hooks/hooks";
|
|
2
7
|
import { schema, idColumn, FragnoId } from "../../schema/create";
|
|
3
|
-
import {
|
|
4
|
-
createUnitOfWork,
|
|
5
|
-
type IUnitOfWork,
|
|
6
|
-
type UOWCompiler,
|
|
7
|
-
type UOWDecoder,
|
|
8
|
-
type UOWExecutor,
|
|
9
|
-
} from "./unit-of-work";
|
|
10
8
|
import {
|
|
11
9
|
createServiceTxBuilder,
|
|
12
10
|
createHandlerTxBuilder,
|
|
13
11
|
isTxResult,
|
|
12
|
+
serviceCalls,
|
|
14
13
|
ConcurrencyConflictError,
|
|
15
14
|
} from "./execute-unit-of-work";
|
|
15
|
+
import type { AwaitedPromisesInObject, TxResult } from "./execute-unit-of-work";
|
|
16
16
|
import {
|
|
17
17
|
ExponentialBackoffRetryPolicy,
|
|
18
18
|
LinearBackoffRetryPolicy,
|
|
19
19
|
NoRetryPolicy,
|
|
20
20
|
} from "./retry-policy";
|
|
21
|
-
import
|
|
21
|
+
import {
|
|
22
|
+
createUnitOfWork,
|
|
23
|
+
type IUnitOfWork,
|
|
24
|
+
type UOWCompiler,
|
|
25
|
+
type UOWDecoder,
|
|
26
|
+
type UOWExecutor,
|
|
27
|
+
} from "./unit-of-work";
|
|
22
28
|
|
|
23
29
|
const testSchema = schema("test", (s) =>
|
|
24
30
|
s.addTable("users", (t) =>
|
|
@@ -31,6 +37,42 @@ const testSchema = schema("test", (s) =>
|
|
|
31
37
|
),
|
|
32
38
|
);
|
|
33
39
|
|
|
40
|
+
function setupCrossSchemaHookTest() {
|
|
41
|
+
const adapter = new InMemoryAdapter();
|
|
42
|
+
const schemaA = schema("alpha", (s) =>
|
|
43
|
+
s.addTable("items", (t) => t.addColumn("id", idColumn()).addColumn("label", "string")),
|
|
44
|
+
);
|
|
45
|
+
const schemaB = schema("beta", (s) =>
|
|
46
|
+
s.addTable("items", (t) => t.addColumn("id", idColumn()).addColumn("label", "string")),
|
|
47
|
+
);
|
|
48
|
+
const namespaceA = "alpha";
|
|
49
|
+
const namespaceB = "beta";
|
|
50
|
+
|
|
51
|
+
const queryA = adapter.createQueryEngine(schemaA, namespaceA);
|
|
52
|
+
const queryB = adapter.createQueryEngine(schemaB, namespaceB);
|
|
53
|
+
const internalQuery = adapter.createQueryEngine(internalSchema, null);
|
|
54
|
+
|
|
55
|
+
const internalFragment = {
|
|
56
|
+
$internal: {
|
|
57
|
+
deps: {
|
|
58
|
+
schema: internalSchema,
|
|
59
|
+
namespace: null,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
} as InternalFragmentInstance;
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
schemaA,
|
|
66
|
+
schemaB,
|
|
67
|
+
namespaceA,
|
|
68
|
+
namespaceB,
|
|
69
|
+
queryA,
|
|
70
|
+
queryB,
|
|
71
|
+
internalQuery,
|
|
72
|
+
internalFragment,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
34
76
|
describe("AwaitedPromisesInObject type tests", () => {
|
|
35
77
|
it("should unwrap promises in objects", () => {
|
|
36
78
|
type Input = { a: Promise<string>; b: number };
|
|
@@ -390,6 +432,36 @@ describe("Unified Tx API", () => {
|
|
|
390
432
|
expect(users[1].name).toBe("Bob");
|
|
391
433
|
});
|
|
392
434
|
|
|
435
|
+
it("should call onAfterRetrieve with full results", async () => {
|
|
436
|
+
const compiler = createMockCompiler();
|
|
437
|
+
const mockUsers = [
|
|
438
|
+
{
|
|
439
|
+
id: FragnoId.fromExternal("1", 1),
|
|
440
|
+
email: "alice@example.com",
|
|
441
|
+
name: "Alice",
|
|
442
|
+
balance: 100,
|
|
443
|
+
},
|
|
444
|
+
];
|
|
445
|
+
const executor: UOWExecutor<unknown, unknown> = {
|
|
446
|
+
executeRetrievalPhase: async () => [mockUsers],
|
|
447
|
+
executeMutationPhase: async () => ({ success: true, createdInternalIds: [] }),
|
|
448
|
+
};
|
|
449
|
+
const decoder = createMockDecoder();
|
|
450
|
+
const onAfterRetrieve = vi.fn();
|
|
451
|
+
|
|
452
|
+
await createHandlerTxBuilder({
|
|
453
|
+
createUnitOfWork: () => createUnitOfWork(compiler, executor, decoder),
|
|
454
|
+
onAfterRetrieve,
|
|
455
|
+
})
|
|
456
|
+
.retrieve(({ forSchema }) =>
|
|
457
|
+
forSchema(testSchema).find("users", (b) => b.whereIndex("idx_email")),
|
|
458
|
+
)
|
|
459
|
+
.execute();
|
|
460
|
+
|
|
461
|
+
expect(onAfterRetrieve).toHaveBeenCalledOnce();
|
|
462
|
+
expect(onAfterRetrieve.mock.calls[0]?.[1]).toEqual([mockUsers]);
|
|
463
|
+
});
|
|
464
|
+
|
|
393
465
|
it("should execute a simple mutate-only transaction", async () => {
|
|
394
466
|
const compiler = createMockCompiler();
|
|
395
467
|
const executor: UOWExecutor<unknown, unknown> = {
|
|
@@ -773,6 +845,72 @@ describe("Unified Tx API", () => {
|
|
|
773
845
|
expect(result.finalDepUserId).toBeInstanceOf(FragnoId);
|
|
774
846
|
});
|
|
775
847
|
|
|
848
|
+
it("should preserve tuple inference for dynamic serviceCalls using helper", async () => {
|
|
849
|
+
const compiler = createMockCompiler();
|
|
850
|
+
const executor: UOWExecutor<unknown, unknown> = {
|
|
851
|
+
executeRetrievalPhase: async () => [],
|
|
852
|
+
executeMutationPhase: async () => ({ success: true, createdInternalIds: [BigInt(1)] }),
|
|
853
|
+
};
|
|
854
|
+
const decoder = createMockDecoder();
|
|
855
|
+
|
|
856
|
+
let currentUow: IUnitOfWork | null = null;
|
|
857
|
+
|
|
858
|
+
type UserData = { id: FragnoId; email: string };
|
|
859
|
+
type Stats = { count: number };
|
|
860
|
+
type HistoryEntry = { page: number };
|
|
861
|
+
|
|
862
|
+
const getUser = () =>
|
|
863
|
+
createServiceTxBuilder(testSchema, currentUow!)
|
|
864
|
+
.mutate(({ uow }): UserData => {
|
|
865
|
+
const userId = uow.create("users", {
|
|
866
|
+
email: "user@example.com",
|
|
867
|
+
name: "User",
|
|
868
|
+
balance: 0,
|
|
869
|
+
});
|
|
870
|
+
return { id: userId, email: "user@example.com" };
|
|
871
|
+
})
|
|
872
|
+
.build();
|
|
873
|
+
|
|
874
|
+
const getStats = () =>
|
|
875
|
+
createServiceTxBuilder(testSchema, currentUow!)
|
|
876
|
+
.mutate((): Stats => ({ count: 42 }))
|
|
877
|
+
.build();
|
|
878
|
+
|
|
879
|
+
const listHistory = (page: number) =>
|
|
880
|
+
createServiceTxBuilder(testSchema, currentUow!)
|
|
881
|
+
.mutate((): HistoryEntry => ({ page }))
|
|
882
|
+
.build();
|
|
883
|
+
|
|
884
|
+
const result = await createHandlerTxBuilder({
|
|
885
|
+
createUnitOfWork: () => {
|
|
886
|
+
currentUow = createUnitOfWork(compiler, executor, decoder);
|
|
887
|
+
return currentUow;
|
|
888
|
+
},
|
|
889
|
+
})
|
|
890
|
+
.withServiceCalls(() => {
|
|
891
|
+
const historyCalls = Array.from({ length: 2 }, (_, idx) => listHistory(idx + 1));
|
|
892
|
+
return serviceCalls(getUser(), getStats(), ...historyCalls);
|
|
893
|
+
})
|
|
894
|
+
.mutate(({ serviceIntermediateResult }) => {
|
|
895
|
+
const [user, stats, ...history] = serviceIntermediateResult;
|
|
896
|
+
|
|
897
|
+
expectTypeOf(user).toEqualTypeOf<UserData>();
|
|
898
|
+
expectTypeOf(stats).toEqualTypeOf<Stats>();
|
|
899
|
+
expectTypeOf(history).items.toEqualTypeOf<HistoryEntry>();
|
|
900
|
+
|
|
901
|
+
return {
|
|
902
|
+
userId: user.id,
|
|
903
|
+
count: stats.count,
|
|
904
|
+
pages: history.map((entry) => entry.page),
|
|
905
|
+
};
|
|
906
|
+
})
|
|
907
|
+
.execute();
|
|
908
|
+
|
|
909
|
+
expect(result.count).toBe(42);
|
|
910
|
+
expect(result.pages).toEqual([1, 2]);
|
|
911
|
+
expect(result.userId).toBeInstanceOf(FragnoId);
|
|
912
|
+
});
|
|
913
|
+
|
|
776
914
|
it("should retry on concurrency conflict", async () => {
|
|
777
915
|
const compiler = createMockCompiler();
|
|
778
916
|
let mutationAttempts = 0;
|
|
@@ -911,6 +1049,88 @@ describe("Unified Tx API", () => {
|
|
|
911
1049
|
).rejects.toThrow("Transaction execution aborted");
|
|
912
1050
|
});
|
|
913
1051
|
|
|
1052
|
+
it("should propagate error when mutate callback rejects a duplicate via retrieve guard", async () => {
|
|
1053
|
+
const compiler = createMockCompiler();
|
|
1054
|
+
const existingUser = {
|
|
1055
|
+
id: FragnoId.fromExternal("existing-1", 1),
|
|
1056
|
+
email: "alice@example.com",
|
|
1057
|
+
name: "Alice",
|
|
1058
|
+
balance: 100,
|
|
1059
|
+
};
|
|
1060
|
+
const executor: UOWExecutor<unknown, unknown> = {
|
|
1061
|
+
executeRetrievalPhase: async () => [[existingUser]],
|
|
1062
|
+
executeMutationPhase: async () => ({ success: true, createdInternalIds: [] }),
|
|
1063
|
+
};
|
|
1064
|
+
const decoder = createMockDecoder();
|
|
1065
|
+
|
|
1066
|
+
let currentUow: IUnitOfWork | null = null;
|
|
1067
|
+
|
|
1068
|
+
const createIfNotExists = (email: string) => {
|
|
1069
|
+
return createServiceTxBuilder(testSchema, currentUow!)
|
|
1070
|
+
.retrieve((uow) =>
|
|
1071
|
+
uow.find("users", (b) => b.whereIndex("idx_email", (eb) => eb("email", "=", email))),
|
|
1072
|
+
)
|
|
1073
|
+
.mutate(({ uow, retrieveResult: [users] }) => {
|
|
1074
|
+
if (users.length > 0) {
|
|
1075
|
+
throw new Error("ALREADY_EXISTS");
|
|
1076
|
+
}
|
|
1077
|
+
const id = uow.create("users", { email, name: "New", balance: 0 });
|
|
1078
|
+
return { id };
|
|
1079
|
+
})
|
|
1080
|
+
.build();
|
|
1081
|
+
};
|
|
1082
|
+
|
|
1083
|
+
await expect(
|
|
1084
|
+
createHandlerTxBuilder({
|
|
1085
|
+
createUnitOfWork: () => {
|
|
1086
|
+
currentUow = createUnitOfWork(compiler, executor, decoder);
|
|
1087
|
+
return currentUow;
|
|
1088
|
+
},
|
|
1089
|
+
})
|
|
1090
|
+
.withServiceCalls(() => [createIfNotExists("alice@example.com")])
|
|
1091
|
+
.transform(({ serviceResult: [result] }) => result)
|
|
1092
|
+
.execute(),
|
|
1093
|
+
).rejects.toThrow("ALREADY_EXISTS");
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1096
|
+
it("should succeed when retrieve guard finds no existing record", async () => {
|
|
1097
|
+
const compiler = createMockCompiler();
|
|
1098
|
+
const executor: UOWExecutor<unknown, unknown> = {
|
|
1099
|
+
executeRetrievalPhase: async () => [[]],
|
|
1100
|
+
executeMutationPhase: async () => ({ success: true, createdInternalIds: [BigInt(1)] }),
|
|
1101
|
+
};
|
|
1102
|
+
const decoder = createMockDecoder();
|
|
1103
|
+
|
|
1104
|
+
let currentUow: IUnitOfWork | null = null;
|
|
1105
|
+
|
|
1106
|
+
const createIfNotExists = (email: string) => {
|
|
1107
|
+
return createServiceTxBuilder(testSchema, currentUow!)
|
|
1108
|
+
.retrieve((uow) =>
|
|
1109
|
+
uow.find("users", (b) => b.whereIndex("idx_email", (eb) => eb("email", "=", email))),
|
|
1110
|
+
)
|
|
1111
|
+
.mutate(({ uow, retrieveResult: [users] }) => {
|
|
1112
|
+
if (users.length > 0) {
|
|
1113
|
+
throw new Error("ALREADY_EXISTS");
|
|
1114
|
+
}
|
|
1115
|
+
const id = uow.create("users", { email, name: "New", balance: 0 });
|
|
1116
|
+
return { id };
|
|
1117
|
+
})
|
|
1118
|
+
.build();
|
|
1119
|
+
};
|
|
1120
|
+
|
|
1121
|
+
const result = await createHandlerTxBuilder({
|
|
1122
|
+
createUnitOfWork: () => {
|
|
1123
|
+
currentUow = createUnitOfWork(compiler, executor, decoder);
|
|
1124
|
+
return currentUow;
|
|
1125
|
+
},
|
|
1126
|
+
})
|
|
1127
|
+
.withServiceCalls(() => [createIfNotExists("new@example.com")])
|
|
1128
|
+
.transform(({ serviceResult: [result] }) => result)
|
|
1129
|
+
.execute();
|
|
1130
|
+
|
|
1131
|
+
expect(result.id).toBeInstanceOf(FragnoId);
|
|
1132
|
+
});
|
|
1133
|
+
|
|
914
1134
|
it("should pass serviceResult to transform callback with final results", async () => {
|
|
915
1135
|
const compiler = createMockCompiler();
|
|
916
1136
|
const mockUser = {
|
|
@@ -1547,6 +1767,7 @@ describe("Unified Tx API", () => {
|
|
|
1547
1767
|
await createHandlerTxBuilder({
|
|
1548
1768
|
createUnitOfWork: () => {
|
|
1549
1769
|
currentUow = createUnitOfWork(compiler, executor, decoder);
|
|
1770
|
+
currentUow.registerSchema(testSchema, "test");
|
|
1550
1771
|
return currentUow;
|
|
1551
1772
|
},
|
|
1552
1773
|
})
|
|
@@ -1616,6 +1837,7 @@ describe("Unified Tx API", () => {
|
|
|
1616
1837
|
await createHandlerTxBuilder({
|
|
1617
1838
|
createUnitOfWork: () => {
|
|
1618
1839
|
currentUow = createUnitOfWork(compiler, executor, decoder);
|
|
1840
|
+
currentUow.registerSchema(testSchema, "test");
|
|
1619
1841
|
return currentUow;
|
|
1620
1842
|
},
|
|
1621
1843
|
})
|
|
@@ -1631,6 +1853,122 @@ describe("Unified Tx API", () => {
|
|
|
1631
1853
|
payload: { userId: expect.any(String) },
|
|
1632
1854
|
});
|
|
1633
1855
|
});
|
|
1856
|
+
|
|
1857
|
+
it("should create hook records when handler uses schema A and service uses schema B", async () => {
|
|
1858
|
+
const { schemaA, schemaB, namespaceA, namespaceB, queryA, internalQuery, internalFragment } =
|
|
1859
|
+
setupCrossSchemaHookTest();
|
|
1860
|
+
|
|
1861
|
+
type HooksA = {
|
|
1862
|
+
onAlpha: (payload: { value: string }) => void;
|
|
1863
|
+
};
|
|
1864
|
+
type HooksB = {
|
|
1865
|
+
onBeta: (payload: { value: string }) => void;
|
|
1866
|
+
};
|
|
1867
|
+
|
|
1868
|
+
const hooksA: HooksA = {
|
|
1869
|
+
onAlpha: (_payload) => {},
|
|
1870
|
+
};
|
|
1871
|
+
const hooksB: HooksB = {
|
|
1872
|
+
onBeta: (_payload) => {},
|
|
1873
|
+
};
|
|
1874
|
+
|
|
1875
|
+
let currentUow: IUnitOfWork | null = null;
|
|
1876
|
+
|
|
1877
|
+
const serviceInSchemaB = (value: string) =>
|
|
1878
|
+
createServiceTxBuilder(schemaB, currentUow!, hooksB)
|
|
1879
|
+
.mutate(({ uow }) => {
|
|
1880
|
+
uow.create("items", { label: value });
|
|
1881
|
+
uow.triggerHook("onBeta", { value });
|
|
1882
|
+
})
|
|
1883
|
+
.build();
|
|
1884
|
+
|
|
1885
|
+
await createHandlerTxBuilder({
|
|
1886
|
+
createUnitOfWork: () => {
|
|
1887
|
+
currentUow = queryA.createBaseUnitOfWork();
|
|
1888
|
+
currentUow.registerSchema(schemaA, namespaceA);
|
|
1889
|
+
currentUow.registerSchema(schemaB, namespaceB);
|
|
1890
|
+
currentUow.registerSchema(internalSchema, null);
|
|
1891
|
+
return currentUow;
|
|
1892
|
+
},
|
|
1893
|
+
onBeforeMutate: (uow) => {
|
|
1894
|
+
prepareHookMutations(uow, internalFragment);
|
|
1895
|
+
},
|
|
1896
|
+
})
|
|
1897
|
+
.mutate(({ forSchema }) => {
|
|
1898
|
+
const uow = forSchema(schemaA, hooksA);
|
|
1899
|
+
uow.create("items", { label: "alpha" });
|
|
1900
|
+
uow.triggerHook("onAlpha", { value: "alpha" });
|
|
1901
|
+
})
|
|
1902
|
+
.withServiceCalls(() => [serviceInSchemaB("beta")] as const)
|
|
1903
|
+
.execute();
|
|
1904
|
+
|
|
1905
|
+
const hooks = await internalQuery.find("fragno_hooks");
|
|
1906
|
+
expect(hooks).toHaveLength(2);
|
|
1907
|
+
expect(hooks).toEqual(
|
|
1908
|
+
expect.arrayContaining([
|
|
1909
|
+
expect.objectContaining({ hookName: "onAlpha", namespace: namespaceA }),
|
|
1910
|
+
expect.objectContaining({ hookName: "onBeta", namespace: namespaceB }),
|
|
1911
|
+
]),
|
|
1912
|
+
);
|
|
1913
|
+
});
|
|
1914
|
+
|
|
1915
|
+
it("should create hook records when handler uses schema B and service uses schema A", async () => {
|
|
1916
|
+
const { schemaA, schemaB, namespaceA, namespaceB, queryB, internalQuery, internalFragment } =
|
|
1917
|
+
setupCrossSchemaHookTest();
|
|
1918
|
+
|
|
1919
|
+
type HooksA = {
|
|
1920
|
+
onAlpha: (payload: { value: string }) => void;
|
|
1921
|
+
};
|
|
1922
|
+
type HooksB = {
|
|
1923
|
+
onBeta: (payload: { value: string }) => void;
|
|
1924
|
+
};
|
|
1925
|
+
|
|
1926
|
+
const hooksA: HooksA = {
|
|
1927
|
+
onAlpha: (_payload) => {},
|
|
1928
|
+
};
|
|
1929
|
+
const hooksB: HooksB = {
|
|
1930
|
+
onBeta: (_payload) => {},
|
|
1931
|
+
};
|
|
1932
|
+
|
|
1933
|
+
let currentUow: IUnitOfWork | null = null;
|
|
1934
|
+
|
|
1935
|
+
const serviceInSchemaA = (value: string) =>
|
|
1936
|
+
createServiceTxBuilder(schemaA, currentUow!, hooksA)
|
|
1937
|
+
.mutate(({ uow }) => {
|
|
1938
|
+
uow.create("items", { label: value });
|
|
1939
|
+
uow.triggerHook("onAlpha", { value });
|
|
1940
|
+
})
|
|
1941
|
+
.build();
|
|
1942
|
+
|
|
1943
|
+
await createHandlerTxBuilder({
|
|
1944
|
+
createUnitOfWork: () => {
|
|
1945
|
+
currentUow = queryB.createBaseUnitOfWork();
|
|
1946
|
+
currentUow.registerSchema(schemaA, namespaceA);
|
|
1947
|
+
currentUow.registerSchema(schemaB, namespaceB);
|
|
1948
|
+
currentUow.registerSchema(internalSchema, null);
|
|
1949
|
+
return currentUow;
|
|
1950
|
+
},
|
|
1951
|
+
onBeforeMutate: (uow) => {
|
|
1952
|
+
prepareHookMutations(uow, internalFragment);
|
|
1953
|
+
},
|
|
1954
|
+
})
|
|
1955
|
+
.mutate(({ forSchema }) => {
|
|
1956
|
+
const uow = forSchema(schemaB, hooksB);
|
|
1957
|
+
uow.create("items", { label: "beta" });
|
|
1958
|
+
uow.triggerHook("onBeta", { value: "beta" });
|
|
1959
|
+
})
|
|
1960
|
+
.withServiceCalls(() => [serviceInSchemaA("alpha")] as const)
|
|
1961
|
+
.execute();
|
|
1962
|
+
|
|
1963
|
+
const hooks = await internalQuery.find("fragno_hooks");
|
|
1964
|
+
expect(hooks).toHaveLength(2);
|
|
1965
|
+
expect(hooks).toEqual(
|
|
1966
|
+
expect.arrayContaining([
|
|
1967
|
+
expect.objectContaining({ hookName: "onAlpha", namespace: namespaceA }),
|
|
1968
|
+
expect.objectContaining({ hookName: "onBeta", namespace: namespaceB }),
|
|
1969
|
+
]),
|
|
1970
|
+
);
|
|
1971
|
+
});
|
|
1634
1972
|
});
|
|
1635
1973
|
|
|
1636
1974
|
describe("error handling in createServiceTx", () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { AnySchema } from "../../schema/create";
|
|
2
|
-
import type { TypedUnitOfWork, IUnitOfWork } from "./unit-of-work";
|
|
3
1
|
import type { HooksMap } from "../../hooks/hooks";
|
|
2
|
+
import type { AnySchema } from "../../schema/create";
|
|
4
3
|
import { ExponentialBackoffRetryPolicy, NoRetryPolicy, type RetryPolicy } from "./retry-policy";
|
|
4
|
+
import type { TypedUnitOfWork, IUnitOfWork } from "./unit-of-work";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Symbol to identify TxResult objects
|
|
@@ -58,6 +58,26 @@ export type ExtractServiceFinalResults<T extends readonly unknown[]> = {
|
|
|
58
58
|
[K in keyof T]: ExtractTxFinalResult<T[K]>;
|
|
59
59
|
};
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Helper to preserve tuple inference for service calls, especially with spreads.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* const historyCalls = Array.from({ length: 3 }, () => svc.listHistory(...));
|
|
67
|
+
* return serviceCalls(
|
|
68
|
+
* svc.getInstanceStatus(...),
|
|
69
|
+
* svc.getInstanceRunNumber(...),
|
|
70
|
+
* ...historyCalls,
|
|
71
|
+
* );
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
75
|
+
export function serviceCalls<const T extends readonly (TxResult<any, any> | undefined)[]>(
|
|
76
|
+
...calls: T
|
|
77
|
+
): T {
|
|
78
|
+
return calls;
|
|
79
|
+
}
|
|
80
|
+
|
|
61
81
|
/**
|
|
62
82
|
* Context passed to mutate callback for service methods
|
|
63
83
|
*/
|
|
@@ -491,6 +511,12 @@ export interface ExecuteTxOptions {
|
|
|
491
511
|
*/
|
|
492
512
|
signal?: AbortSignal;
|
|
493
513
|
|
|
514
|
+
/**
|
|
515
|
+
* Callback invoked after retrieval phase completes.
|
|
516
|
+
* Use this to inspect retrieval operations and results (e.g., read tracking).
|
|
517
|
+
*/
|
|
518
|
+
onAfterRetrieve?: (uow: IUnitOfWork, results: unknown[]) => void | Promise<void>;
|
|
519
|
+
|
|
494
520
|
/**
|
|
495
521
|
* Callback invoked before mutations are executed.
|
|
496
522
|
* Use this to add additional mutation operations (e.g., hook event records).
|
|
@@ -502,6 +528,11 @@ export interface ExecuteTxOptions {
|
|
|
502
528
|
* Use this for post-mutation processing like hook execution.
|
|
503
529
|
*/
|
|
504
530
|
onAfterMutate?: (uow: IUnitOfWork) => Promise<void>;
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Plan mode suppresses hook execution while still running serviceTx logic.
|
|
534
|
+
*/
|
|
535
|
+
planMode?: boolean;
|
|
505
536
|
}
|
|
506
537
|
|
|
507
538
|
/**
|
|
@@ -738,6 +769,10 @@ async function executeTx(
|
|
|
738
769
|
try {
|
|
739
770
|
// Create a fresh UOW for this attempt
|
|
740
771
|
const baseUow = options.createUnitOfWork();
|
|
772
|
+
if (options.onAfterRetrieve) {
|
|
773
|
+
const readTrackingUow = baseUow as { enableReadTracking?: () => void };
|
|
774
|
+
readTrackingUow.enableReadTracking?.();
|
|
775
|
+
}
|
|
741
776
|
|
|
742
777
|
// Create handler context
|
|
743
778
|
const context: HandlerTxContext<THooks> = {
|
|
@@ -777,7 +812,10 @@ async function executeTx(
|
|
|
777
812
|
});
|
|
778
813
|
}
|
|
779
814
|
|
|
780
|
-
await baseUow.executeRetrieve();
|
|
815
|
+
const allRetrieveResults = await baseUow.executeRetrieve();
|
|
816
|
+
if (options.onAfterRetrieve) {
|
|
817
|
+
await options.onAfterRetrieve(baseUow, allRetrieveResults);
|
|
818
|
+
}
|
|
781
819
|
|
|
782
820
|
// Get retrieve results from TypedUnitOfWork's retrievalPhase or default to empty array
|
|
783
821
|
const retrieveResult: TRetrieveResults = typedUowFromRetrieve
|
|
@@ -840,7 +878,7 @@ async function executeTx(
|
|
|
840
878
|
mutateResult = callbacks.mutate(mutateCtx);
|
|
841
879
|
}
|
|
842
880
|
|
|
843
|
-
if (options.onBeforeMutate) {
|
|
881
|
+
if (!options.planMode && options.onBeforeMutate) {
|
|
844
882
|
options.onBeforeMutate(baseUow);
|
|
845
883
|
}
|
|
846
884
|
const result = await baseUow.executeMutations();
|
|
@@ -883,7 +921,7 @@ async function executeTx(
|
|
|
883
921
|
finalResult = serviceFinalResults;
|
|
884
922
|
}
|
|
885
923
|
|
|
886
|
-
if (options.onAfterMutate) {
|
|
924
|
+
if (!options.planMode && options.onAfterMutate) {
|
|
887
925
|
await options.onAfterMutate(baseUow);
|
|
888
926
|
}
|
|
889
927
|
|
|
@@ -1555,6 +1593,7 @@ interface HandlerTxBuilderState<
|
|
|
1555
1593
|
> {
|
|
1556
1594
|
options: ExecuteTxOptions;
|
|
1557
1595
|
hooks?: THooks;
|
|
1596
|
+
executeWrapper?: <T>(run: () => Promise<T>) => Promise<T>;
|
|
1558
1597
|
withServiceCallsFn?: () => TServiceCalls;
|
|
1559
1598
|
retrieveFn?: (context: {
|
|
1560
1599
|
forSchema: <S extends AnySchema, H extends HooksMap = THooks>(
|
|
@@ -1891,22 +1930,24 @@ export class HandlerTxBuilder<
|
|
|
1891
1930
|
: undefined,
|
|
1892
1931
|
};
|
|
1893
1932
|
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1933
|
+
const run = () =>
|
|
1934
|
+
executeTx(callbacks as Parameters<typeof executeTx>[0], state.options) as Promise<
|
|
1935
|
+
AwaitedPromisesInObject<
|
|
1936
|
+
InferBuilderResultType<
|
|
1937
|
+
TRetrieveResults,
|
|
1938
|
+
TRetrieveSuccessResult,
|
|
1939
|
+
TServiceCalls,
|
|
1940
|
+
TMutateResult,
|
|
1941
|
+
TTransformResult,
|
|
1942
|
+
HasTransform,
|
|
1943
|
+
HasMutate,
|
|
1944
|
+
HasTransformRetrieve,
|
|
1945
|
+
HasRetrieve
|
|
1946
|
+
>
|
|
1907
1947
|
>
|
|
1908
|
-
|
|
1909
|
-
|
|
1948
|
+
>;
|
|
1949
|
+
|
|
1950
|
+
return state.executeWrapper ? state.executeWrapper(run) : run();
|
|
1910
1951
|
}
|
|
1911
1952
|
}
|
|
1912
1953
|
|
|
@@ -1916,9 +1957,11 @@ export class HandlerTxBuilder<
|
|
|
1916
1957
|
export function createHandlerTxBuilder<THooks extends HooksMap = {}>(
|
|
1917
1958
|
options: ExecuteTxOptions,
|
|
1918
1959
|
hooks?: THooks,
|
|
1960
|
+
executeWrapper?: <T>(run: () => Promise<T>) => Promise<T>,
|
|
1919
1961
|
): HandlerTxBuilder<readonly [], [], [], unknown, unknown, false, false, false, false, THooks> {
|
|
1920
1962
|
return new HandlerTxBuilder({
|
|
1921
1963
|
options,
|
|
1922
1964
|
hooks,
|
|
1965
|
+
executeWrapper,
|
|
1923
1966
|
});
|
|
1924
1967
|
}
|
|
@@ -7,12 +7,13 @@
|
|
|
7
7
|
* not the runtime behavior (which is covered by execute-unit-of-work.test.ts).
|
|
8
8
|
*/
|
|
9
9
|
import { describe, expectTypeOf, it } from "vitest";
|
|
10
|
+
|
|
10
11
|
import type { AnySchema } from "../../schema/create";
|
|
11
|
-
import type { TypedUnitOfWork } from "./unit-of-work";
|
|
12
12
|
import {
|
|
13
13
|
ServiceTxBuilder,
|
|
14
14
|
HandlerTxBuilder,
|
|
15
15
|
type TxResult,
|
|
16
|
+
serviceCalls,
|
|
16
17
|
type ServiceBuilderMutateContext,
|
|
17
18
|
type HandlerBuilderMutateContext,
|
|
18
19
|
type BuilderTransformContextWithMutate,
|
|
@@ -21,6 +22,7 @@ import {
|
|
|
21
22
|
type ExtractServiceFinalResults,
|
|
22
23
|
type AwaitedPromisesInObject,
|
|
23
24
|
} from "./execute-unit-of-work";
|
|
25
|
+
import type { TypedUnitOfWork } from "./unit-of-work";
|
|
24
26
|
|
|
25
27
|
// =============================================================================
|
|
26
28
|
// Helper types for extracting TxResult type parameters
|
|
@@ -552,6 +554,76 @@ describe("HandlerTxBuilder type inference", () => {
|
|
|
552
554
|
readonly [{ user: { id: string } }]
|
|
553
555
|
>();
|
|
554
556
|
});
|
|
557
|
+
|
|
558
|
+
it("widens serviceIntermediateResult when serviceCalls is a non-tuple array", () => {
|
|
559
|
+
type Status = { status: string };
|
|
560
|
+
type HistoryPage = { runNumber: number };
|
|
561
|
+
type StatusCall = TxResult<Status, Status>;
|
|
562
|
+
type RunNumberCall = TxResult<number, number>;
|
|
563
|
+
type HistoryCall = TxResult<HistoryPage, HistoryPage>;
|
|
564
|
+
|
|
565
|
+
// When serviceCalls are built dynamically (e.g. Array.from + spread),
|
|
566
|
+
// the tuple shape is lost and results widen to a union array.
|
|
567
|
+
type ServiceCalls = readonly (StatusCall | RunNumberCall | HistoryCall)[];
|
|
568
|
+
|
|
569
|
+
type Builder = HandlerTxBuilder<
|
|
570
|
+
ServiceCalls,
|
|
571
|
+
[],
|
|
572
|
+
[],
|
|
573
|
+
unknown,
|
|
574
|
+
unknown,
|
|
575
|
+
false,
|
|
576
|
+
false,
|
|
577
|
+
true, // HasMutate
|
|
578
|
+
false,
|
|
579
|
+
{}
|
|
580
|
+
>;
|
|
581
|
+
|
|
582
|
+
type MutateParam = Parameters<Builder["mutate"]>[0];
|
|
583
|
+
type MutateCtx = Parameters<MutateParam>[0];
|
|
584
|
+
|
|
585
|
+
expectTypeOf<MutateCtx["serviceIntermediateResult"]>().toEqualTypeOf<
|
|
586
|
+
readonly (Status | number | HistoryPage)[]
|
|
587
|
+
>();
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
it("preserves tuple inference for dynamic serviceCalls when using helper", () => {
|
|
591
|
+
type Status = { status: string };
|
|
592
|
+
type HistoryPage = { runNumber: number };
|
|
593
|
+
type StatusCall = TxResult<Status, Status>;
|
|
594
|
+
type RunNumberCall = TxResult<number, number>;
|
|
595
|
+
type HistoryCall = TxResult<HistoryPage, HistoryPage>;
|
|
596
|
+
|
|
597
|
+
const statusCall = null as unknown as StatusCall;
|
|
598
|
+
const runNumberCall = null as unknown as RunNumberCall;
|
|
599
|
+
const historyCalls = [] as HistoryCall[];
|
|
600
|
+
|
|
601
|
+
const calls = serviceCalls(statusCall, runNumberCall, ...historyCalls);
|
|
602
|
+
|
|
603
|
+
expectTypeOf<typeof calls>().toEqualTypeOf<
|
|
604
|
+
readonly [StatusCall, RunNumberCall, ...HistoryCall[]]
|
|
605
|
+
>();
|
|
606
|
+
|
|
607
|
+
type Builder = HandlerTxBuilder<
|
|
608
|
+
typeof calls,
|
|
609
|
+
[],
|
|
610
|
+
[],
|
|
611
|
+
unknown,
|
|
612
|
+
unknown,
|
|
613
|
+
false,
|
|
614
|
+
false,
|
|
615
|
+
true, // HasMutate
|
|
616
|
+
false,
|
|
617
|
+
{}
|
|
618
|
+
>;
|
|
619
|
+
|
|
620
|
+
type MutateParam = Parameters<Builder["mutate"]>[0];
|
|
621
|
+
type MutateCtx = Parameters<MutateParam>[0];
|
|
622
|
+
|
|
623
|
+
expectTypeOf<MutateCtx["serviceIntermediateResult"]>().toEqualTypeOf<
|
|
624
|
+
readonly [Status, number, ...HistoryPage[]]
|
|
625
|
+
>();
|
|
626
|
+
});
|
|
555
627
|
});
|
|
556
628
|
|
|
557
629
|
describe("retrieve + transformRetrieve flow", () => {
|