@fragno-dev/db 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +206 -140
- package/CHANGELOG.md +67 -0
- package/README.md +30 -9
- package/dist/adapters/adapters.d.ts +23 -21
- package/dist/adapters/adapters.d.ts.map +1 -1
- package/dist/adapters/adapters.js.map +1 -1
- package/dist/adapters/generic-sql/driver-config.d.ts +16 -1
- package/dist/adapters/generic-sql/driver-config.d.ts.map +1 -1
- package/dist/adapters/generic-sql/driver-config.js +23 -1
- package/dist/adapters/generic-sql/driver-config.js.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-adapter.d.ts +27 -9
- package/dist/adapters/generic-sql/generic-sql-adapter.d.ts.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-adapter.js +55 -16
- package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-uow-executor.js +129 -3
- package/dist/adapters/generic-sql/generic-sql-uow-executor.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/mysql.js +24 -5
- package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/postgres.js +6 -5
- package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/sqlite.js +21 -10
- package/dist/adapters/generic-sql/migration/dialect/sqlite.js.map +1 -1
- package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -1
- package/dist/adapters/generic-sql/migration/prepared-migrations.js +8 -8
- package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -1
- package/dist/adapters/generic-sql/migration/sql-generator.js +74 -51
- package/dist/adapters/generic-sql/migration/sql-generator.js.map +1 -1
- package/dist/adapters/generic-sql/query/create-sql-query-compiler.js +6 -5
- package/dist/adapters/generic-sql/query/create-sql-query-compiler.js.map +1 -1
- package/dist/adapters/generic-sql/query/cursor-utils.js +42 -4
- package/dist/adapters/generic-sql/query/cursor-utils.js.map +1 -1
- package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js +25 -17
- package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js.map +1 -1
- package/dist/adapters/generic-sql/query/select-builder.js +5 -3
- package/dist/adapters/generic-sql/query/select-builder.js.map +1 -1
- package/dist/adapters/generic-sql/query/sql-query-compiler.js +15 -12
- package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -1
- package/dist/adapters/generic-sql/query/where-builder.js +38 -28
- package/dist/adapters/generic-sql/query/where-builder.js.map +1 -1
- package/dist/adapters/generic-sql/sqlite-storage.d.ts +13 -0
- package/dist/adapters/generic-sql/sqlite-storage.d.ts.map +1 -0
- package/dist/adapters/generic-sql/sqlite-storage.js +15 -0
- package/dist/adapters/generic-sql/sqlite-storage.js.map +1 -0
- package/dist/adapters/generic-sql/uow-decoder.js +7 -3
- package/dist/adapters/generic-sql/uow-decoder.js.map +1 -1
- package/dist/adapters/generic-sql/uow-encoder.js +28 -8
- package/dist/adapters/generic-sql/uow-encoder.js.map +1 -1
- package/dist/adapters/in-memory/condition-evaluator.js +131 -0
- package/dist/adapters/in-memory/condition-evaluator.js.map +1 -0
- package/dist/adapters/in-memory/errors.d.ts +13 -0
- package/dist/adapters/in-memory/errors.d.ts.map +1 -0
- package/dist/adapters/in-memory/errors.js +23 -0
- package/dist/adapters/in-memory/errors.js.map +1 -0
- package/dist/adapters/in-memory/in-memory-adapter.d.ts +27 -0
- package/dist/adapters/in-memory/in-memory-adapter.d.ts.map +1 -0
- package/dist/adapters/in-memory/in-memory-adapter.js +176 -0
- package/dist/adapters/in-memory/in-memory-adapter.js.map +1 -0
- package/dist/adapters/in-memory/in-memory-uow.js +648 -0
- package/dist/adapters/in-memory/in-memory-uow.js.map +1 -0
- package/dist/adapters/in-memory/index.d.ts +4 -0
- package/dist/adapters/in-memory/index.js +4 -0
- package/dist/adapters/in-memory/options.d.ts +28 -0
- package/dist/adapters/in-memory/options.d.ts.map +1 -0
- package/dist/adapters/in-memory/options.js +61 -0
- package/dist/adapters/in-memory/options.js.map +1 -0
- package/dist/adapters/in-memory/reference-resolution.js +26 -0
- package/dist/adapters/in-memory/reference-resolution.js.map +1 -0
- package/dist/adapters/in-memory/sorted-array-index.js +129 -0
- package/dist/adapters/in-memory/sorted-array-index.js.map +1 -0
- package/dist/adapters/in-memory/store.js +71 -0
- package/dist/adapters/in-memory/store.js.map +1 -0
- package/dist/adapters/in-memory/value-comparison.js +28 -0
- package/dist/adapters/in-memory/value-comparison.js.map +1 -0
- package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -1
- package/dist/adapters/shared/uow-operation-compiler.js +11 -11
- package/dist/adapters/shared/uow-operation-compiler.js.map +1 -1
- package/dist/adapters/sql/index.d.ts +5 -0
- package/dist/adapters/sql/index.js +4 -0
- package/dist/db-fragment-definition-builder.d.ts +45 -96
- package/dist/db-fragment-definition-builder.d.ts.map +1 -1
- package/dist/db-fragment-definition-builder.js +121 -99
- package/dist/db-fragment-definition-builder.js.map +1 -1
- package/dist/dispatchers/cloudflare-do/index.d.ts +26 -0
- package/dist/dispatchers/cloudflare-do/index.d.ts.map +1 -0
- package/dist/dispatchers/cloudflare-do/index.js +63 -0
- package/dist/dispatchers/cloudflare-do/index.js.map +1 -0
- package/dist/dispatchers/node/index.d.ts +17 -0
- package/dist/dispatchers/node/index.d.ts.map +1 -0
- package/dist/dispatchers/node/index.js +59 -0
- package/dist/dispatchers/node/index.js.map +1 -0
- package/dist/fragments/internal-fragment.d.ts +172 -9
- package/dist/fragments/internal-fragment.d.ts.map +1 -1
- package/dist/fragments/internal-fragment.js +193 -74
- package/dist/fragments/internal-fragment.js.map +1 -1
- package/dist/fragments/internal-fragment.routes.js +29 -0
- package/dist/fragments/internal-fragment.routes.js.map +1 -0
- package/dist/fragments/internal-fragment.schema.d.ts +9 -0
- package/dist/fragments/internal-fragment.schema.d.ts.map +1 -0
- package/dist/fragments/internal-fragment.schema.js +22 -0
- package/dist/fragments/internal-fragment.schema.js.map +1 -0
- package/dist/hooks/durable-hooks-processor.d.ts +14 -0
- package/dist/hooks/durable-hooks-processor.d.ts.map +1 -0
- package/dist/hooks/durable-hooks-processor.js +32 -0
- package/dist/hooks/durable-hooks-processor.js.map +1 -0
- package/dist/hooks/hooks.d.ts +47 -4
- package/dist/hooks/hooks.d.ts.map +1 -1
- package/dist/hooks/hooks.js +106 -39
- package/dist/hooks/hooks.js.map +1 -1
- package/dist/migration-engine/auto-from-schema.js +14 -11
- package/dist/migration-engine/auto-from-schema.js.map +1 -1
- package/dist/migration-engine/generation-engine.d.ts +16 -10
- package/dist/migration-engine/generation-engine.d.ts.map +1 -1
- package/dist/migration-engine/generation-engine.js +72 -33
- package/dist/migration-engine/generation-engine.js.map +1 -1
- package/dist/migration-engine/shared.js.map +1 -1
- package/dist/mod.d.ts +17 -10
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +14 -8
- package/dist/mod.js.map +1 -1
- package/dist/naming/sql-naming.d.ts +19 -0
- package/dist/naming/sql-naming.d.ts.map +1 -0
- package/dist/naming/sql-naming.js +116 -0
- package/dist/naming/sql-naming.js.map +1 -0
- package/dist/node_modules/.pnpm/{rou3@0.7.10 → rou3@0.7.12}/node_modules/rou3/dist/index.js +8 -5
- package/dist/node_modules/.pnpm/rou3@0.7.12/node_modules/rou3/dist/index.js.map +1 -0
- package/dist/outbox/outbox-builder.js +156 -0
- package/dist/outbox/outbox-builder.js.map +1 -0
- package/dist/outbox/outbox.d.ts +52 -0
- package/dist/outbox/outbox.d.ts.map +1 -0
- package/dist/outbox/outbox.js +37 -0
- package/dist/outbox/outbox.js.map +1 -0
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js +3 -2
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +1 -1
- package/dist/packages/fragno/dist/api/fragment-instantiator.js +164 -20
- package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +1 -1
- package/dist/packages/fragno/dist/api/request-input-context.js +67 -0
- package/dist/packages/fragno/dist/api/request-input-context.js.map +1 -1
- package/dist/packages/fragno/dist/api/route.js +14 -1
- package/dist/packages/fragno/dist/api/route.js.map +1 -1
- package/dist/packages/fragno/dist/internal/trace-context.js +12 -0
- package/dist/packages/fragno/dist/internal/trace-context.js.map +1 -0
- package/dist/query/column-defaults.js +20 -4
- package/dist/query/column-defaults.js.map +1 -1
- package/dist/query/cursor.d.ts +3 -1
- package/dist/query/cursor.d.ts.map +1 -1
- package/dist/query/cursor.js +45 -14
- package/dist/query/cursor.js.map +1 -1
- package/dist/query/db-now.d.ts +8 -0
- package/dist/query/db-now.d.ts.map +1 -0
- package/dist/query/db-now.js +7 -0
- package/dist/query/db-now.js.map +1 -0
- package/dist/query/serialize/create-sql-serializer.js +3 -2
- package/dist/query/serialize/create-sql-serializer.js.map +1 -1
- package/dist/query/serialize/dialect/mysql-serializer.js +12 -6
- package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -1
- package/dist/query/serialize/dialect/postgres-serializer.js +25 -7
- package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -1
- package/dist/query/serialize/dialect/sqlite-serializer.js +55 -11
- package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -1
- package/dist/query/serialize/sql-serializer.js +2 -2
- package/dist/query/serialize/sql-serializer.js.map +1 -1
- package/dist/query/simple-query-interface.d.ts +6 -1
- package/dist/query/simple-query-interface.d.ts.map +1 -1
- package/dist/query/unit-of-work/execute-unit-of-work.d.ts +351 -100
- package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work/execute-unit-of-work.js +440 -267
- package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -1
- package/dist/query/unit-of-work/unit-of-work.d.ts +67 -22
- package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work/unit-of-work.js +110 -13
- package/dist/query/unit-of-work/unit-of-work.js.map +1 -1
- package/dist/query/value-decoding.js +8 -5
- package/dist/query/value-decoding.js.map +1 -1
- package/dist/query/value-encoding.js +29 -9
- package/dist/query/value-encoding.js.map +1 -1
- package/dist/schema/create.d.ts +40 -14
- package/dist/schema/create.d.ts.map +1 -1
- package/dist/schema/create.js +82 -42
- package/dist/schema/create.js.map +1 -1
- package/dist/schema/generate-id.d.ts +20 -0
- package/dist/schema/generate-id.d.ts.map +1 -0
- package/dist/schema/generate-id.js +28 -0
- package/dist/schema/generate-id.js.map +1 -0
- package/dist/schema/type-conversion/create-sql-type-mapper.js +3 -2
- package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -1
- package/dist/schema/type-conversion/dialect/sqlite.js +9 -0
- package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -1
- package/dist/schema/validator.d.ts +10 -0
- package/dist/schema/validator.d.ts.map +1 -0
- package/dist/schema/validator.js +123 -0
- package/dist/schema/validator.js.map +1 -0
- package/dist/schema-output/drizzle.d.ts +30 -0
- package/dist/schema-output/drizzle.d.ts.map +1 -0
- package/dist/{adapters/drizzle/generate.js → schema-output/drizzle.js} +82 -56
- package/dist/schema-output/drizzle.js.map +1 -0
- package/dist/schema-output/prisma.d.ts +17 -0
- package/dist/schema-output/prisma.d.ts.map +1 -0
- package/dist/schema-output/prisma.js +296 -0
- package/dist/schema-output/prisma.js.map +1 -0
- package/dist/util/default-database-adapter.js +61 -0
- package/dist/util/default-database-adapter.js.map +1 -0
- package/dist/with-database.d.ts +1 -1
- package/dist/with-database.d.ts.map +1 -1
- package/dist/with-database.js +12 -3
- package/dist/with-database.js.map +1 -1
- package/package.json +43 -28
- package/src/adapters/adapters.ts +30 -24
- package/src/adapters/drizzle/migrate-drizzle.test.ts +54 -33
- package/src/adapters/drizzle/migration-parity-drizzle-kit.test.ts +599 -0
- package/src/adapters/drizzle/test-utils.ts +12 -8
- package/src/adapters/generic-sql/driver-config.ts +38 -0
- package/src/adapters/generic-sql/generic-sql-adapter.test.ts +5 -5
- package/src/adapters/generic-sql/generic-sql-adapter.ts +110 -24
- package/src/adapters/generic-sql/generic-sql-uow-executor.test.ts +54 -0
- package/src/adapters/generic-sql/generic-sql-uow-executor.ts +231 -3
- package/src/adapters/generic-sql/migration/adapter-migration-parity.test.ts +118 -0
- package/src/adapters/generic-sql/migration/dialect/mysql.test.ts +26 -8
- package/src/adapters/generic-sql/migration/dialect/mysql.ts +46 -8
- package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +25 -7
- package/src/adapters/generic-sql/migration/dialect/postgres.ts +8 -4
- package/src/adapters/generic-sql/migration/dialect/sqlite.test.ts +47 -8
- package/src/adapters/generic-sql/migration/dialect/sqlite.ts +27 -12
- package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +128 -39
- package/src/adapters/generic-sql/migration/prepared-migrations.ts +15 -8
- package/src/adapters/generic-sql/migration/sql-generator.ts +142 -65
- package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +9 -6
- package/src/adapters/generic-sql/query/cursor-utils.test.ts +271 -0
- package/src/adapters/generic-sql/query/cursor-utils.ts +41 -6
- package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +27 -27
- package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +38 -24
- package/src/adapters/generic-sql/query/select-builder.test.ts +15 -11
- package/src/adapters/generic-sql/query/select-builder.ts +6 -2
- package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +52 -2
- package/src/adapters/generic-sql/query/sql-query-compiler.ts +50 -15
- package/src/adapters/generic-sql/query/where-builder.test.ts +91 -17
- package/src/adapters/generic-sql/query/where-builder.ts +90 -38
- package/src/adapters/{kysely/kysely-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-migrations.test.ts} +6 -6
- package/src/adapters/generic-sql/sql-adapter-pglite-pagination.test.ts +806 -0
- package/src/adapters/{drizzle/drizzle-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-queries.test.ts} +11 -11
- package/src/adapters/generic-sql/{test/generic-drizzle-adapter-sqlite3.test.ts → sql-adapter-sqlite3-driver.test.ts} +49 -35
- package/src/adapters/{drizzle/drizzle-adapter-sqlite3.test.ts → generic-sql/sql-adapter-sqlite3-uow.test.ts} +48 -32
- package/src/adapters/{kysely/kysely-adapter-sqlocal.test.ts → generic-sql/sql-adapter-sqlocal.test.ts} +6 -6
- package/src/adapters/generic-sql/sqlite-storage.ts +20 -0
- package/src/adapters/generic-sql/uow-decoder.test.ts +1 -1
- package/src/adapters/generic-sql/uow-decoder.ts +21 -3
- package/src/adapters/generic-sql/uow-encoder.test.ts +33 -2
- package/src/adapters/generic-sql/uow-encoder.ts +50 -11
- package/src/adapters/in-memory/condition-evaluator.test.ts +193 -0
- package/src/adapters/in-memory/condition-evaluator.ts +275 -0
- package/src/adapters/in-memory/errors.ts +20 -0
- package/src/adapters/in-memory/in-memory-adapter.ts +277 -0
- package/src/adapters/in-memory/in-memory-uow.mutations.test.ts +296 -0
- package/src/adapters/in-memory/in-memory-uow.retrieval.test.ts +100 -0
- package/src/adapters/in-memory/in-memory-uow.ts +1348 -0
- package/src/adapters/in-memory/index.ts +3 -0
- package/src/adapters/in-memory/options.test.ts +41 -0
- package/src/adapters/in-memory/options.ts +87 -0
- package/src/adapters/in-memory/reference-resolution.test.ts +50 -0
- package/src/adapters/in-memory/reference-resolution.ts +67 -0
- package/src/adapters/in-memory/sorted-array-index.test.ts +123 -0
- package/src/adapters/in-memory/sorted-array-index.ts +228 -0
- package/src/adapters/in-memory/store.test.ts +68 -0
- package/src/adapters/in-memory/store.ts +145 -0
- package/src/adapters/in-memory/value-comparison.ts +53 -0
- package/src/adapters/in-memory/value-normalization.test.ts +57 -0
- package/src/adapters/prisma/prisma-adapter-sqlite3.test.ts +1163 -0
- package/src/adapters/shared/from-unit-of-work-compiler.ts +3 -1
- package/src/adapters/shared/uow-operation-compiler.ts +26 -16
- package/src/adapters/sql/index.ts +12 -0
- package/src/db-fragment-definition-builder.test.ts +88 -54
- package/src/db-fragment-definition-builder.ts +201 -322
- package/src/db-fragment-instantiator.test.ts +169 -101
- package/src/db-fragment-integration.test.ts +301 -149
- package/src/dispatchers/cloudflare-do/index.test.ts +73 -0
- package/src/dispatchers/cloudflare-do/index.ts +104 -0
- package/src/dispatchers/node/index.test.ts +91 -0
- package/src/dispatchers/node/index.ts +87 -0
- package/src/fragments/internal-fragment.routes.ts +42 -0
- package/src/fragments/internal-fragment.schema.ts +51 -0
- package/src/fragments/internal-fragment.test.ts +730 -274
- package/src/fragments/internal-fragment.ts +447 -154
- package/src/hooks/durable-hooks-processor.test.ts +117 -0
- package/src/hooks/durable-hooks-processor.ts +67 -0
- package/src/hooks/hooks.test.ts +411 -259
- package/src/hooks/hooks.ts +265 -66
- package/src/migration-engine/auto-from-schema.test.ts +14 -14
- package/src/migration-engine/auto-from-schema.ts +5 -2
- package/src/migration-engine/create.test.ts +2 -2
- package/src/migration-engine/generation-engine.test.ts +229 -104
- package/src/migration-engine/generation-engine.ts +94 -64
- package/src/migration-engine/shared.ts +1 -0
- package/src/mod.ts +78 -30
- package/src/naming/sql-naming.ts +180 -0
- package/src/outbox/outbox-builder.ts +241 -0
- package/src/outbox/outbox.test.ts +253 -0
- package/src/outbox/outbox.ts +137 -0
- package/src/query/column-defaults.ts +41 -3
- package/src/query/condition-builder.test.ts +3 -3
- package/src/query/cursor.test.ts +116 -18
- package/src/query/cursor.ts +75 -26
- package/src/query/db-now.ts +6 -0
- package/src/query/query-type.test.ts +2 -2
- package/src/query/serialize/create-sql-serializer.ts +7 -2
- package/src/query/serialize/dialect/mysql-serializer.ts +12 -4
- package/src/query/serialize/dialect/postgres-serializer.ts +34 -4
- package/src/query/serialize/dialect/sqlite-serializer.test.ts +51 -1
- package/src/query/serialize/dialect/sqlite-serializer.ts +92 -9
- package/src/query/serialize/sql-serializer.ts +4 -4
- package/src/query/simple-query-interface.ts +5 -0
- package/src/query/unit-of-work/execute-unit-of-work.test.ts +1512 -1458
- package/src/query/unit-of-work/execute-unit-of-work.ts +1708 -596
- package/src/query/unit-of-work/tx-builder.test.ts +1041 -0
- package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +32 -32
- package/src/query/unit-of-work/unit-of-work-types.test.ts +1 -1
- package/src/query/unit-of-work/unit-of-work.test.ts +231 -36
- package/src/query/unit-of-work/unit-of-work.ts +229 -31
- package/src/query/value-decoding.test.ts +13 -2
- package/src/query/value-decoding.ts +17 -4
- package/src/query/value-encoding.test.ts +85 -2
- package/src/query/value-encoding.ts +56 -6
- package/src/schema/create.test.ts +129 -42
- package/src/schema/create.ts +187 -47
- package/src/schema/generate-id.test.ts +57 -0
- package/src/schema/generate-id.ts +38 -0
- package/src/schema/serialize.test.ts +14 -2
- package/src/schema/type-conversion/create-sql-type-mapper.ts +7 -2
- package/src/schema/type-conversion/dialect/sqlite.ts +18 -0
- package/src/schema/type-conversion/type-mapping.test.ts +25 -1
- package/src/schema/validator.test.ts +197 -0
- package/src/schema/validator.ts +231 -0
- package/src/{adapters/drizzle/generate.test.ts → schema-output/drizzle.test.ts} +179 -129
- package/src/{adapters/drizzle/generate.ts → schema-output/drizzle.ts} +143 -93
- package/src/schema-output/prisma.test.ts +536 -0
- package/src/schema-output/prisma.ts +573 -0
- package/src/util/default-database-adapter.ts +106 -0
- package/src/with-database.ts +22 -3
- package/tsdown.config.ts +6 -4
- package/dist/adapters/drizzle/drizzle-adapter.d.ts +0 -20
- package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +0 -1
- package/dist/adapters/drizzle/drizzle-adapter.js +0 -27
- package/dist/adapters/drizzle/drizzle-adapter.js.map +0 -1
- package/dist/adapters/drizzle/generate.d.ts +0 -30
- package/dist/adapters/drizzle/generate.d.ts.map +0 -1
- package/dist/adapters/drizzle/generate.js.map +0 -1
- package/dist/adapters/kysely/kysely-adapter.d.ts +0 -19
- package/dist/adapters/kysely/kysely-adapter.d.ts.map +0 -1
- package/dist/adapters/kysely/kysely-adapter.js +0 -17
- package/dist/adapters/kysely/kysely-adapter.js.map +0 -1
- package/dist/adapters/shared/table-name-mapper.d.ts +0 -12
- package/dist/adapters/shared/table-name-mapper.d.ts.map +0 -1
- package/dist/adapters/shared/table-name-mapper.js +0 -43
- package/dist/adapters/shared/table-name-mapper.js.map +0 -1
- package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js.map +0 -1
- package/dist/schema-generator/schema-generator.d.ts +0 -15
- package/dist/schema-generator/schema-generator.d.ts.map +0 -1
- package/src/adapters/drizzle/drizzle-adapter.ts +0 -39
- package/src/adapters/kysely/kysely-adapter.ts +0 -27
- package/src/adapters/shared/table-name-mapper.ts +0 -50
- package/src/schema-generator/schema-generator.ts +0 -12
- package/src/shared/config.ts +0 -10
- package/src/shared/connection-pool.ts +0 -24
- package/src/shared/prisma.ts +0 -45
package/src/hooks/hooks.test.ts
CHANGED
|
@@ -2,17 +2,26 @@ import SQLite from "better-sqlite3";
|
|
|
2
2
|
import { SqliteDialect } from "kysely";
|
|
3
3
|
import { beforeAll, describe, expect, it, vi } from "vitest";
|
|
4
4
|
import { instantiate } from "@fragno-dev/core";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
prepareHookMutations,
|
|
7
|
+
processHooks,
|
|
8
|
+
type HooksMap,
|
|
9
|
+
type HookContext,
|
|
10
|
+
type HookHandlerTx,
|
|
11
|
+
} from "./hooks";
|
|
6
12
|
import { internalFragmentDef, internalSchema } from "../fragments/internal-fragment";
|
|
7
13
|
import type { FragnoPublicConfigWithDatabase } from "../db-fragment-definition-builder";
|
|
8
|
-
import {
|
|
14
|
+
import { SqlAdapter } from "../adapters/generic-sql/generic-sql-adapter";
|
|
9
15
|
import { BetterSQLite3DriverConfig } from "../adapters/generic-sql/driver-config";
|
|
10
16
|
import { ExponentialBackoffRetryPolicy, NoRetryPolicy } from "../query/unit-of-work/retry-policy";
|
|
11
17
|
import type { FragnoId } from "../schema/create";
|
|
12
18
|
|
|
13
19
|
describe("Hook System", () => {
|
|
20
|
+
const handlerTx = (() => {
|
|
21
|
+
throw new Error("handlerTx not configured for hooks test");
|
|
22
|
+
}) as HookHandlerTx;
|
|
14
23
|
let sqliteDatabase: SQLite.Database;
|
|
15
|
-
let adapter:
|
|
24
|
+
let adapter: SqlAdapter;
|
|
16
25
|
let internalFragment: ReturnType<typeof instantiateFragment>;
|
|
17
26
|
|
|
18
27
|
function instantiateFragment(options: FragnoPublicConfigWithDatabase) {
|
|
@@ -26,18 +35,19 @@ describe("Hook System", () => {
|
|
|
26
35
|
database: sqliteDatabase,
|
|
27
36
|
});
|
|
28
37
|
|
|
29
|
-
adapter = new
|
|
38
|
+
adapter = new SqlAdapter({
|
|
30
39
|
dialect,
|
|
31
40
|
driverConfig: new BetterSQLite3DriverConfig(),
|
|
32
41
|
});
|
|
33
42
|
|
|
34
43
|
{
|
|
35
|
-
const migrations = adapter.prepareMigrations(internalSchema,
|
|
44
|
+
const migrations = adapter.prepareMigrations(internalSchema, null);
|
|
36
45
|
await migrations.executeWithDriver(adapter.driver, 0);
|
|
37
46
|
}
|
|
38
47
|
|
|
39
48
|
const options: FragnoPublicConfigWithDatabase = {
|
|
40
49
|
databaseAdapter: adapter,
|
|
50
|
+
databaseNamespace: null,
|
|
41
51
|
};
|
|
42
52
|
|
|
43
53
|
internalFragment = instantiateFragment(options);
|
|
@@ -57,8 +67,11 @@ describe("Hook System", () => {
|
|
|
57
67
|
const onBeforeMutate = vi.fn();
|
|
58
68
|
|
|
59
69
|
await internalFragment.inContext(async function () {
|
|
60
|
-
await this.
|
|
61
|
-
|
|
70
|
+
await this.handlerTx({
|
|
71
|
+
onAfterMutate: onSuccess,
|
|
72
|
+
onBeforeMutate,
|
|
73
|
+
})
|
|
74
|
+
.mutate(({ forSchema }) => {
|
|
62
75
|
const uow = forSchema(internalSchema, hooks);
|
|
63
76
|
|
|
64
77
|
// Trigger a hook
|
|
@@ -69,16 +82,11 @@ describe("Hook System", () => {
|
|
|
69
82
|
hooks,
|
|
70
83
|
namespace,
|
|
71
84
|
internalFragment,
|
|
85
|
+
handlerTx,
|
|
72
86
|
defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 5 }),
|
|
73
87
|
});
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
onSuccess,
|
|
79
|
-
onBeforeMutate,
|
|
80
|
-
},
|
|
81
|
-
);
|
|
88
|
+
})
|
|
89
|
+
.execute();
|
|
82
90
|
});
|
|
83
91
|
|
|
84
92
|
// Verify callbacks were executed
|
|
@@ -87,11 +95,12 @@ describe("Hook System", () => {
|
|
|
87
95
|
|
|
88
96
|
// Verify hook was created
|
|
89
97
|
const events = await internalFragment.inContext(async function () {
|
|
90
|
-
return await this.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
98
|
+
return await this.handlerTx()
|
|
99
|
+
.withServiceCalls(
|
|
100
|
+
() => [internalFragment.services.hookService.getPendingHookEvents(namespace)] as const,
|
|
101
|
+
)
|
|
102
|
+
.transform(({ serviceResult: [result] }) => result)
|
|
103
|
+
.execute();
|
|
95
104
|
});
|
|
96
105
|
|
|
97
106
|
expect(events).toHaveLength(1);
|
|
@@ -110,28 +119,30 @@ describe("Hook System", () => {
|
|
|
110
119
|
};
|
|
111
120
|
|
|
112
121
|
await internalFragment.inContext(async function () {
|
|
113
|
-
await this.
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
uow.triggerHook("onNoRetry", { data: "test" });
|
|
122
|
+
await this.handlerTx()
|
|
123
|
+
.mutate(({ forSchema }) => {
|
|
124
|
+
const uow = forSchema(internalSchema, hooks);
|
|
117
125
|
|
|
118
|
-
|
|
119
|
-
hooks,
|
|
120
|
-
namespace,
|
|
121
|
-
internalFragment,
|
|
122
|
-
defaultRetryPolicy: new NoRetryPolicy(),
|
|
123
|
-
});
|
|
126
|
+
uow.triggerHook("onNoRetry", { data: "test" });
|
|
124
127
|
|
|
125
|
-
|
|
126
|
-
|
|
128
|
+
prepareHookMutations(uow, {
|
|
129
|
+
hooks,
|
|
130
|
+
namespace,
|
|
131
|
+
internalFragment,
|
|
132
|
+
handlerTx,
|
|
133
|
+
defaultRetryPolicy: new NoRetryPolicy(),
|
|
134
|
+
});
|
|
135
|
+
})
|
|
136
|
+
.execute();
|
|
127
137
|
});
|
|
128
138
|
|
|
129
139
|
const events = await internalFragment.inContext(async function () {
|
|
130
|
-
return await this.
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
140
|
+
return await this.handlerTx()
|
|
141
|
+
.withServiceCalls(
|
|
142
|
+
() => [internalFragment.services.hookService.getPendingHookEvents(namespace)] as const,
|
|
143
|
+
)
|
|
144
|
+
.transform(({ serviceResult: [result] }) => result)
|
|
145
|
+
.execute();
|
|
135
146
|
});
|
|
136
147
|
|
|
137
148
|
expect(events).toHaveLength(1);
|
|
@@ -145,38 +156,118 @@ describe("Hook System", () => {
|
|
|
145
156
|
};
|
|
146
157
|
|
|
147
158
|
await internalFragment.inContext(async function () {
|
|
148
|
-
await this.
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
uow.triggerHook(
|
|
152
|
-
"onCustomRetry",
|
|
153
|
-
{ data: "test" },
|
|
154
|
-
{
|
|
155
|
-
retryPolicy: new NoRetryPolicy(),
|
|
156
|
-
},
|
|
157
|
-
);
|
|
159
|
+
await this.handlerTx()
|
|
160
|
+
.mutate(({ forSchema }) => {
|
|
161
|
+
const uow = forSchema(internalSchema, hooks);
|
|
158
162
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
163
|
+
uow.triggerHook(
|
|
164
|
+
"onCustomRetry",
|
|
165
|
+
{ data: "test" },
|
|
166
|
+
{
|
|
167
|
+
retryPolicy: new NoRetryPolicy(),
|
|
168
|
+
},
|
|
169
|
+
);
|
|
165
170
|
|
|
166
|
-
|
|
167
|
-
|
|
171
|
+
prepareHookMutations(uow, {
|
|
172
|
+
hooks,
|
|
173
|
+
namespace,
|
|
174
|
+
internalFragment,
|
|
175
|
+
handlerTx,
|
|
176
|
+
defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 10 }),
|
|
177
|
+
});
|
|
178
|
+
})
|
|
179
|
+
.execute();
|
|
168
180
|
});
|
|
169
181
|
|
|
170
182
|
const events = await internalFragment.inContext(async function () {
|
|
171
|
-
return await this.
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
183
|
+
return await this.handlerTx()
|
|
184
|
+
.withServiceCalls(
|
|
185
|
+
() => [internalFragment.services.hookService.getPendingHookEvents(namespace)] as const,
|
|
186
|
+
)
|
|
187
|
+
.transform(({ serviceResult: [result] }) => result)
|
|
188
|
+
.execute();
|
|
176
189
|
});
|
|
177
190
|
|
|
178
191
|
expect(events[0]?.maxAttempts).toBe(1);
|
|
179
192
|
});
|
|
193
|
+
|
|
194
|
+
it("should set nextRetryAt when processAt is in the future", async () => {
|
|
195
|
+
const namespace = "test-process-at-future";
|
|
196
|
+
const hooks: HooksMap = {
|
|
197
|
+
onScheduled: vi.fn(),
|
|
198
|
+
};
|
|
199
|
+
const futureTime = new Date(Date.now() + 60000);
|
|
200
|
+
|
|
201
|
+
await internalFragment.inContext(async function () {
|
|
202
|
+
await this.handlerTx()
|
|
203
|
+
.mutate(({ forSchema }) => {
|
|
204
|
+
const uow = forSchema(internalSchema, hooks);
|
|
205
|
+
|
|
206
|
+
uow.triggerHook("onScheduled", { data: "test" }, { processAt: futureTime });
|
|
207
|
+
|
|
208
|
+
prepareHookMutations(uow, {
|
|
209
|
+
hooks,
|
|
210
|
+
namespace,
|
|
211
|
+
internalFragment,
|
|
212
|
+
handlerTx,
|
|
213
|
+
defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 5 }),
|
|
214
|
+
});
|
|
215
|
+
})
|
|
216
|
+
.execute();
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
const events = await internalFragment.inContext(async function () {
|
|
220
|
+
return await this.handlerTx()
|
|
221
|
+
.withServiceCalls(
|
|
222
|
+
() => [internalFragment.services.hookService.getHooksByNamespace(namespace)] as const,
|
|
223
|
+
)
|
|
224
|
+
.transform(({ serviceResult: [result] }) => result)
|
|
225
|
+
.execute();
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
expect(events).toHaveLength(1);
|
|
229
|
+
expect(events[0]?.nextRetryAt).toBeInstanceOf(Date);
|
|
230
|
+
expect(events[0]?.nextRetryAt?.getTime()).toBe(futureTime.getTime());
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it("should keep processAt in the past while remaining immediately eligible", async () => {
|
|
234
|
+
const namespace = "test-process-at-past";
|
|
235
|
+
const hooks: HooksMap = {
|
|
236
|
+
onImmediate: vi.fn(),
|
|
237
|
+
};
|
|
238
|
+
const pastTime = new Date(Date.now() - 60000);
|
|
239
|
+
|
|
240
|
+
await internalFragment.inContext(async function () {
|
|
241
|
+
await this.handlerTx()
|
|
242
|
+
.mutate(({ forSchema }) => {
|
|
243
|
+
const uow = forSchema(internalSchema, hooks);
|
|
244
|
+
|
|
245
|
+
uow.triggerHook("onImmediate", { data: "test" }, { processAt: pastTime });
|
|
246
|
+
|
|
247
|
+
prepareHookMutations(uow, {
|
|
248
|
+
hooks,
|
|
249
|
+
namespace,
|
|
250
|
+
internalFragment,
|
|
251
|
+
handlerTx,
|
|
252
|
+
defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 5 }),
|
|
253
|
+
});
|
|
254
|
+
})
|
|
255
|
+
.execute();
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
const events = await internalFragment.inContext(async function () {
|
|
259
|
+
return await this.handlerTx()
|
|
260
|
+
.withServiceCalls(
|
|
261
|
+
() => [internalFragment.services.hookService.getHooksByNamespace(namespace)] as const,
|
|
262
|
+
)
|
|
263
|
+
.transform(({ serviceResult: [result] }) => result)
|
|
264
|
+
.execute();
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
expect(events).toHaveLength(1);
|
|
268
|
+
expect(events[0]?.nextRetryAt).toBeInstanceOf(Date);
|
|
269
|
+
expect(events[0]?.nextRetryAt?.getTime()).toBe(pastTime.getTime());
|
|
270
|
+
});
|
|
180
271
|
});
|
|
181
272
|
|
|
182
273
|
describe("processHooks", () => {
|
|
@@ -191,22 +282,24 @@ describe("Hook System", () => {
|
|
|
191
282
|
|
|
192
283
|
// Create a pending hook event
|
|
193
284
|
await internalFragment.inContext(async function () {
|
|
194
|
-
await this.
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
285
|
+
const createdId = await this.handlerTx()
|
|
286
|
+
.mutate(({ forSchema }) => {
|
|
287
|
+
const uow = forSchema(internalSchema);
|
|
288
|
+
return uow.create("fragno_hooks", {
|
|
289
|
+
namespace,
|
|
290
|
+
hookName: "onSuccess",
|
|
291
|
+
payload: { email: "test@example.com" },
|
|
292
|
+
status: "pending",
|
|
293
|
+
attempts: 0,
|
|
294
|
+
maxAttempts: 5,
|
|
295
|
+
lastAttemptAt: null,
|
|
296
|
+
nextRetryAt: null,
|
|
297
|
+
error: null,
|
|
298
|
+
nonce: "test-nonce",
|
|
299
|
+
});
|
|
300
|
+
})
|
|
301
|
+
.execute();
|
|
302
|
+
eventId = createdId;
|
|
210
303
|
});
|
|
211
304
|
|
|
212
305
|
// Process hooks
|
|
@@ -214,6 +307,7 @@ describe("Hook System", () => {
|
|
|
214
307
|
hooks,
|
|
215
308
|
namespace,
|
|
216
309
|
internalFragment,
|
|
310
|
+
handlerTx,
|
|
217
311
|
defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 3 }),
|
|
218
312
|
});
|
|
219
313
|
|
|
@@ -223,19 +317,16 @@ describe("Hook System", () => {
|
|
|
223
317
|
|
|
224
318
|
// Verify hook context (this)
|
|
225
319
|
const hookContext = hookFn.mock.contexts[0] as HookContext;
|
|
226
|
-
expect(hookContext.
|
|
320
|
+
expect(hookContext.idempotencyKey).toBe("test-nonce");
|
|
227
321
|
|
|
228
322
|
// Verify event was marked as completed
|
|
229
323
|
const result = await internalFragment.inContext(async function () {
|
|
230
|
-
return await this.
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
)
|
|
235
|
-
|
|
236
|
-
const [events] = await findUow.retrievalPhase;
|
|
237
|
-
return events?.[0];
|
|
238
|
-
});
|
|
324
|
+
return await this.handlerTx()
|
|
325
|
+
.withServiceCalls(
|
|
326
|
+
() => [internalFragment.services.hookService.getHookById(eventId)] as const,
|
|
327
|
+
)
|
|
328
|
+
.transform(({ serviceResult: [event] }) => event)
|
|
329
|
+
.execute();
|
|
239
330
|
});
|
|
240
331
|
|
|
241
332
|
expect(result?.status).toBe("completed");
|
|
@@ -252,43 +343,43 @@ describe("Hook System", () => {
|
|
|
252
343
|
let eventId: FragnoId;
|
|
253
344
|
|
|
254
345
|
await internalFragment.inContext(async function () {
|
|
255
|
-
await this.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
346
|
+
const createdId = await this.handlerTx()
|
|
347
|
+
.mutate(({ forSchema }) => {
|
|
348
|
+
const uow = forSchema(internalSchema);
|
|
349
|
+
return uow.create("fragno_hooks", {
|
|
350
|
+
namespace,
|
|
351
|
+
hookName: "onFailure",
|
|
352
|
+
payload: { data: "test" },
|
|
353
|
+
status: "pending",
|
|
354
|
+
attempts: 0,
|
|
355
|
+
maxAttempts: 5,
|
|
356
|
+
lastAttemptAt: null,
|
|
357
|
+
nextRetryAt: null,
|
|
358
|
+
error: null,
|
|
359
|
+
nonce: "test-nonce",
|
|
360
|
+
});
|
|
361
|
+
})
|
|
362
|
+
.execute();
|
|
363
|
+
eventId = createdId;
|
|
271
364
|
});
|
|
272
365
|
|
|
273
366
|
await processHooks({
|
|
274
367
|
hooks,
|
|
275
368
|
namespace,
|
|
276
369
|
internalFragment,
|
|
370
|
+
handlerTx,
|
|
277
371
|
defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 3 }),
|
|
278
372
|
});
|
|
279
373
|
|
|
280
374
|
expect(hookFn).toHaveBeenCalledOnce();
|
|
281
375
|
|
|
282
376
|
const result = await internalFragment.inContext(async function () {
|
|
283
|
-
return await this.
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
)
|
|
288
|
-
|
|
289
|
-
const [events] = await findUow.retrievalPhase;
|
|
290
|
-
return events?.[0];
|
|
291
|
-
});
|
|
377
|
+
return await this.handlerTx()
|
|
378
|
+
.withServiceCalls(
|
|
379
|
+
() => [internalFragment.services.hookService.getHookById(eventId)] as const,
|
|
380
|
+
)
|
|
381
|
+
.transform(({ serviceResult: [event] }) => event)
|
|
382
|
+
.execute();
|
|
292
383
|
});
|
|
293
384
|
|
|
294
385
|
expect(result?.status).toBe("pending");
|
|
@@ -307,41 +398,41 @@ describe("Hook System", () => {
|
|
|
307
398
|
let eventId: FragnoId;
|
|
308
399
|
|
|
309
400
|
await internalFragment.inContext(async function () {
|
|
310
|
-
await this.
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
401
|
+
const createdId = await this.handlerTx()
|
|
402
|
+
.mutate(({ forSchema }) => {
|
|
403
|
+
const uow = forSchema(internalSchema);
|
|
404
|
+
return uow.create("fragno_hooks", {
|
|
405
|
+
namespace,
|
|
406
|
+
hookName: "onMaxRetries",
|
|
407
|
+
payload: { data: "test" },
|
|
408
|
+
status: "pending",
|
|
409
|
+
attempts: 0,
|
|
410
|
+
maxAttempts: 1,
|
|
411
|
+
lastAttemptAt: null,
|
|
412
|
+
nextRetryAt: null,
|
|
413
|
+
error: null,
|
|
414
|
+
nonce: "test-nonce",
|
|
415
|
+
});
|
|
416
|
+
})
|
|
417
|
+
.execute();
|
|
418
|
+
eventId = createdId;
|
|
326
419
|
});
|
|
327
420
|
|
|
328
421
|
await processHooks({
|
|
329
422
|
hooks,
|
|
330
423
|
namespace,
|
|
331
424
|
internalFragment,
|
|
425
|
+
handlerTx,
|
|
332
426
|
defaultRetryPolicy: new NoRetryPolicy(),
|
|
333
427
|
});
|
|
334
428
|
|
|
335
429
|
const result = await internalFragment.inContext(async function () {
|
|
336
|
-
return await this.
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
)
|
|
341
|
-
|
|
342
|
-
const [events] = await findUow.retrievalPhase;
|
|
343
|
-
return events?.[0];
|
|
344
|
-
});
|
|
430
|
+
return await this.handlerTx()
|
|
431
|
+
.withServiceCalls(
|
|
432
|
+
() => [internalFragment.services.hookService.getHookById(eventId)] as const,
|
|
433
|
+
)
|
|
434
|
+
.transform(({ serviceResult: [event] }) => event)
|
|
435
|
+
.execute();
|
|
345
436
|
});
|
|
346
437
|
|
|
347
438
|
expect(result?.status).toBe("failed");
|
|
@@ -358,47 +449,109 @@ describe("Hook System", () => {
|
|
|
358
449
|
let eventId: FragnoId;
|
|
359
450
|
|
|
360
451
|
await internalFragment.inContext(async function () {
|
|
361
|
-
await this.
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
452
|
+
const createdId = await this.handlerTx()
|
|
453
|
+
.mutate(({ forSchema }) => {
|
|
454
|
+
const uow = forSchema(internalSchema);
|
|
455
|
+
return uow.create("fragno_hooks", {
|
|
456
|
+
namespace,
|
|
457
|
+
hookName: "onMissing",
|
|
458
|
+
payload: { data: "test" },
|
|
459
|
+
status: "pending",
|
|
460
|
+
attempts: 0,
|
|
461
|
+
maxAttempts: 1,
|
|
462
|
+
lastAttemptAt: null,
|
|
463
|
+
nextRetryAt: null,
|
|
464
|
+
error: null,
|
|
465
|
+
nonce: "test-nonce",
|
|
466
|
+
});
|
|
467
|
+
})
|
|
468
|
+
.execute();
|
|
469
|
+
eventId = createdId;
|
|
377
470
|
});
|
|
378
471
|
|
|
379
472
|
await processHooks({
|
|
380
473
|
hooks,
|
|
381
474
|
namespace,
|
|
382
475
|
internalFragment,
|
|
476
|
+
handlerTx,
|
|
383
477
|
defaultRetryPolicy: new NoRetryPolicy(),
|
|
384
478
|
});
|
|
385
479
|
|
|
386
480
|
const result = await internalFragment.inContext(async function () {
|
|
387
|
-
return await this.
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
)
|
|
392
|
-
|
|
393
|
-
const [events] = await findUow.retrievalPhase;
|
|
394
|
-
return events?.[0];
|
|
395
|
-
});
|
|
481
|
+
return await this.handlerTx()
|
|
482
|
+
.withServiceCalls(
|
|
483
|
+
() => [internalFragment.services.hookService.getHookById(eventId)] as const,
|
|
484
|
+
)
|
|
485
|
+
.transform(({ serviceResult: [event] }) => event)
|
|
486
|
+
.execute();
|
|
396
487
|
});
|
|
397
488
|
|
|
398
489
|
expect(result?.status).toBe("failed");
|
|
399
490
|
expect(result?.error).toBe("Hook 'onMissing' not found in hooks map");
|
|
400
491
|
});
|
|
401
492
|
|
|
493
|
+
it("should re-queue stuck processing hooks and call the handler", async () => {
|
|
494
|
+
const namespace = "test-stuck-processing";
|
|
495
|
+
const hookFn = vi.fn();
|
|
496
|
+
const hooks: HooksMap = {
|
|
497
|
+
onStuck: hookFn,
|
|
498
|
+
};
|
|
499
|
+
const onStuckProcessingHooks = vi.fn();
|
|
500
|
+
|
|
501
|
+
let eventId: FragnoId;
|
|
502
|
+
|
|
503
|
+
await internalFragment.inContext(async function () {
|
|
504
|
+
const createdId = await this.handlerTx()
|
|
505
|
+
.mutate(({ forSchema }) => {
|
|
506
|
+
const uow = forSchema(internalSchema);
|
|
507
|
+
return uow.create("fragno_hooks", {
|
|
508
|
+
namespace,
|
|
509
|
+
hookName: "onStuck",
|
|
510
|
+
payload: { ok: true },
|
|
511
|
+
status: "processing",
|
|
512
|
+
attempts: 0,
|
|
513
|
+
maxAttempts: 5,
|
|
514
|
+
lastAttemptAt: new Date(Date.now() - 20 * 60_000),
|
|
515
|
+
nextRetryAt: null,
|
|
516
|
+
error: null,
|
|
517
|
+
nonce: "test-nonce",
|
|
518
|
+
});
|
|
519
|
+
})
|
|
520
|
+
.execute();
|
|
521
|
+
eventId = createdId;
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
await processHooks({
|
|
525
|
+
hooks,
|
|
526
|
+
namespace,
|
|
527
|
+
internalFragment,
|
|
528
|
+
handlerTx,
|
|
529
|
+
stuckProcessingTimeoutMinutes: 1,
|
|
530
|
+
onStuckProcessingHooks,
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
expect(hookFn).toHaveBeenCalledOnce();
|
|
534
|
+
expect(onStuckProcessingHooks).toHaveBeenCalledOnce();
|
|
535
|
+
expect(onStuckProcessingHooks).toHaveBeenCalledWith(
|
|
536
|
+
expect.objectContaining({
|
|
537
|
+
namespace,
|
|
538
|
+
timeoutMinutes: 1,
|
|
539
|
+
events: [expect.objectContaining({ hookName: "onStuck" })],
|
|
540
|
+
}),
|
|
541
|
+
);
|
|
542
|
+
|
|
543
|
+
const result = await internalFragment.inContext(async function () {
|
|
544
|
+
return await this.handlerTx()
|
|
545
|
+
.withServiceCalls(
|
|
546
|
+
() => [internalFragment.services.hookService.getHookById(eventId)] as const,
|
|
547
|
+
)
|
|
548
|
+
.transform(({ serviceResult: [event] }) => event)
|
|
549
|
+
.execute();
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
expect(result?.status).toBe("completed");
|
|
553
|
+
});
|
|
554
|
+
|
|
402
555
|
it("should process multiple hooks in parallel", async () => {
|
|
403
556
|
const namespace = "test-parallel";
|
|
404
557
|
const hook1 = vi.fn();
|
|
@@ -411,52 +564,54 @@ describe("Hook System", () => {
|
|
|
411
564
|
};
|
|
412
565
|
|
|
413
566
|
await internalFragment.inContext(async function () {
|
|
414
|
-
await this.
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
567
|
+
await this.handlerTx()
|
|
568
|
+
.mutate(({ forSchema }) => {
|
|
569
|
+
const uow = forSchema(internalSchema);
|
|
570
|
+
uow.create("fragno_hooks", {
|
|
571
|
+
namespace,
|
|
572
|
+
hookName: "onHook1",
|
|
573
|
+
payload: { id: 1 },
|
|
574
|
+
status: "pending",
|
|
575
|
+
attempts: 0,
|
|
576
|
+
maxAttempts: 5,
|
|
577
|
+
lastAttemptAt: null,
|
|
578
|
+
nextRetryAt: null,
|
|
579
|
+
error: null,
|
|
580
|
+
nonce: "nonce-1",
|
|
581
|
+
});
|
|
582
|
+
uow.create("fragno_hooks", {
|
|
583
|
+
namespace,
|
|
584
|
+
hookName: "onHook2",
|
|
585
|
+
payload: { id: 2 },
|
|
586
|
+
status: "pending",
|
|
587
|
+
attempts: 0,
|
|
588
|
+
maxAttempts: 5,
|
|
589
|
+
lastAttemptAt: null,
|
|
590
|
+
nextRetryAt: null,
|
|
591
|
+
error: null,
|
|
592
|
+
nonce: "nonce-2",
|
|
593
|
+
});
|
|
594
|
+
uow.create("fragno_hooks", {
|
|
595
|
+
namespace,
|
|
596
|
+
hookName: "onHook3",
|
|
597
|
+
payload: { id: 3 },
|
|
598
|
+
status: "pending",
|
|
599
|
+
attempts: 0,
|
|
600
|
+
maxAttempts: 5,
|
|
601
|
+
lastAttemptAt: null,
|
|
602
|
+
nextRetryAt: null,
|
|
603
|
+
error: null,
|
|
604
|
+
nonce: "nonce-3",
|
|
605
|
+
});
|
|
606
|
+
})
|
|
607
|
+
.execute();
|
|
454
608
|
});
|
|
455
609
|
|
|
456
610
|
await processHooks({
|
|
457
611
|
hooks,
|
|
458
612
|
namespace,
|
|
459
613
|
internalFragment,
|
|
614
|
+
handlerTx,
|
|
460
615
|
defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 3 }),
|
|
461
616
|
});
|
|
462
617
|
|
|
@@ -466,15 +621,12 @@ describe("Hook System", () => {
|
|
|
466
621
|
|
|
467
622
|
// Verify all were marked as completed
|
|
468
623
|
const events = await internalFragment.inContext(async function () {
|
|
469
|
-
return await this.
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
)
|
|
474
|
-
|
|
475
|
-
const [results] = await findUow.retrievalPhase;
|
|
476
|
-
return results;
|
|
477
|
-
});
|
|
624
|
+
return await this.handlerTx()
|
|
625
|
+
.withServiceCalls(
|
|
626
|
+
() => [internalFragment.services.hookService.getHooksByNamespace(namespace)] as const,
|
|
627
|
+
)
|
|
628
|
+
.transform(({ serviceResult: [result] }) => result)
|
|
629
|
+
.execute();
|
|
478
630
|
});
|
|
479
631
|
|
|
480
632
|
const completed = events.filter((e) => e.status === "completed");
|
|
@@ -493,52 +645,54 @@ describe("Hook System", () => {
|
|
|
493
645
|
};
|
|
494
646
|
|
|
495
647
|
await internalFragment.inContext(async function () {
|
|
496
|
-
await this.
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
648
|
+
await this.handlerTx()
|
|
649
|
+
.mutate(({ forSchema }) => {
|
|
650
|
+
const uow = forSchema(internalSchema);
|
|
651
|
+
uow.create("fragno_hooks", {
|
|
652
|
+
namespace,
|
|
653
|
+
hookName: "onHook1",
|
|
654
|
+
payload: { id: 1 },
|
|
655
|
+
status: "pending",
|
|
656
|
+
attempts: 0,
|
|
657
|
+
maxAttempts: 5,
|
|
658
|
+
lastAttemptAt: null,
|
|
659
|
+
nextRetryAt: null,
|
|
660
|
+
error: null,
|
|
661
|
+
nonce: "nonce-1",
|
|
662
|
+
});
|
|
663
|
+
uow.create("fragno_hooks", {
|
|
664
|
+
namespace,
|
|
665
|
+
hookName: "onHook2",
|
|
666
|
+
payload: { id: 2 },
|
|
667
|
+
status: "pending",
|
|
668
|
+
attempts: 0,
|
|
669
|
+
maxAttempts: 5,
|
|
670
|
+
lastAttemptAt: null,
|
|
671
|
+
nextRetryAt: null,
|
|
672
|
+
error: null,
|
|
673
|
+
nonce: "nonce-2",
|
|
674
|
+
});
|
|
675
|
+
uow.create("fragno_hooks", {
|
|
676
|
+
namespace,
|
|
677
|
+
hookName: "onHook3",
|
|
678
|
+
payload: { id: 3 },
|
|
679
|
+
status: "pending",
|
|
680
|
+
attempts: 0,
|
|
681
|
+
maxAttempts: 5,
|
|
682
|
+
lastAttemptAt: null,
|
|
683
|
+
nextRetryAt: null,
|
|
684
|
+
error: null,
|
|
685
|
+
nonce: "nonce-3",
|
|
686
|
+
});
|
|
687
|
+
})
|
|
688
|
+
.execute();
|
|
536
689
|
});
|
|
537
690
|
|
|
538
691
|
await processHooks({
|
|
539
692
|
hooks,
|
|
540
693
|
namespace,
|
|
541
694
|
internalFragment,
|
|
695
|
+
handlerTx,
|
|
542
696
|
defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 3 }),
|
|
543
697
|
});
|
|
544
698
|
|
|
@@ -548,15 +702,12 @@ describe("Hook System", () => {
|
|
|
548
702
|
|
|
549
703
|
// Verify hook1 and hook3 were completed, hook2 was marked for retry
|
|
550
704
|
const events = await internalFragment.inContext(async function () {
|
|
551
|
-
return await this.
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
)
|
|
556
|
-
|
|
557
|
-
const [results] = await findUow.retrievalPhase;
|
|
558
|
-
return results;
|
|
559
|
-
});
|
|
705
|
+
return await this.handlerTx()
|
|
706
|
+
.withServiceCalls(
|
|
707
|
+
() => [internalFragment.services.hookService.getHooksByNamespace(namespace)] as const,
|
|
708
|
+
)
|
|
709
|
+
.transform(({ serviceResult: [result] }) => result)
|
|
710
|
+
.execute();
|
|
560
711
|
});
|
|
561
712
|
|
|
562
713
|
const completed = events.filter((e) => e.status === "completed");
|
|
@@ -578,6 +729,7 @@ describe("Hook System", () => {
|
|
|
578
729
|
hooks,
|
|
579
730
|
namespace,
|
|
580
731
|
internalFragment,
|
|
732
|
+
handlerTx,
|
|
581
733
|
defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 3 }),
|
|
582
734
|
});
|
|
583
735
|
|