@fragno-dev/db 0.2.2 → 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 +404 -175
- package/CHANGELOG.md +109 -0
- package/README.md +54 -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 +24 -9
- package/dist/adapters/generic-sql/generic-sql-adapter.d.ts.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-adapter.js +60 -22
- package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-uow-executor.js +169 -3
- 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 +25 -6
- package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/postgres.js +7 -6
- package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/sqlite.js +193 -16
- 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 +9 -9
- package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -1
- package/dist/adapters/generic-sql/migration/sql-generator.js +75 -52
- package/dist/adapters/generic-sql/migration/sql-generator.js.map +1 -1
- package/dist/adapters/generic-sql/query/create-sql-query-compiler.js +7 -6
- 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/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 +32 -21
- 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 +49 -18
- package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -1
- package/dist/adapters/generic-sql/query/where-builder.js +43 -29
- 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 +6 -2
- package/dist/adapters/generic-sql/uow-decoder.js.map +1 -1
- package/dist/adapters/generic-sql/uow-encoder.js +27 -8
- package/dist/adapters/generic-sql/uow-encoder.js.map +1 -1
- package/dist/adapters/in-memory/condition-evaluator.js +135 -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 +196 -0
- package/dist/adapters/in-memory/in-memory-adapter.js.map +1 -0
- package/dist/adapters/in-memory/in-memory-uow.js +871 -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 +30 -0
- package/dist/adapters/in-memory/options.d.ts.map +1 -0
- package/dist/adapters/in-memory/options.js +62 -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 +51 -24
- 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/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 +101 -33
- package/dist/db-fragment-definition-builder.d.ts.map +1 -1
- package/dist/db-fragment-definition-builder.js +450 -60
- 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 +11 -0
- package/dist/dispatchers/cloudflare-do/index.d.ts.map +1 -0
- package/dist/dispatchers/cloudflare-do/index.js +31 -0
- package/dist/dispatchers/cloudflare-do/index.js.map +1 -0
- 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 +12 -0
- package/dist/dispatchers/node/index.d.ts.map +1 -0
- package/dist/dispatchers/node/index.js +27 -0
- package/dist/dispatchers/node/index.js.map +1 -0
- 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 +186 -8
- package/dist/fragments/internal-fragment.d.ts.map +1 -1
- package/dist/fragments/internal-fragment.js +203 -38
- package/dist/fragments/internal-fragment.js.map +1 -1
- package/dist/fragments/internal-fragment.routes.js +164 -0
- package/dist/fragments/internal-fragment.routes.js.map +1 -0
- package/dist/fragments/internal-fragment.schema.d.ts +15 -0
- package/dist/fragments/internal-fragment.schema.d.ts.map +1 -0
- package/dist/fragments/internal-fragment.schema.js +39 -0
- package/dist/fragments/internal-fragment.schema.js.map +1 -0
- 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 -0
- package/dist/hooks/durable-hooks-processor.js +80 -0
- package/dist/hooks/durable-hooks-processor.js.map +1 -0
- 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 +100 -1
- package/dist/hooks/hooks.d.ts.map +1 -1
- package/dist/hooks/hooks.js +254 -27
- 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 +223 -37
- 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 +86 -35
- 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 +20 -12
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +18 -12
- 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/outbox/outbox-builder.js +156 -0
- package/dist/outbox/outbox-builder.js.map +1 -0
- package/dist/outbox/outbox.d.ts +54 -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/query/column-defaults.js +20 -4
- 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 +3 -1
- package/dist/query/cursor.d.ts.map +1 -1
- package/dist/query/cursor.js +51 -14
- package/dist/query/cursor.js.map +1 -1
- package/dist/query/db-now.d.ts +22 -0
- package/dist/query/db-now.d.ts.map +1 -0
- package/dist/query/db-now.js +35 -0
- package/dist/query/db-now.js.map +1 -0
- package/dist/query/orm/orm.js.map +1 -1
- package/dist/query/serialize/create-sql-serializer.js +5 -4
- 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 +60 -12
- 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 +13 -4
- 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 +50 -24
- 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 +92 -30
- package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work/unit-of-work.js +136 -11
- package/dist/query/unit-of-work/unit-of-work.js.map +1 -1
- package/dist/query/value-decoding.js +16 -6
- 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 +103 -35
- package/dist/schema/create.d.ts.map +1 -1
- package/dist/schema/create.js +172 -58
- package/dist/schema/create.js.map +1 -1
- package/dist/schema/generate-id.js +2 -2
- package/dist/schema/generate-id.js.map +1 -1
- package/dist/schema/type-conversion/create-sql-type-mapper.js +4 -3
- 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} +88 -60
- 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 +307 -0
- package/dist/schema-output/prisma.js.map +1 -0
- 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 +66 -0
- package/dist/util/default-database-adapter.js.map +1 -0
- package/dist/with-database.d.ts +3 -6
- package/dist/with-database.d.ts.map +1 -1
- package/dist/with-database.js +8 -7
- package/dist/with-database.js.map +1 -1
- package/package.json +62 -55
- package/src/adapters/adapters.ts +33 -26
- package/src/adapters/drizzle/migrate-drizzle.test.ts +99 -41
- package/src/adapters/drizzle/migration-parity-drizzle-kit.test.ts +601 -0
- package/src/adapters/drizzle/test-utils.ts +13 -8
- package/src/adapters/generic-sql/driver-config.ts +38 -0
- package/src/adapters/generic-sql/generic-sql-adapter.test.ts +10 -8
- package/src/adapters/generic-sql/generic-sql-adapter.ts +117 -34
- package/src/adapters/generic-sql/generic-sql-uow-executor.test.ts +55 -0
- package/src/adapters/generic-sql/generic-sql-uow-executor.ts +297 -3
- package/src/adapters/generic-sql/migration/adapter-migration-parity.test.ts +120 -0
- package/src/adapters/generic-sql/migration/cold-kysely.ts +1 -0
- package/src/adapters/generic-sql/migration/dialect/mysql.test.ts +27 -8
- package/src/adapters/generic-sql/migration/dialect/mysql.ts +47 -8
- package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +28 -9
- package/src/adapters/generic-sql/migration/dialect/postgres.ts +9 -4
- package/src/adapters/generic-sql/migration/dialect/sqlite.test.ts +839 -8
- package/src/adapters/generic-sql/migration/dialect/sqlite.ts +396 -53
- 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 +238 -46
- package/src/adapters/generic-sql/migration/prepared-migrations.ts +21 -13
- package/src/adapters/generic-sql/migration/sql-generator.ts +145 -66
- package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +11 -8
- package/src/adapters/generic-sql/query/cursor-utils.test.ts +272 -0
- package/src/adapters/generic-sql/query/cursor-utils.ts +42 -7
- 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 +171 -35
- package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +53 -40
- package/src/adapters/generic-sql/query/select-builder.test.ts +16 -11
- package/src/adapters/generic-sql/query/select-builder.ts +7 -3
- package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +75 -6
- package/src/adapters/generic-sql/query/sql-query-compiler.ts +129 -24
- package/src/adapters/generic-sql/query/where-builder.test.ts +96 -20
- package/src/adapters/generic-sql/query/where-builder.ts +112 -41
- package/src/adapters/{kysely/kysely-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-migrations.test.ts} +11 -20
- package/src/adapters/generic-sql/sql-adapter-pglite-pagination.test.ts +851 -0
- package/src/adapters/{drizzle/drizzle-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-queries.test.ts} +18 -15
- package/src/adapters/generic-sql/{test/generic-drizzle-adapter-sqlite3.test.ts → sql-adapter-sqlite3-driver.test.ts} +282 -14
- package/src/adapters/{drizzle/drizzle-adapter-sqlite3.test.ts → generic-sql/sql-adapter-sqlite3-uow.test.ts} +129 -12
- package/src/adapters/{kysely/kysely-adapter-sqlocal.test.ts → generic-sql/sql-adapter-sqlocal.test.ts} +9 -7
- package/src/adapters/generic-sql/sqlite-storage.ts +20 -0
- package/src/adapters/generic-sql/uow-decoder.test.ts +5 -4
- package/src/adapters/generic-sql/uow-decoder.ts +23 -5
- package/src/adapters/generic-sql/uow-encoder.test.ts +36 -3
- package/src/adapters/generic-sql/uow-encoder.ts +48 -13
- package/src/adapters/in-memory/condition-evaluator.test.ts +194 -0
- package/src/adapters/in-memory/condition-evaluator.ts +280 -0
- package/src/adapters/in-memory/errors.ts +20 -0
- package/src/adapters/in-memory/in-memory-adapter.ts +388 -0
- package/src/adapters/in-memory/in-memory-uow.mutations.test.ts +344 -0
- package/src/adapters/in-memory/in-memory-uow.retrieval.test.ts +255 -0
- package/src/adapters/in-memory/in-memory-uow.ts +1724 -0
- package/src/adapters/in-memory/index.ts +3 -0
- package/src/adapters/in-memory/options.test.ts +42 -0
- package/src/adapters/in-memory/options.ts +91 -0
- package/src/adapters/in-memory/outbox.test.ts +361 -0
- package/src/adapters/in-memory/reference-resolution.test.ts +51 -0
- package/src/adapters/in-memory/reference-resolution.ts +67 -0
- package/src/adapters/in-memory/sorted-array-index.test.ts +124 -0
- package/src/adapters/in-memory/sorted-array-index.ts +228 -0
- package/src/adapters/in-memory/store.test.ts +69 -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 +58 -0
- package/src/adapters/prisma/prisma-adapter-sqlite3.test.ts +1207 -0
- package/src/adapters/shared/from-unit-of-work-compiler.ts +159 -47
- package/src/adapters/shared/uow-operation-compiler.ts +28 -18
- package/src/adapters/sql/index.ts +12 -0
- package/src/browser/mod.ts +64 -0
- package/src/client.ts +19 -0
- package/src/db-fragment-definition-builder.test.ts +845 -53
- package/src/db-fragment-definition-builder.ts +911 -95
- package/src/db-fragment-instantiator.test.ts +210 -94
- package/src/db-fragment-integration.test.ts +17 -12
- package/src/dispatchers/cloudflare-do/dispatcher.ts +204 -0
- package/src/dispatchers/cloudflare-do/index.test.ts +206 -0
- package/src/dispatchers/cloudflare-do/index.ts +63 -0
- package/src/dispatchers/node/dispatcher.ts +112 -0
- package/src/dispatchers/node/index.test.ts +120 -0
- package/src/dispatchers/node/index.ts +50 -0
- 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 +334 -0
- package/src/fragments/internal-fragment.schema.ts +95 -0
- package/src/fragments/internal-fragment.test.ts +505 -83
- package/src/fragments/internal-fragment.ts +453 -70
- 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 +282 -0
- package/src/hooks/durable-hooks-processor.ts +173 -0
- 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 +455 -34
- package/src/hooks/hooks.ts +501 -34
- 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 +107 -14
- package/src/migration-engine/auto-from-schema.ts +365 -44
- package/src/migration-engine/create.test.ts +4 -3
- package/src/migration-engine/create.ts +1 -1
- package/src/migration-engine/generation-engine.test.ts +292 -110
- package/src/migration-engine/generation-engine.ts +117 -66
- package/src/migration-engine/shared.ts +14 -0
- package/src/mod.ts +95 -39
- package/src/naming/sql-naming.ts +181 -0
- package/src/outbox/outbox-builder.ts +241 -0
- package/src/outbox/outbox.test.ts +424 -0
- package/src/outbox/outbox.ts +139 -0
- package/src/query/column-defaults.ts +42 -4
- package/src/query/condition-builder.test.ts +18 -3
- 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 +119 -20
- package/src/query/cursor.ts +88 -27
- package/src/query/db-now.ts +73 -0
- package/src/query/orm/orm.ts +2 -2
- package/src/query/query-type.test.ts +4 -3
- package/src/query/serialize/create-sql-serializer.ts +10 -5
- package/src/query/serialize/dialect/mysql-serializer.ts +13 -5
- package/src/query/serialize/dialect/postgres-serializer.ts +35 -5
- package/src/query/serialize/dialect/sqlite-serializer.test.ts +90 -3
- package/src/query/serialize/dialect/sqlite-serializer.ts +108 -12
- package/src/query/serialize/sql-serializer.ts +4 -4
- package/src/query/simple-query-interface.ts +15 -4
- package/src/query/unit-of-work/execute-unit-of-work.test.ts +372 -10
- package/src/query/unit-of-work/execute-unit-of-work.ts +87 -27
- 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 +17 -16
- package/src/query/unit-of-work/unit-of-work-types.test.ts +42 -12
- package/src/query/unit-of-work/unit-of-work.test.ts +196 -39
- package/src/query/unit-of-work/unit-of-work.ts +309 -38
- package/src/query/value-decoding.test.ts +63 -4
- package/src/query/value-decoding.ts +32 -6
- package/src/query/value-encoding.test.ts +86 -2
- package/src/query/value-encoding.ts +56 -6
- package/src/schema/create.test.ts +293 -47
- package/src/schema/create.ts +406 -70
- package/src/schema/generate-id.test.ts +3 -2
- package/src/schema/generate-id.ts +2 -2
- package/src/schema/serialize.test.ts +18 -5
- package/src/schema/type-conversion/create-sql-type-mapper.ts +8 -3
- package/src/schema/type-conversion/dialect/sqlite.ts +18 -0
- package/src/schema/type-conversion/type-mapping.test.ts +26 -1
- package/src/schema/validator.test.ts +199 -0
- package/src/schema/validator.ts +232 -0
- package/src/{adapters/drizzle/generate.test.ts → schema-output/drizzle.test.ts} +232 -129
- package/src/{adapters/drizzle/generate.ts → schema-output/drizzle.ts} +155 -99
- package/src/schema-output/prisma.test.ts +694 -0
- package/src/schema-output/prisma.ts +593 -0
- 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 +119 -0
- package/src/with-database.ts +20 -31
- package/tsconfig.json +1 -1
- package/tsdown.config.ts +38 -24
- package/vitest.config.ts +1 -0
- 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 +0 -165
- package/dist/node_modules/.pnpm/rou3@0.7.10/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 -320
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +0 -1
- package/dist/packages/fragno/dist/api/fragment-instantiator.js +0 -525
- 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 -118
- 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 -17
- 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/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
|
@@ -1,17 +1,37 @@
|
|
|
1
1
|
import { describe, it, expect, vi, expectTypeOf } from "vitest";
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
|
|
7
|
+
import { RequestContextStorage } from "@fragno-dev/core/internal/request-context-storage";
|
|
8
|
+
import SQLite from "better-sqlite3";
|
|
9
|
+
import { SqliteDialect } from "kysely";
|
|
10
|
+
|
|
11
|
+
import { defineFragment, instantiate } from "@fragno-dev/core";
|
|
12
|
+
|
|
13
|
+
import type { DatabaseAdapter, DatabaseContextStorage } from "./adapters/adapters";
|
|
14
|
+
import { BetterSQLite3DriverConfig } from "./adapters/generic-sql/driver-config";
|
|
15
|
+
import { SqlAdapter } from "./adapters/generic-sql/generic-sql-adapter";
|
|
3
16
|
import {
|
|
4
17
|
DatabaseFragmentDefinitionBuilder,
|
|
5
18
|
type ImplicitDatabaseDependencies,
|
|
6
19
|
} from "./db-fragment-definition-builder";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
20
|
+
import { internalSchema } from "./fragments/internal-fragment";
|
|
21
|
+
import { getDurableHooksRuntimeByToken } from "./hooks/durable-hooks-runtime";
|
|
22
|
+
import type { HookFn } from "./hooks/hooks";
|
|
23
|
+
import * as hooks from "./hooks/hooks";
|
|
24
|
+
import { getInternalFragment, getRegistryForAdapterSync } from "./internal/adapter-registry";
|
|
25
|
+
import { suffixNamingStrategy, sanitizeNamespace } from "./naming/sql-naming";
|
|
9
26
|
import type { SimpleQueryInterface } from "./query/simple-query-interface";
|
|
10
|
-
import type { DatabaseAdapter } from "./adapters/adapters";
|
|
11
27
|
import * as executeUnitOfWork from "./query/unit-of-work/execute-unit-of-work";
|
|
28
|
+
import type { IUnitOfWork } from "./query/unit-of-work/unit-of-work";
|
|
29
|
+
import { schema, column, idColumn } from "./schema/create";
|
|
30
|
+
import { defineSyncCommands } from "./sync/commands";
|
|
31
|
+
import { withDatabase } from "./with-database";
|
|
12
32
|
|
|
13
33
|
// Create a test schema
|
|
14
|
-
const testSchema = schema((s) => {
|
|
34
|
+
const testSchema = schema("test", (s) => {
|
|
15
35
|
return s.addTable("users", (t) => {
|
|
16
36
|
return t
|
|
17
37
|
.addColumn("id", idColumn())
|
|
@@ -24,18 +44,25 @@ type TestSchema = typeof testSchema;
|
|
|
24
44
|
|
|
25
45
|
// Mock database adapter
|
|
26
46
|
function createMockAdapter(): DatabaseAdapter {
|
|
47
|
+
const createMockUow = () => ({
|
|
48
|
+
forSchema: vi.fn(),
|
|
49
|
+
executeRetrieve: vi.fn(),
|
|
50
|
+
executeMutations: vi.fn(),
|
|
51
|
+
registerSchema: vi.fn(),
|
|
52
|
+
reset: vi.fn(),
|
|
53
|
+
});
|
|
54
|
+
|
|
27
55
|
const mockdb = {
|
|
28
|
-
createUnitOfWork: vi.fn(() => (
|
|
29
|
-
|
|
30
|
-
executeRetrieve: vi.fn(),
|
|
31
|
-
executeMutations: vi.fn(),
|
|
32
|
-
})),
|
|
56
|
+
createUnitOfWork: vi.fn(() => createMockUow()),
|
|
57
|
+
createBaseUnitOfWork: vi.fn(() => createMockUow()),
|
|
33
58
|
} as unknown as SimpleQueryInterface<TestSchema>;
|
|
34
59
|
|
|
35
60
|
return {
|
|
36
61
|
createQueryEngine: vi.fn(() => mockdb),
|
|
37
|
-
|
|
62
|
+
getSchemaVersion: vi.fn(async () => undefined),
|
|
38
63
|
close: vi.fn(),
|
|
64
|
+
contextStorage: new RequestContextStorage(),
|
|
65
|
+
namingStrategy: suffixNamingStrategy,
|
|
39
66
|
} as unknown as DatabaseAdapter;
|
|
40
67
|
}
|
|
41
68
|
|
|
@@ -78,8 +105,8 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
78
105
|
|
|
79
106
|
const definition = defineFragment("test-frag")
|
|
80
107
|
.extend(withDatabase(testSchema))
|
|
81
|
-
.withDependencies(({
|
|
82
|
-
expect(
|
|
108
|
+
.withDependencies(({ databaseAdapter }) => {
|
|
109
|
+
expect(databaseAdapter).toBeDefined();
|
|
83
110
|
return {
|
|
84
111
|
customDep: "value",
|
|
85
112
|
};
|
|
@@ -92,7 +119,8 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
92
119
|
});
|
|
93
120
|
|
|
94
121
|
expect(deps.customDep).toBe("value");
|
|
95
|
-
expect(deps.
|
|
122
|
+
expect(deps.databaseAdapter).toBeDefined();
|
|
123
|
+
expect(deps.createUnitOfWork).toBeDefined();
|
|
96
124
|
expect(deps.schema).toBeDefined();
|
|
97
125
|
});
|
|
98
126
|
|
|
@@ -112,7 +140,8 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
112
140
|
});
|
|
113
141
|
|
|
114
142
|
expect(deps.apiKey).toBe("key123");
|
|
115
|
-
expect(deps.
|
|
143
|
+
expect(deps.databaseAdapter).toBeDefined();
|
|
144
|
+
expect(deps.createUnitOfWork).toBeDefined();
|
|
116
145
|
expect(deps.schema).toBeDefined();
|
|
117
146
|
});
|
|
118
147
|
|
|
@@ -122,7 +151,7 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
122
151
|
const definition = defineFragment("test-frag")
|
|
123
152
|
.extend(withDatabase(testSchema))
|
|
124
153
|
.providesService("users", ({ deps }) => {
|
|
125
|
-
expect(deps.
|
|
154
|
+
expect(deps.databaseAdapter).toBeDefined();
|
|
126
155
|
return {
|
|
127
156
|
list: () => "users list",
|
|
128
157
|
};
|
|
@@ -155,7 +184,7 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
155
184
|
}))
|
|
156
185
|
.extend(withDatabase(testSchema))
|
|
157
186
|
.providesService("users", ({ deps }) => {
|
|
158
|
-
expect(deps.
|
|
187
|
+
expect(deps.databaseAdapter).toBeDefined();
|
|
159
188
|
return {
|
|
160
189
|
list: () => "users list",
|
|
161
190
|
};
|
|
@@ -229,7 +258,7 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
229
258
|
const definition = defineFragment("test-frag")
|
|
230
259
|
.extend(withDatabase(testSchema))
|
|
231
260
|
.providesBaseService(({ deps }) => {
|
|
232
|
-
expect(deps.
|
|
261
|
+
expect(deps.databaseAdapter).toBeDefined();
|
|
233
262
|
return {
|
|
234
263
|
healthCheck: () => "healthy",
|
|
235
264
|
};
|
|
@@ -262,7 +291,7 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
262
291
|
}))
|
|
263
292
|
.extend(withDatabase(testSchema))
|
|
264
293
|
.providesBaseService(({ deps }) => {
|
|
265
|
-
expect(deps.
|
|
294
|
+
expect(deps.databaseAdapter).toBeDefined();
|
|
266
295
|
return {
|
|
267
296
|
status: () => "ok",
|
|
268
297
|
};
|
|
@@ -297,8 +326,8 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
297
326
|
|
|
298
327
|
const definition = defineFragment("test-frag")
|
|
299
328
|
.extend(withDatabase(testSchema))
|
|
300
|
-
.withDependencies(({
|
|
301
|
-
expect(
|
|
329
|
+
.withDependencies(({ databaseAdapter }) => {
|
|
330
|
+
expect(databaseAdapter).toBeDefined();
|
|
302
331
|
return {
|
|
303
332
|
apiKey: "secret",
|
|
304
333
|
};
|
|
@@ -313,7 +342,7 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
313
342
|
},
|
|
314
343
|
}))
|
|
315
344
|
.providesService("data", ({ deps }) => {
|
|
316
|
-
expect(deps.
|
|
345
|
+
expect(deps.databaseAdapter).toBeDefined();
|
|
317
346
|
return {
|
|
318
347
|
fetch: () => `Fetching with ${deps.apiKey}`,
|
|
319
348
|
};
|
|
@@ -366,15 +395,15 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
366
395
|
baseConfig: "config1",
|
|
367
396
|
}))
|
|
368
397
|
.extend(withDatabase(testSchema))
|
|
369
|
-
.withDependencies(({
|
|
370
|
-
expect(
|
|
398
|
+
.withDependencies(({ databaseAdapter }) => {
|
|
399
|
+
expect(databaseAdapter).toBeDefined();
|
|
371
400
|
// Second withDependencies replaces the first one
|
|
372
401
|
return {
|
|
373
402
|
enhancedConfig: "enhanced",
|
|
374
403
|
};
|
|
375
404
|
})
|
|
376
405
|
.providesService("combined", ({ deps }) => {
|
|
377
|
-
expect(deps.
|
|
406
|
+
expect(deps.databaseAdapter).toBeDefined();
|
|
378
407
|
return {
|
|
379
408
|
getConfig: () => deps.enhancedConfig,
|
|
380
409
|
};
|
|
@@ -389,7 +418,7 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
389
418
|
// Only the second withDependencies is used (plus implicit deps)
|
|
390
419
|
expect(deps).not.toHaveProperty("baseConfig");
|
|
391
420
|
expect(deps.enhancedConfig).toBe("enhanced");
|
|
392
|
-
expect(deps.
|
|
421
|
+
expect(deps.databaseAdapter).toBeDefined();
|
|
393
422
|
|
|
394
423
|
const combinedService = definition.namedServices!.combined({
|
|
395
424
|
config: {},
|
|
@@ -419,9 +448,9 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
419
448
|
};
|
|
420
449
|
})
|
|
421
450
|
.extend(withDatabase(testSchema))
|
|
422
|
-
.withDependencies(({ config,
|
|
451
|
+
.withDependencies(({ config, databaseAdapter }) => {
|
|
423
452
|
expectTypeOf(config).toExtend<MyConfig>();
|
|
424
|
-
expect(
|
|
453
|
+
expect(databaseAdapter).toBeDefined();
|
|
425
454
|
// Second withDependencies replaces the first, so combine them here
|
|
426
455
|
return {
|
|
427
456
|
connectionTimeout: config.timeout,
|
|
@@ -437,7 +466,7 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
437
466
|
|
|
438
467
|
expect(deps.connectionTimeout).toBe(5000);
|
|
439
468
|
expect(deps.dbConnectionString).toBe("postgres://localhost");
|
|
440
|
-
expect(deps.
|
|
469
|
+
expect(deps.databaseAdapter).toBeDefined();
|
|
441
470
|
});
|
|
442
471
|
|
|
443
472
|
it("recommended pattern: extend first then configure", () => {
|
|
@@ -454,8 +483,8 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
454
483
|
// Best practice: .extend() early, then add all your features
|
|
455
484
|
const definition = defineFragment("best-practice")
|
|
456
485
|
.extend(withDatabase(testSchema))
|
|
457
|
-
.withDependencies(({
|
|
458
|
-
expect(
|
|
486
|
+
.withDependencies(({ databaseAdapter }) => {
|
|
487
|
+
expect(databaseAdapter).toBeDefined();
|
|
459
488
|
return {
|
|
460
489
|
apiKey: "secret",
|
|
461
490
|
timeout: 5000,
|
|
@@ -465,7 +494,7 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
465
494
|
.usesOptionalService<"auth", AuthService>("auth")
|
|
466
495
|
.providesBaseService(({ deps }) => ({
|
|
467
496
|
healthCheck: () => {
|
|
468
|
-
expect(deps.
|
|
497
|
+
expect(deps.databaseAdapter).toBeDefined();
|
|
469
498
|
return `OK (timeout: ${deps.timeout})`;
|
|
470
499
|
},
|
|
471
500
|
}))
|
|
@@ -488,7 +517,7 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
488
517
|
// Verify all dependencies including implicit ones
|
|
489
518
|
expect(deps.apiKey).toBe("secret");
|
|
490
519
|
expect(deps.timeout).toBe(5000);
|
|
491
|
-
expect(deps.
|
|
520
|
+
expect(deps.databaseAdapter).toBeDefined();
|
|
492
521
|
expect(deps.schema).toBeDefined();
|
|
493
522
|
expect(deps.createUnitOfWork).toBeDefined();
|
|
494
523
|
|
|
@@ -528,8 +557,7 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
528
557
|
const mockAdapter = createMockAdapter();
|
|
529
558
|
|
|
530
559
|
const definition = withDatabase(testSchema)(defineFragment("db-frag"))
|
|
531
|
-
.withDependencies(({
|
|
532
|
-
expect(db).toBeDefined();
|
|
560
|
+
.withDependencies(({ databaseAdapter }) => {
|
|
533
561
|
expect(databaseAdapter).toBeDefined();
|
|
534
562
|
return {
|
|
535
563
|
customDep: "test",
|
|
@@ -546,7 +574,7 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
546
574
|
});
|
|
547
575
|
|
|
548
576
|
// Should have implicit deps
|
|
549
|
-
expect(deps).toHaveProperty("
|
|
577
|
+
expect(deps).toHaveProperty("databaseAdapter");
|
|
550
578
|
expect(deps).toHaveProperty("schema");
|
|
551
579
|
expect(deps).toHaveProperty("createUnitOfWork");
|
|
552
580
|
expect(deps).toHaveProperty("customDep");
|
|
@@ -567,7 +595,7 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
567
595
|
});
|
|
568
596
|
|
|
569
597
|
// Check implicit dependencies structure
|
|
570
|
-
expect(deps.
|
|
598
|
+
expect(deps.databaseAdapter).toBeDefined();
|
|
571
599
|
expect(deps.schema).toBeDefined();
|
|
572
600
|
expect(typeof deps.createUnitOfWork).toBe("function");
|
|
573
601
|
});
|
|
@@ -581,7 +609,7 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
581
609
|
.withDependencies(() => ({ apiKey: "key" }))
|
|
582
610
|
.providesBaseService(({ deps, defineService }) => {
|
|
583
611
|
expect(deps.apiKey).toBe("key");
|
|
584
|
-
expect(deps.
|
|
612
|
+
expect(deps.databaseAdapter).toBeDefined();
|
|
585
613
|
expect(defineService).toBeDefined();
|
|
586
614
|
|
|
587
615
|
return defineService({
|
|
@@ -678,6 +706,43 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
678
706
|
});
|
|
679
707
|
});
|
|
680
708
|
|
|
709
|
+
describe("withSyncCommands", () => {
|
|
710
|
+
it("registers sync commands in adapter registry", async () => {
|
|
711
|
+
const sqlite = new SQLite(":memory:");
|
|
712
|
+
const adapter = new SqlAdapter({
|
|
713
|
+
dialect: new SqliteDialect({ database: sqlite }),
|
|
714
|
+
driverConfig: new BetterSQLite3DriverConfig(),
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
const registry = getRegistryForAdapterSync(adapter);
|
|
718
|
+
const syncCommands = defineSyncCommands({ schema: testSchema }).create(
|
|
719
|
+
({ defineCommand }) => [
|
|
720
|
+
defineCommand({
|
|
721
|
+
name: "ping",
|
|
722
|
+
handler: async () => undefined,
|
|
723
|
+
}),
|
|
724
|
+
],
|
|
725
|
+
);
|
|
726
|
+
|
|
727
|
+
const definition = defineFragment("sync-frag")
|
|
728
|
+
.extend(withDatabase(testSchema))
|
|
729
|
+
.withSyncCommands(syncCommands)
|
|
730
|
+
.build();
|
|
731
|
+
|
|
732
|
+
definition.dependencies!({
|
|
733
|
+
config: {},
|
|
734
|
+
options: { databaseAdapter: adapter },
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
const resolved = registry.resolveSyncCommand("sync-frag", testSchema.name, "ping");
|
|
738
|
+
expect(resolved?.command).toBe(syncCommands.commands.get("ping"));
|
|
739
|
+
expect(resolved?.namespace).toBe(sanitizeNamespace(testSchema.name));
|
|
740
|
+
|
|
741
|
+
await adapter.close();
|
|
742
|
+
sqlite.close();
|
|
743
|
+
});
|
|
744
|
+
});
|
|
745
|
+
|
|
681
746
|
describe("createRequestStorage and createThisContext", () => {
|
|
682
747
|
it("should create request storage with UnitOfWork", () => {
|
|
683
748
|
const mockAdapter = createMockAdapter();
|
|
@@ -735,10 +800,7 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
735
800
|
|
|
736
801
|
const mockAdapter = createMockAdapter();
|
|
737
802
|
|
|
738
|
-
const definition = withDatabase(
|
|
739
|
-
testSchema,
|
|
740
|
-
"my-namespace",
|
|
741
|
-
)(defineFragment<Config>("complex-db-frag"))
|
|
803
|
+
const definition = withDatabase(testSchema)(defineFragment<Config>("complex-db-frag"))
|
|
742
804
|
.withDependencies(({ config }) => ({
|
|
743
805
|
connectionString: config.dbConnectionString,
|
|
744
806
|
debug: config.debug,
|
|
@@ -806,17 +868,29 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
806
868
|
});
|
|
807
869
|
});
|
|
808
870
|
|
|
809
|
-
describe("
|
|
810
|
-
it("should
|
|
871
|
+
describe("default adapter", () => {
|
|
872
|
+
it("should default to sqlite adapter when database adapter is missing", () => {
|
|
873
|
+
const previous = process.env["FRAGNO_DATA_DIR"];
|
|
874
|
+
const dataDir = fs.mkdtempSync(path.join(os.tmpdir(), "fragno-db-default-"));
|
|
875
|
+
process.env["FRAGNO_DATA_DIR"] = dataDir;
|
|
876
|
+
|
|
811
877
|
const definition = withDatabase(testSchema)(defineFragment("db-frag")).build();
|
|
812
878
|
|
|
813
|
-
|
|
814
|
-
definition.dependencies!({
|
|
879
|
+
try {
|
|
880
|
+
const deps = definition.dependencies!({
|
|
815
881
|
config: {},
|
|
816
|
-
// @ts-expect-error No databaseAdapter - intentionally invalid for runtime error test
|
|
817
882
|
options: {},
|
|
818
883
|
});
|
|
819
|
-
|
|
884
|
+
|
|
885
|
+
expect(deps.databaseAdapter).toBeDefined();
|
|
886
|
+
expect(deps.createUnitOfWork).toBeDefined();
|
|
887
|
+
} finally {
|
|
888
|
+
if (previous === undefined) {
|
|
889
|
+
delete process.env["FRAGNO_DATA_DIR"];
|
|
890
|
+
} else {
|
|
891
|
+
process.env["FRAGNO_DATA_DIR"] = previous;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
820
894
|
});
|
|
821
895
|
});
|
|
822
896
|
|
|
@@ -842,7 +916,7 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
842
916
|
>();
|
|
843
917
|
|
|
844
918
|
expect(deps.customDep).toBe("test");
|
|
845
|
-
expect(deps.
|
|
919
|
+
expect(deps.databaseAdapter).toBeDefined();
|
|
846
920
|
});
|
|
847
921
|
});
|
|
848
922
|
|
|
@@ -870,21 +944,31 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
870
944
|
getStore: () => ({
|
|
871
945
|
uow: mockAdapter.createQueryEngine(testSchema, "test").createUnitOfWork(),
|
|
872
946
|
}),
|
|
873
|
-
|
|
874
|
-
} as any;
|
|
947
|
+
} as unknown as RequestContextStorage<DatabaseContextStorage>;
|
|
875
948
|
|
|
876
949
|
// Spy on createServiceTxBuilder
|
|
877
950
|
const createServiceTxBuilderSpy = vi.spyOn(executeUnitOfWork, "createServiceTxBuilder");
|
|
878
951
|
|
|
952
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
953
|
+
const deps = {} as any;
|
|
954
|
+
|
|
879
955
|
// Get the contexts which includes serviceTx
|
|
880
956
|
const contexts = definition.createThisContext!({
|
|
881
957
|
config: {},
|
|
882
958
|
options: { databaseAdapter: mockAdapter },
|
|
883
|
-
|
|
884
|
-
deps: {} as any,
|
|
959
|
+
deps,
|
|
885
960
|
storage: mockStorage,
|
|
886
961
|
});
|
|
887
962
|
|
|
963
|
+
// Initialize hooks with services so serviceTx receives the hooks map.
|
|
964
|
+
definition.internalDataFactory?.({
|
|
965
|
+
config: {},
|
|
966
|
+
options: { databaseAdapter: mockAdapter },
|
|
967
|
+
deps,
|
|
968
|
+
services: {} as Record<string, never>,
|
|
969
|
+
serviceDeps: {} as Record<string, never>,
|
|
970
|
+
});
|
|
971
|
+
|
|
888
972
|
// Call serviceTx - this should pass hooks to createServiceTxBuilder
|
|
889
973
|
contexts.serviceContext.serviceTx(testSchema);
|
|
890
974
|
|
|
@@ -900,4 +984,712 @@ describe("DatabaseFragmentDefinitionBuilder", () => {
|
|
|
900
984
|
createServiceTxBuilderSpy.mockRestore();
|
|
901
985
|
});
|
|
902
986
|
});
|
|
987
|
+
|
|
988
|
+
describe("provideHooks services access", () => {
|
|
989
|
+
it("should provide bound services to hooks factory", () => {
|
|
990
|
+
const mockAdapter = createMockAdapter();
|
|
991
|
+
let observed: string | null = null;
|
|
992
|
+
|
|
993
|
+
type TestHooks = {
|
|
994
|
+
onPing: HookFn;
|
|
995
|
+
};
|
|
996
|
+
|
|
997
|
+
const definition = defineFragment("db-frag-hooks-services")
|
|
998
|
+
.extend(withDatabase(testSchema))
|
|
999
|
+
.providesBaseService(() => ({
|
|
1000
|
+
ping: () => "pong",
|
|
1001
|
+
}))
|
|
1002
|
+
.provideHooks<TestHooks>(({ defineHook, services }) => {
|
|
1003
|
+
observed = services.ping();
|
|
1004
|
+
return {
|
|
1005
|
+
onPing: defineHook(async function () {
|
|
1006
|
+
// no-op
|
|
1007
|
+
}),
|
|
1008
|
+
};
|
|
1009
|
+
})
|
|
1010
|
+
.build();
|
|
1011
|
+
|
|
1012
|
+
const deps = definition.dependencies!({
|
|
1013
|
+
config: {},
|
|
1014
|
+
options: { databaseAdapter: mockAdapter },
|
|
1015
|
+
});
|
|
1016
|
+
|
|
1017
|
+
const internalData = definition.internalDataFactory?.({
|
|
1018
|
+
config: {},
|
|
1019
|
+
options: { databaseAdapter: mockAdapter },
|
|
1020
|
+
deps,
|
|
1021
|
+
services: { ping: () => "pong" },
|
|
1022
|
+
serviceDeps: {},
|
|
1023
|
+
}) as { durableHooksToken?: object } | undefined;
|
|
1024
|
+
|
|
1025
|
+
expect(observed).toBe("pong");
|
|
1026
|
+
expect(internalData?.durableHooksToken).toBeDefined();
|
|
1027
|
+
const runtime = internalData?.durableHooksToken
|
|
1028
|
+
? getDurableHooksRuntimeByToken(internalData.durableHooksToken)
|
|
1029
|
+
: undefined;
|
|
1030
|
+
expect(runtime?.config.hooks).toBeDefined();
|
|
1031
|
+
expect(runtime?.config.hooks).toHaveProperty("onPing");
|
|
1032
|
+
});
|
|
1033
|
+
});
|
|
1034
|
+
|
|
1035
|
+
describe("durable hooks waitUntil forwarding", () => {
|
|
1036
|
+
it("forwards request waitUntil to notifier context", async () => {
|
|
1037
|
+
const mockAdapter = createMockAdapter();
|
|
1038
|
+
const requestSourceSymbol = Symbol.for("fragno-request-source");
|
|
1039
|
+
const requestRouteSymbol = Symbol.for("fragno-request-route");
|
|
1040
|
+
const requestWaitUntilSymbol = Symbol.for("fragno-request-wait-until");
|
|
1041
|
+
const notifySpy = vi.fn().mockResolvedValue(undefined);
|
|
1042
|
+
const waitUntilSpy = vi.fn();
|
|
1043
|
+
|
|
1044
|
+
type TestHooks = {
|
|
1045
|
+
onPing: HookFn<{ value: string }>;
|
|
1046
|
+
};
|
|
1047
|
+
|
|
1048
|
+
const definition = defineFragment("db-frag-hooks-waituntil")
|
|
1049
|
+
.extend(withDatabase(testSchema))
|
|
1050
|
+
.provideHooks<TestHooks>(({ defineHook }) => ({
|
|
1051
|
+
onPing: defineHook(async function () {
|
|
1052
|
+
// no-op
|
|
1053
|
+
}),
|
|
1054
|
+
}))
|
|
1055
|
+
.build();
|
|
1056
|
+
|
|
1057
|
+
const deps = definition.dependencies!({
|
|
1058
|
+
config: {},
|
|
1059
|
+
options: { databaseAdapter: mockAdapter },
|
|
1060
|
+
});
|
|
1061
|
+
|
|
1062
|
+
const internalData = definition.internalDataFactory?.({
|
|
1063
|
+
config: {},
|
|
1064
|
+
options: { databaseAdapter: mockAdapter },
|
|
1065
|
+
deps,
|
|
1066
|
+
services: {} as Record<string, never>,
|
|
1067
|
+
serviceDeps: {} as Record<string, never>,
|
|
1068
|
+
}) as { durableHooksToken?: object } | undefined;
|
|
1069
|
+
|
|
1070
|
+
const runtime = internalData?.durableHooksToken
|
|
1071
|
+
? getDurableHooksRuntimeByToken(internalData.durableHooksToken)
|
|
1072
|
+
: undefined;
|
|
1073
|
+
if (!runtime) {
|
|
1074
|
+
throw new Error("Durable hooks runtime missing");
|
|
1075
|
+
}
|
|
1076
|
+
runtime.config.notifier = {
|
|
1077
|
+
notify: notifySpy,
|
|
1078
|
+
};
|
|
1079
|
+
|
|
1080
|
+
const createHandlerTxBuilderSpy = vi
|
|
1081
|
+
.spyOn(executeUnitOfWork, "createHandlerTxBuilder")
|
|
1082
|
+
.mockReturnValue(
|
|
1083
|
+
{} as unknown as ReturnType<typeof executeUnitOfWork.createHandlerTxBuilder>,
|
|
1084
|
+
);
|
|
1085
|
+
|
|
1086
|
+
const mockStorage = {
|
|
1087
|
+
getStore: () => ({
|
|
1088
|
+
uow: mockAdapter.createQueryEngine(testSchema, "test").createUnitOfWork(),
|
|
1089
|
+
[requestSourceSymbol]: "route",
|
|
1090
|
+
[requestRouteSymbol]: { method: "POST", path: "/users" },
|
|
1091
|
+
[requestWaitUntilSymbol]: waitUntilSpy,
|
|
1092
|
+
}),
|
|
1093
|
+
} as unknown as RequestContextStorage<DatabaseContextStorage>;
|
|
1094
|
+
|
|
1095
|
+
const contexts = definition.createThisContext!({
|
|
1096
|
+
config: {},
|
|
1097
|
+
options: { databaseAdapter: mockAdapter },
|
|
1098
|
+
deps,
|
|
1099
|
+
storage: mockStorage,
|
|
1100
|
+
});
|
|
1101
|
+
|
|
1102
|
+
contexts.handlerContext.handlerTx();
|
|
1103
|
+
const callArgs = createHandlerTxBuilderSpy.mock.calls[0]?.[0];
|
|
1104
|
+
const mockUow = {
|
|
1105
|
+
getTriggeredHooks: () => [
|
|
1106
|
+
{
|
|
1107
|
+
namespace: runtime.config.namespace,
|
|
1108
|
+
hookName: "onPing",
|
|
1109
|
+
payload: { value: "ping" },
|
|
1110
|
+
},
|
|
1111
|
+
],
|
|
1112
|
+
} as unknown as IUnitOfWork;
|
|
1113
|
+
await callArgs?.onAfterMutate?.(mockUow);
|
|
1114
|
+
|
|
1115
|
+
expect(notifySpy).toHaveBeenCalledTimes(1);
|
|
1116
|
+
const notifyContext = notifySpy.mock.calls[0]?.[0] as
|
|
1117
|
+
| { route?: string; source?: string; waitUntil?: unknown }
|
|
1118
|
+
| undefined;
|
|
1119
|
+
expect(notifyContext).toMatchObject({
|
|
1120
|
+
source: "request",
|
|
1121
|
+
route: "POST /users",
|
|
1122
|
+
});
|
|
1123
|
+
expect(notifyContext?.waitUntil).toBe(waitUntilSpy);
|
|
1124
|
+
expect(waitUntilSpy).toHaveBeenCalledTimes(1);
|
|
1125
|
+
|
|
1126
|
+
createHandlerTxBuilderSpy.mockRestore();
|
|
1127
|
+
});
|
|
1128
|
+
|
|
1129
|
+
it("forwards inherited request waitUntil for hook mutations", async () => {
|
|
1130
|
+
const mockAdapter = createMockAdapter();
|
|
1131
|
+
const requestWaitUntilSymbol = Symbol.for("fragno-request-wait-until");
|
|
1132
|
+
const notifySpy = vi.fn().mockResolvedValue(undefined);
|
|
1133
|
+
const waitUntilSpy = vi.fn();
|
|
1134
|
+
|
|
1135
|
+
type TestHooks = {
|
|
1136
|
+
onPing: HookFn<{ value: string }>;
|
|
1137
|
+
};
|
|
1138
|
+
|
|
1139
|
+
const definition = defineFragment("db-frag-hooks-hook-waituntil")
|
|
1140
|
+
.extend(withDatabase(testSchema))
|
|
1141
|
+
.provideHooks<TestHooks>(({ defineHook }) => ({
|
|
1142
|
+
onPing: defineHook(async function () {
|
|
1143
|
+
// no-op
|
|
1144
|
+
}),
|
|
1145
|
+
}))
|
|
1146
|
+
.build();
|
|
1147
|
+
|
|
1148
|
+
const deps = definition.dependencies!({
|
|
1149
|
+
config: {},
|
|
1150
|
+
options: { databaseAdapter: mockAdapter },
|
|
1151
|
+
});
|
|
1152
|
+
|
|
1153
|
+
const internalData = definition.internalDataFactory?.({
|
|
1154
|
+
config: {},
|
|
1155
|
+
options: { databaseAdapter: mockAdapter },
|
|
1156
|
+
deps,
|
|
1157
|
+
services: {} as Record<string, never>,
|
|
1158
|
+
serviceDeps: {} as Record<string, never>,
|
|
1159
|
+
}) as { durableHooksToken?: object } | undefined;
|
|
1160
|
+
|
|
1161
|
+
const runtime = internalData?.durableHooksToken
|
|
1162
|
+
? getDurableHooksRuntimeByToken(internalData.durableHooksToken)
|
|
1163
|
+
: undefined;
|
|
1164
|
+
if (!runtime) {
|
|
1165
|
+
throw new Error("Durable hooks runtime missing");
|
|
1166
|
+
}
|
|
1167
|
+
runtime.config.notifier = {
|
|
1168
|
+
notify: notifySpy,
|
|
1169
|
+
};
|
|
1170
|
+
|
|
1171
|
+
const createHandlerTxBuilderSpy = vi
|
|
1172
|
+
.spyOn(executeUnitOfWork, "createHandlerTxBuilder")
|
|
1173
|
+
.mockImplementation((options) => {
|
|
1174
|
+
return {
|
|
1175
|
+
execute: vi.fn(async () => {
|
|
1176
|
+
const mockUow = {
|
|
1177
|
+
getTriggeredHooks: () => [
|
|
1178
|
+
{
|
|
1179
|
+
namespace: runtime.config.namespace,
|
|
1180
|
+
hookName: "onPing",
|
|
1181
|
+
payload: { value: "ping" },
|
|
1182
|
+
},
|
|
1183
|
+
],
|
|
1184
|
+
} as unknown as IUnitOfWork;
|
|
1185
|
+
await options.onAfterMutate?.(mockUow);
|
|
1186
|
+
}),
|
|
1187
|
+
} as unknown as ReturnType<typeof executeUnitOfWork.createHandlerTxBuilder>;
|
|
1188
|
+
});
|
|
1189
|
+
|
|
1190
|
+
try {
|
|
1191
|
+
const storage = mockAdapter.contextStorage as RequestContextStorage<DatabaseContextStorage>;
|
|
1192
|
+
await storage.runWithInitializer(
|
|
1193
|
+
() =>
|
|
1194
|
+
({
|
|
1195
|
+
uow: mockAdapter.createQueryEngine(testSchema, "test").createUnitOfWork(),
|
|
1196
|
+
[requestWaitUntilSymbol]: waitUntilSpy,
|
|
1197
|
+
}) as DatabaseContextStorage,
|
|
1198
|
+
async () => {
|
|
1199
|
+
await runtime.config.handlerTx().execute();
|
|
1200
|
+
},
|
|
1201
|
+
);
|
|
1202
|
+
|
|
1203
|
+
expect(notifySpy).toHaveBeenCalledTimes(1);
|
|
1204
|
+
const notifyContext = notifySpy.mock.calls[0]?.[0] as
|
|
1205
|
+
| { source?: string; waitUntil?: unknown }
|
|
1206
|
+
| undefined;
|
|
1207
|
+
expect(notifyContext?.source).toBe("hook");
|
|
1208
|
+
expect(notifyContext?.waitUntil).toBe(waitUntilSpy);
|
|
1209
|
+
expect(waitUntilSpy).toHaveBeenCalledTimes(1);
|
|
1210
|
+
} finally {
|
|
1211
|
+
createHandlerTxBuilderSpy.mockRestore();
|
|
1212
|
+
}
|
|
1213
|
+
});
|
|
1214
|
+
});
|
|
1215
|
+
|
|
1216
|
+
describe("durable hooks cross-namespace scheduling", () => {
|
|
1217
|
+
it("should schedule hooks triggered in another namespace when mutation runs inside a hook", async () => {
|
|
1218
|
+
const sqlite = new SQLite(":memory:");
|
|
1219
|
+
const adapter = new SqlAdapter({
|
|
1220
|
+
dialect: new SqliteDialect({ database: sqlite }),
|
|
1221
|
+
driverConfig: new BetterSQLite3DriverConfig(),
|
|
1222
|
+
});
|
|
1223
|
+
|
|
1224
|
+
const schemaA = schema("hooks_alpha", (s) =>
|
|
1225
|
+
s.addTable("items", (t) =>
|
|
1226
|
+
t.addColumn("id", idColumn()).addColumn("name", column("string")),
|
|
1227
|
+
),
|
|
1228
|
+
);
|
|
1229
|
+
const schemaB = schema("hooks_beta", (s) =>
|
|
1230
|
+
s.addTable("items", (t) =>
|
|
1231
|
+
t.addColumn("id", idColumn()).addColumn("name", column("string")),
|
|
1232
|
+
),
|
|
1233
|
+
);
|
|
1234
|
+
|
|
1235
|
+
type HooksA = {
|
|
1236
|
+
onAlpha: (payload: { value: string }) => void;
|
|
1237
|
+
};
|
|
1238
|
+
type HooksB = {
|
|
1239
|
+
onBeta: (payload: { value: string }) => void;
|
|
1240
|
+
};
|
|
1241
|
+
|
|
1242
|
+
const hooksB: HooksB = {
|
|
1243
|
+
onBeta: () => {},
|
|
1244
|
+
};
|
|
1245
|
+
|
|
1246
|
+
const namespaceA = sanitizeNamespace(schemaA.name);
|
|
1247
|
+
const namespaceB = sanitizeNamespace(schemaB.name);
|
|
1248
|
+
|
|
1249
|
+
const fragmentADef = defineFragment("frag-hooks-a")
|
|
1250
|
+
.extend(withDatabase(schemaA))
|
|
1251
|
+
.provideHooks<HooksA>(({ defineHook }) => ({
|
|
1252
|
+
onAlpha: defineHook(async function () {
|
|
1253
|
+
await this.handlerTx({
|
|
1254
|
+
onBeforeMutate: (uow) => {
|
|
1255
|
+
uow.registerSchema(schemaB, namespaceB);
|
|
1256
|
+
},
|
|
1257
|
+
})
|
|
1258
|
+
.mutate(({ forSchema }) => {
|
|
1259
|
+
const other = forSchema(schemaB, hooksB);
|
|
1260
|
+
other.triggerHook("onBeta", { value: "beta" });
|
|
1261
|
+
})
|
|
1262
|
+
.execute();
|
|
1263
|
+
}),
|
|
1264
|
+
}))
|
|
1265
|
+
.build();
|
|
1266
|
+
|
|
1267
|
+
const fragmentBDef = defineFragment("frag-hooks-b")
|
|
1268
|
+
.extend(withDatabase(schemaB))
|
|
1269
|
+
.provideHooks<HooksB>(({ defineHook }) => ({
|
|
1270
|
+
onBeta: defineHook(async function () {
|
|
1271
|
+
// no-op
|
|
1272
|
+
}),
|
|
1273
|
+
}))
|
|
1274
|
+
.build();
|
|
1275
|
+
|
|
1276
|
+
try {
|
|
1277
|
+
const internalMigrations = adapter.prepareMigrations(internalSchema, null);
|
|
1278
|
+
await internalMigrations.executeWithDriver(adapter.driver, 0);
|
|
1279
|
+
|
|
1280
|
+
const migrationsA = adapter.prepareMigrations(schemaA, namespaceA);
|
|
1281
|
+
await migrationsA.executeWithDriver(adapter.driver, 0);
|
|
1282
|
+
|
|
1283
|
+
const migrationsB = adapter.prepareMigrations(schemaB, namespaceB);
|
|
1284
|
+
await migrationsB.executeWithDriver(adapter.driver, 0);
|
|
1285
|
+
|
|
1286
|
+
const fragmentA = instantiate(fragmentADef)
|
|
1287
|
+
.withConfig({})
|
|
1288
|
+
.withOptions({ databaseAdapter: adapter })
|
|
1289
|
+
.build();
|
|
1290
|
+
const fragmentB = instantiate(fragmentBDef)
|
|
1291
|
+
.withConfig({})
|
|
1292
|
+
.withOptions({ databaseAdapter: adapter })
|
|
1293
|
+
.build();
|
|
1294
|
+
|
|
1295
|
+
const tokenA = (fragmentA.$internal as { durableHooksToken?: object }).durableHooksToken;
|
|
1296
|
+
const tokenB = (fragmentB.$internal as { durableHooksToken?: object }).durableHooksToken;
|
|
1297
|
+
|
|
1298
|
+
expect(tokenA).toBeDefined();
|
|
1299
|
+
expect(tokenB).toBeDefined();
|
|
1300
|
+
|
|
1301
|
+
const runtimeA = tokenA ? getDurableHooksRuntimeByToken(tokenA) : undefined;
|
|
1302
|
+
const runtimeB = tokenB ? getDurableHooksRuntimeByToken(tokenB) : undefined;
|
|
1303
|
+
|
|
1304
|
+
if (!runtimeA || !runtimeB) {
|
|
1305
|
+
throw new Error("Durable hooks runtime missing");
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
const notifySpy = vi.fn();
|
|
1309
|
+
runtimeB.config.notifier = {
|
|
1310
|
+
notify: notifySpy,
|
|
1311
|
+
};
|
|
1312
|
+
|
|
1313
|
+
const internalFragment = getInternalFragment(adapter);
|
|
1314
|
+
await internalFragment.inContext(async function () {
|
|
1315
|
+
await this.handlerTx()
|
|
1316
|
+
.mutate(({ forSchema }) => {
|
|
1317
|
+
const uow = forSchema(internalSchema);
|
|
1318
|
+
uow.create("fragno_hooks", {
|
|
1319
|
+
namespace: namespaceA,
|
|
1320
|
+
hookName: "onAlpha",
|
|
1321
|
+
payload: { value: "alpha" },
|
|
1322
|
+
status: "pending",
|
|
1323
|
+
attempts: 0,
|
|
1324
|
+
maxAttempts: 1,
|
|
1325
|
+
lastAttemptAt: null,
|
|
1326
|
+
nextRetryAt: null,
|
|
1327
|
+
error: null,
|
|
1328
|
+
nonce: "test-nonce",
|
|
1329
|
+
});
|
|
1330
|
+
})
|
|
1331
|
+
.execute();
|
|
1332
|
+
});
|
|
1333
|
+
|
|
1334
|
+
const runnerA = runtimeA.config.runner ?? hooks.createDurableHooksRunner(runtimeA.config);
|
|
1335
|
+
runtimeA.config.runner = runnerA;
|
|
1336
|
+
await runnerA.processDue();
|
|
1337
|
+
|
|
1338
|
+
expect(notifySpy).toHaveBeenCalled();
|
|
1339
|
+
} finally {
|
|
1340
|
+
await adapter.close();
|
|
1341
|
+
sqlite.close();
|
|
1342
|
+
}
|
|
1343
|
+
});
|
|
1344
|
+
|
|
1345
|
+
it("should skip cross-namespace notify when target namespace has autoSchedule=false", async () => {
|
|
1346
|
+
const sqlite = new SQLite(":memory:");
|
|
1347
|
+
const adapter = new SqlAdapter({
|
|
1348
|
+
dialect: new SqliteDialect({ database: sqlite }),
|
|
1349
|
+
driverConfig: new BetterSQLite3DriverConfig(),
|
|
1350
|
+
});
|
|
1351
|
+
|
|
1352
|
+
const schemaA = schema("hooks_alpha_autoschedule", (s) =>
|
|
1353
|
+
s.addTable("items", (t) =>
|
|
1354
|
+
t.addColumn("id", idColumn()).addColumn("name", column("string")),
|
|
1355
|
+
),
|
|
1356
|
+
);
|
|
1357
|
+
const schemaB = schema("hooks_beta_autoschedule", (s) =>
|
|
1358
|
+
s.addTable("items", (t) =>
|
|
1359
|
+
t.addColumn("id", idColumn()).addColumn("name", column("string")),
|
|
1360
|
+
),
|
|
1361
|
+
);
|
|
1362
|
+
|
|
1363
|
+
type HooksA = {
|
|
1364
|
+
onAlpha: (payload: { value: string }) => void;
|
|
1365
|
+
};
|
|
1366
|
+
type HooksB = {
|
|
1367
|
+
onBeta: (payload: { value: string }) => void;
|
|
1368
|
+
};
|
|
1369
|
+
|
|
1370
|
+
const hooksB: HooksB = {
|
|
1371
|
+
onBeta: () => {},
|
|
1372
|
+
};
|
|
1373
|
+
|
|
1374
|
+
const namespaceA = sanitizeNamespace(schemaA.name);
|
|
1375
|
+
const namespaceB = sanitizeNamespace(schemaB.name);
|
|
1376
|
+
|
|
1377
|
+
const fragmentADef = defineFragment("frag-hooks-autoschedule-a")
|
|
1378
|
+
.extend(withDatabase(schemaA))
|
|
1379
|
+
.provideHooks<HooksA>(({ defineHook }) => ({
|
|
1380
|
+
onAlpha: defineHook(async function () {
|
|
1381
|
+
await this.handlerTx({
|
|
1382
|
+
onBeforeMutate: (uow) => {
|
|
1383
|
+
uow.registerSchema(schemaB, namespaceB);
|
|
1384
|
+
},
|
|
1385
|
+
})
|
|
1386
|
+
.mutate(({ forSchema }) => {
|
|
1387
|
+
const other = forSchema(schemaB, hooksB);
|
|
1388
|
+
other.triggerHook("onBeta", { value: "beta" });
|
|
1389
|
+
})
|
|
1390
|
+
.execute();
|
|
1391
|
+
}),
|
|
1392
|
+
}))
|
|
1393
|
+
.build();
|
|
1394
|
+
|
|
1395
|
+
const fragmentBDef = defineFragment("frag-hooks-autoschedule-b")
|
|
1396
|
+
.extend(withDatabase(schemaB))
|
|
1397
|
+
.provideHooks<HooksB>(({ defineHook }) => ({
|
|
1398
|
+
onBeta: defineHook(async function () {
|
|
1399
|
+
// no-op
|
|
1400
|
+
}),
|
|
1401
|
+
}))
|
|
1402
|
+
.build();
|
|
1403
|
+
|
|
1404
|
+
try {
|
|
1405
|
+
const internalMigrations = adapter.prepareMigrations(internalSchema, null);
|
|
1406
|
+
await internalMigrations.executeWithDriver(adapter.driver, 0);
|
|
1407
|
+
|
|
1408
|
+
const migrationsA = adapter.prepareMigrations(schemaA, namespaceA);
|
|
1409
|
+
await migrationsA.executeWithDriver(adapter.driver, 0);
|
|
1410
|
+
|
|
1411
|
+
const migrationsB = adapter.prepareMigrations(schemaB, namespaceB);
|
|
1412
|
+
await migrationsB.executeWithDriver(adapter.driver, 0);
|
|
1413
|
+
|
|
1414
|
+
const fragmentA = instantiate(fragmentADef)
|
|
1415
|
+
.withConfig({})
|
|
1416
|
+
.withOptions({ databaseAdapter: adapter })
|
|
1417
|
+
.build();
|
|
1418
|
+
const fragmentB = instantiate(fragmentBDef)
|
|
1419
|
+
.withConfig({})
|
|
1420
|
+
.withOptions({ databaseAdapter: adapter, durableHooks: { autoSchedule: false } })
|
|
1421
|
+
.build();
|
|
1422
|
+
|
|
1423
|
+
const tokenA = (fragmentA.$internal as { durableHooksToken?: object }).durableHooksToken;
|
|
1424
|
+
const tokenB = (fragmentB.$internal as { durableHooksToken?: object }).durableHooksToken;
|
|
1425
|
+
|
|
1426
|
+
expect(tokenA).toBeDefined();
|
|
1427
|
+
expect(tokenB).toBeDefined();
|
|
1428
|
+
|
|
1429
|
+
const runtimeA = tokenA ? getDurableHooksRuntimeByToken(tokenA) : undefined;
|
|
1430
|
+
const runtimeB = tokenB ? getDurableHooksRuntimeByToken(tokenB) : undefined;
|
|
1431
|
+
|
|
1432
|
+
if (!runtimeA || !runtimeB) {
|
|
1433
|
+
throw new Error("Durable hooks runtime missing");
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
const notifySpy = vi.fn();
|
|
1437
|
+
runtimeB.config.notifier = {
|
|
1438
|
+
notify: notifySpy,
|
|
1439
|
+
};
|
|
1440
|
+
|
|
1441
|
+
const internalFragment = getInternalFragment(adapter);
|
|
1442
|
+
await internalFragment.inContext(async function () {
|
|
1443
|
+
await this.handlerTx()
|
|
1444
|
+
.mutate(({ forSchema }) => {
|
|
1445
|
+
const uow = forSchema(internalSchema);
|
|
1446
|
+
uow.create("fragno_hooks", {
|
|
1447
|
+
namespace: namespaceA,
|
|
1448
|
+
hookName: "onAlpha",
|
|
1449
|
+
payload: { value: "alpha" },
|
|
1450
|
+
status: "pending",
|
|
1451
|
+
attempts: 0,
|
|
1452
|
+
maxAttempts: 1,
|
|
1453
|
+
lastAttemptAt: null,
|
|
1454
|
+
nextRetryAt: null,
|
|
1455
|
+
error: null,
|
|
1456
|
+
nonce: "auto-schedule-test-nonce",
|
|
1457
|
+
});
|
|
1458
|
+
})
|
|
1459
|
+
.execute();
|
|
1460
|
+
});
|
|
1461
|
+
|
|
1462
|
+
const runnerA = runtimeA.config.runner ?? hooks.createDurableHooksRunner(runtimeA.config);
|
|
1463
|
+
runtimeA.config.runner = runnerA;
|
|
1464
|
+
await runnerA.processDue();
|
|
1465
|
+
|
|
1466
|
+
expect(notifySpy).not.toHaveBeenCalled();
|
|
1467
|
+
|
|
1468
|
+
const queuedHooks = await internalFragment.inContext(async function () {
|
|
1469
|
+
return await this.handlerTx()
|
|
1470
|
+
.withServiceCalls(
|
|
1471
|
+
() =>
|
|
1472
|
+
[internalFragment.services.hookService.getHooksByNamespace(namespaceB)] as const,
|
|
1473
|
+
)
|
|
1474
|
+
.transform(({ serviceResult: [result] }) => result)
|
|
1475
|
+
.execute();
|
|
1476
|
+
});
|
|
1477
|
+
|
|
1478
|
+
const pendingBetaHooks = queuedHooks.filter(
|
|
1479
|
+
(hook) => hook.status === "pending" && hook.hookName === "onBeta",
|
|
1480
|
+
);
|
|
1481
|
+
expect(pendingBetaHooks.length).toBeGreaterThan(0);
|
|
1482
|
+
} finally {
|
|
1483
|
+
await adapter.close();
|
|
1484
|
+
sqlite.close();
|
|
1485
|
+
}
|
|
1486
|
+
});
|
|
1487
|
+
|
|
1488
|
+
it("should notify the matching runtime instance when namespace has multiple runtimes", async () => {
|
|
1489
|
+
const sqliteA = new SQLite(":memory:");
|
|
1490
|
+
const sqliteB = new SQLite(":memory:");
|
|
1491
|
+
const adapterA = new SqlAdapter({
|
|
1492
|
+
dialect: new SqliteDialect({ database: sqliteA }),
|
|
1493
|
+
driverConfig: new BetterSQLite3DriverConfig(),
|
|
1494
|
+
});
|
|
1495
|
+
const adapterB = new SqlAdapter({
|
|
1496
|
+
dialect: new SqliteDialect({ database: sqliteB }),
|
|
1497
|
+
driverConfig: new BetterSQLite3DriverConfig(),
|
|
1498
|
+
});
|
|
1499
|
+
|
|
1500
|
+
const unique = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
1501
|
+
const schemaA = schema(`hooks_alpha_instance_${unique}`, (s) =>
|
|
1502
|
+
s.addTable("items", (t) =>
|
|
1503
|
+
t.addColumn("id", idColumn()).addColumn("name", column("string")),
|
|
1504
|
+
),
|
|
1505
|
+
);
|
|
1506
|
+
const schemaB = schema(`hooks_shared_${unique}`, (s) =>
|
|
1507
|
+
s.addTable("items", (t) =>
|
|
1508
|
+
t.addColumn("id", idColumn()).addColumn("name", column("string")),
|
|
1509
|
+
),
|
|
1510
|
+
);
|
|
1511
|
+
|
|
1512
|
+
type HooksA = {
|
|
1513
|
+
onAlpha: (payload: { value: string }) => void;
|
|
1514
|
+
};
|
|
1515
|
+
type HooksB = {
|
|
1516
|
+
onBeta: (payload: { value: string }) => void;
|
|
1517
|
+
};
|
|
1518
|
+
|
|
1519
|
+
const hooksB: HooksB = {
|
|
1520
|
+
onBeta: () => {},
|
|
1521
|
+
};
|
|
1522
|
+
|
|
1523
|
+
const namespaceA = sanitizeNamespace(schemaA.name);
|
|
1524
|
+
const namespaceB = sanitizeNamespace(schemaB.name);
|
|
1525
|
+
|
|
1526
|
+
const fragmentADef = defineFragment("frag-hooks-instance-a")
|
|
1527
|
+
.extend(withDatabase(schemaA))
|
|
1528
|
+
.provideHooks<HooksA>(({ defineHook }) => ({
|
|
1529
|
+
onAlpha: defineHook(async function () {
|
|
1530
|
+
await this.handlerTx({
|
|
1531
|
+
onBeforeMutate: (uow) => {
|
|
1532
|
+
uow.registerSchema(schemaB, namespaceB);
|
|
1533
|
+
},
|
|
1534
|
+
})
|
|
1535
|
+
.mutate(({ forSchema }) => {
|
|
1536
|
+
const other = forSchema(schemaB, hooksB);
|
|
1537
|
+
other.triggerHook("onBeta", { value: "beta" });
|
|
1538
|
+
})
|
|
1539
|
+
.execute();
|
|
1540
|
+
}),
|
|
1541
|
+
}))
|
|
1542
|
+
.build();
|
|
1543
|
+
|
|
1544
|
+
const fragmentBDef = defineFragment("frag-hooks-shared")
|
|
1545
|
+
.extend(withDatabase(schemaB))
|
|
1546
|
+
.provideHooks<HooksB>(({ defineHook }) => ({
|
|
1547
|
+
onBeta: defineHook(async function () {
|
|
1548
|
+
// no-op
|
|
1549
|
+
}),
|
|
1550
|
+
}))
|
|
1551
|
+
.build();
|
|
1552
|
+
|
|
1553
|
+
try {
|
|
1554
|
+
const internalMigrationsA = adapterA.prepareMigrations(internalSchema, null);
|
|
1555
|
+
await internalMigrationsA.executeWithDriver(adapterA.driver, 0);
|
|
1556
|
+
const schemaAMigrations = adapterA.prepareMigrations(schemaA, namespaceA);
|
|
1557
|
+
await schemaAMigrations.executeWithDriver(adapterA.driver, 0);
|
|
1558
|
+
const schemaBMigrationsA = adapterA.prepareMigrations(schemaB, namespaceB);
|
|
1559
|
+
await schemaBMigrationsA.executeWithDriver(adapterA.driver, 0);
|
|
1560
|
+
|
|
1561
|
+
const internalMigrationsB = adapterB.prepareMigrations(internalSchema, null);
|
|
1562
|
+
await internalMigrationsB.executeWithDriver(adapterB.driver, 0);
|
|
1563
|
+
const schemaBMigrationsB = adapterB.prepareMigrations(schemaB, namespaceB);
|
|
1564
|
+
await schemaBMigrationsB.executeWithDriver(adapterB.driver, 0);
|
|
1565
|
+
|
|
1566
|
+
const fragmentA = instantiate(fragmentADef)
|
|
1567
|
+
.withConfig({})
|
|
1568
|
+
.withOptions({ databaseAdapter: adapterA })
|
|
1569
|
+
.build();
|
|
1570
|
+
const fragmentBForAdapterA = instantiate(fragmentBDef)
|
|
1571
|
+
.withConfig({})
|
|
1572
|
+
.withOptions({ databaseAdapter: adapterA })
|
|
1573
|
+
.build();
|
|
1574
|
+
const fragmentBForAdapterB = instantiate(fragmentBDef)
|
|
1575
|
+
.withConfig({})
|
|
1576
|
+
.withOptions({ databaseAdapter: adapterB })
|
|
1577
|
+
.build();
|
|
1578
|
+
|
|
1579
|
+
const tokenA = (fragmentA.$internal as { durableHooksToken?: object }).durableHooksToken;
|
|
1580
|
+
const tokenBForAdapterA = (fragmentBForAdapterA.$internal as { durableHooksToken?: object })
|
|
1581
|
+
.durableHooksToken;
|
|
1582
|
+
const tokenBForAdapterB = (fragmentBForAdapterB.$internal as { durableHooksToken?: object })
|
|
1583
|
+
.durableHooksToken;
|
|
1584
|
+
|
|
1585
|
+
expect(tokenA).toBeDefined();
|
|
1586
|
+
expect(tokenBForAdapterA).toBeDefined();
|
|
1587
|
+
expect(tokenBForAdapterB).toBeDefined();
|
|
1588
|
+
|
|
1589
|
+
const runtimeA = tokenA ? getDurableHooksRuntimeByToken(tokenA) : undefined;
|
|
1590
|
+
const runtimeBForAdapterA = tokenBForAdapterA
|
|
1591
|
+
? getDurableHooksRuntimeByToken(tokenBForAdapterA)
|
|
1592
|
+
: undefined;
|
|
1593
|
+
const runtimeBForAdapterB = tokenBForAdapterB
|
|
1594
|
+
? getDurableHooksRuntimeByToken(tokenBForAdapterB)
|
|
1595
|
+
: undefined;
|
|
1596
|
+
|
|
1597
|
+
if (!runtimeA || !runtimeBForAdapterA || !runtimeBForAdapterB) {
|
|
1598
|
+
throw new Error("Durable hooks runtime missing");
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
const notifySpyForAdapterA = vi.fn();
|
|
1602
|
+
const notifySpyForAdapterB = vi.fn();
|
|
1603
|
+
runtimeBForAdapterA.config.notifier = {
|
|
1604
|
+
notify: notifySpyForAdapterA,
|
|
1605
|
+
};
|
|
1606
|
+
runtimeBForAdapterB.config.notifier = {
|
|
1607
|
+
notify: notifySpyForAdapterB,
|
|
1608
|
+
};
|
|
1609
|
+
|
|
1610
|
+
const internalFragment = getInternalFragment(adapterA);
|
|
1611
|
+
await internalFragment.inContext(async function () {
|
|
1612
|
+
await this.handlerTx()
|
|
1613
|
+
.mutate(({ forSchema }) => {
|
|
1614
|
+
const uow = forSchema(internalSchema);
|
|
1615
|
+
uow.create("fragno_hooks", {
|
|
1616
|
+
namespace: namespaceA,
|
|
1617
|
+
hookName: "onAlpha",
|
|
1618
|
+
payload: { value: "alpha" },
|
|
1619
|
+
status: "pending",
|
|
1620
|
+
attempts: 0,
|
|
1621
|
+
maxAttempts: 1,
|
|
1622
|
+
lastAttemptAt: null,
|
|
1623
|
+
nextRetryAt: null,
|
|
1624
|
+
error: null,
|
|
1625
|
+
nonce: "instance-test-nonce",
|
|
1626
|
+
});
|
|
1627
|
+
})
|
|
1628
|
+
.execute();
|
|
1629
|
+
});
|
|
1630
|
+
|
|
1631
|
+
const runnerA = runtimeA.config.runner ?? hooks.createDurableHooksRunner(runtimeA.config);
|
|
1632
|
+
runtimeA.config.runner = runnerA;
|
|
1633
|
+
await runnerA.processDue();
|
|
1634
|
+
|
|
1635
|
+
expect(notifySpyForAdapterA).toHaveBeenCalled();
|
|
1636
|
+
expect(notifySpyForAdapterB).not.toHaveBeenCalled();
|
|
1637
|
+
} finally {
|
|
1638
|
+
await adapterA.close();
|
|
1639
|
+
await adapterB.close();
|
|
1640
|
+
sqliteA.close();
|
|
1641
|
+
sqliteB.close();
|
|
1642
|
+
}
|
|
1643
|
+
});
|
|
1644
|
+
});
|
|
1645
|
+
|
|
1646
|
+
describe("handlerTx plan mode", () => {
|
|
1647
|
+
it("should suppress hook mutations in plan mode", () => {
|
|
1648
|
+
const mockAdapter = createMockAdapter();
|
|
1649
|
+
|
|
1650
|
+
type TestHooks = {
|
|
1651
|
+
onUserCreated: (payload: { email: string }) => void;
|
|
1652
|
+
};
|
|
1653
|
+
|
|
1654
|
+
const definition = withDatabase(testSchema)(defineFragment("db-frag-plan-mode"))
|
|
1655
|
+
.provideHooks<TestHooks>(({ defineHook }) => ({
|
|
1656
|
+
onUserCreated: defineHook(function () {
|
|
1657
|
+
// no-op
|
|
1658
|
+
}),
|
|
1659
|
+
}))
|
|
1660
|
+
.build();
|
|
1661
|
+
|
|
1662
|
+
const mockStorage = {
|
|
1663
|
+
getStore: () => ({
|
|
1664
|
+
uow: mockAdapter.createQueryEngine(testSchema, "test").createUnitOfWork(),
|
|
1665
|
+
}),
|
|
1666
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1667
|
+
} as any;
|
|
1668
|
+
|
|
1669
|
+
const createHandlerTxBuilderSpy = vi
|
|
1670
|
+
.spyOn(executeUnitOfWork, "createHandlerTxBuilder")
|
|
1671
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1672
|
+
.mockReturnValue({} as any);
|
|
1673
|
+
|
|
1674
|
+
const prepareHookMutationsSpy = vi.spyOn(hooks, "prepareHookMutations");
|
|
1675
|
+
|
|
1676
|
+
const contexts = definition.createThisContext!({
|
|
1677
|
+
config: {},
|
|
1678
|
+
options: { databaseAdapter: mockAdapter },
|
|
1679
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1680
|
+
deps: {} as any,
|
|
1681
|
+
storage: mockStorage,
|
|
1682
|
+
});
|
|
1683
|
+
|
|
1684
|
+
contexts.handlerContext.handlerTx({ planMode: true });
|
|
1685
|
+
|
|
1686
|
+
const callArgs = createHandlerTxBuilderSpy.mock.calls[0]?.[0];
|
|
1687
|
+
callArgs?.onBeforeMutate?.({} as unknown as IUnitOfWork);
|
|
1688
|
+
|
|
1689
|
+
expect(prepareHookMutationsSpy).not.toHaveBeenCalled();
|
|
1690
|
+
|
|
1691
|
+
prepareHookMutationsSpy.mockRestore();
|
|
1692
|
+
createHandlerTxBuilderSpy.mockRestore();
|
|
1693
|
+
});
|
|
1694
|
+
});
|
|
903
1695
|
});
|