@fragno-dev/db 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +327 -160
- package/CHANGELOG.md +74 -0
- package/README.md +24 -0
- package/dist/adapters/adapters.d.ts +1 -1
- package/dist/adapters/adapters.d.ts.map +1 -1
- package/dist/adapters/adapters.js.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-adapter.d.ts +0 -3
- package/dist/adapters/generic-sql/generic-sql-adapter.d.ts.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-adapter.js +11 -12
- package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-uow-executor.js +46 -6
- package/dist/adapters/generic-sql/generic-sql-uow-executor.js.map +1 -1
- package/dist/adapters/generic-sql/migration/cold-kysely.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/mysql.js +1 -1
- package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/postgres.js +1 -1
- package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/sqlite.js +185 -19
- package/dist/adapters/generic-sql/migration/dialect/sqlite.js.map +1 -1
- package/dist/adapters/generic-sql/migration/executor.d.ts.map +1 -1
- package/dist/adapters/generic-sql/migration/executor.js +30 -3
- package/dist/adapters/generic-sql/migration/executor.js.map +1 -1
- package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -1
- package/dist/adapters/generic-sql/migration/prepared-migrations.js +3 -3
- package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -1
- package/dist/adapters/generic-sql/migration/sql-generator.js +1 -1
- package/dist/adapters/generic-sql/migration/sql-generator.js.map +1 -1
- package/dist/adapters/generic-sql/query/create-sql-query-compiler.js +1 -1
- package/dist/adapters/generic-sql/query/create-sql-query-compiler.js.map +1 -1
- package/dist/adapters/generic-sql/query/cursor-utils.js.map +1 -1
- package/dist/adapters/generic-sql/query/db-now-sql.js +27 -0
- package/dist/adapters/generic-sql/query/db-now-sql.js.map +1 -0
- package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js +9 -6
- package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js.map +1 -1
- package/dist/adapters/generic-sql/query/select-builder.js.map +1 -1
- package/dist/adapters/generic-sql/query/sql-query-compiler.js +37 -9
- package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -1
- package/dist/adapters/generic-sql/query/where-builder.js +24 -20
- package/dist/adapters/generic-sql/query/where-builder.js.map +1 -1
- package/dist/adapters/generic-sql/uow-decoder.js +1 -1
- package/dist/adapters/generic-sql/uow-decoder.js.map +1 -1
- package/dist/adapters/generic-sql/uow-encoder.js +8 -9
- package/dist/adapters/generic-sql/uow-encoder.js.map +1 -1
- package/dist/adapters/in-memory/condition-evaluator.js +10 -6
- package/dist/adapters/in-memory/condition-evaluator.js.map +1 -1
- package/dist/adapters/in-memory/in-memory-adapter.d.ts.map +1 -1
- package/dist/adapters/in-memory/in-memory-adapter.js +45 -25
- package/dist/adapters/in-memory/in-memory-adapter.js.map +1 -1
- package/dist/adapters/in-memory/in-memory-uow.js +236 -13
- package/dist/adapters/in-memory/in-memory-uow.js.map +1 -1
- package/dist/adapters/in-memory/options.d.ts +2 -0
- package/dist/adapters/in-memory/options.d.ts.map +1 -1
- package/dist/adapters/in-memory/options.js +3 -2
- package/dist/adapters/in-memory/options.js.map +1 -1
- package/dist/adapters/in-memory/reference-resolution.js.map +1 -1
- package/dist/adapters/in-memory/store.js +1 -1
- package/dist/adapters/in-memory/store.js.map +1 -1
- package/dist/adapters/shared/from-unit-of-work-compiler.js +51 -24
- package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -1
- package/dist/adapters/shared/uow-operation-compiler.js.map +1 -1
- package/dist/browser/adapters/adapters.d.ts +61 -0
- package/dist/browser/adapters/adapters.d.ts.map +1 -0
- package/dist/browser/adapters/generic-sql/migration/executor.d.ts +15 -0
- package/dist/browser/adapters/generic-sql/migration/executor.d.ts.map +1 -0
- package/dist/browser/adapters/generic-sql/migration/prepared-migrations.d.ts +66 -0
- package/dist/browser/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -0
- package/dist/browser/adapters/generic-sql/sqlite-storage.d.ts +11 -0
- package/dist/browser/adapters/generic-sql/sqlite-storage.d.ts.map +1 -0
- package/dist/browser/adapters/in-memory/in-memory-adapter.d.ts +5 -0
- package/dist/browser/adapters/in-memory/index.d.ts +2 -0
- package/dist/browser/adapters/in-memory/options.d.ts +1 -0
- package/dist/browser/db-fragment-definition-builder.d.ts +237 -0
- package/dist/browser/db-fragment-definition-builder.d.ts.map +1 -0
- package/dist/browser/durable-hooks.d.ts +3 -0
- package/dist/browser/fragments/internal-fragment.d.ts +317 -0
- package/dist/browser/fragments/internal-fragment.d.ts.map +1 -0
- package/dist/browser/fragments/internal-fragment.schema.d.ts +1 -0
- package/dist/browser/hooks/durable-hooks-logger.d.ts +10 -0
- package/dist/browser/hooks/durable-hooks-logger.d.ts.map +1 -0
- package/dist/browser/hooks/hooks.d.ts +146 -0
- package/dist/browser/hooks/hooks.d.ts.map +1 -0
- package/dist/browser/id.js +1 -0
- package/dist/browser/internal/adapter-registry.d.ts +4 -0
- package/dist/browser/internal/outbox-state.d.ts +2 -0
- package/dist/browser/mod.d.ts +15 -0
- package/dist/browser/mod.d.ts.map +1 -0
- package/dist/browser/mod.js +17 -0
- package/dist/browser/mod.js.map +1 -0
- package/dist/browser/mod2.d.ts +48 -0
- package/dist/browser/mod2.d.ts.map +1 -0
- package/dist/browser/naming/sql-naming.d.ts +19 -0
- package/dist/browser/naming/sql-naming.d.ts.map +1 -0
- package/dist/browser/outbox/outbox.d.ts +21 -0
- package/dist/browser/outbox/outbox.d.ts.map +1 -0
- package/dist/browser/query/column-defaults.js +1 -0
- package/dist/browser/query/condition-builder.d.ts +44 -0
- package/dist/browser/query/condition-builder.d.ts.map +1 -0
- package/dist/browser/query/condition-builder.js +97 -0
- package/dist/browser/query/condition-builder.js.map +1 -0
- package/dist/browser/query/cursor.d.ts +105 -0
- package/dist/browser/query/cursor.d.ts.map +1 -0
- package/dist/browser/query/cursor.js +150 -0
- package/dist/browser/query/cursor.js.map +1 -0
- package/dist/browser/query/db-now.d.ts +22 -0
- package/dist/browser/query/db-now.d.ts.map +1 -0
- package/dist/browser/query/db-now.js +33 -0
- package/dist/browser/query/db-now.js.map +1 -0
- package/dist/browser/query/orm/orm.d.ts +18 -0
- package/dist/browser/query/orm/orm.d.ts.map +1 -0
- package/dist/browser/query/simple-query-interface.d.ts +108 -0
- package/dist/browser/query/simple-query-interface.d.ts.map +1 -0
- package/dist/browser/query/unit-of-work/execute-unit-of-work.d.ts +423 -0
- package/dist/browser/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -0
- package/dist/browser/query/unit-of-work/execute-unit-of-work.js +507 -0
- package/dist/browser/query/unit-of-work/execute-unit-of-work.js.map +1 -0
- package/dist/browser/query/unit-of-work/retry-policy.d.ts +23 -0
- package/dist/browser/query/unit-of-work/retry-policy.d.ts.map +1 -0
- package/dist/browser/query/unit-of-work/retry-policy.js +40 -0
- package/dist/browser/query/unit-of-work/retry-policy.js.map +1 -0
- package/dist/browser/query/unit-of-work/unit-of-work.d.ts +703 -0
- package/dist/browser/query/unit-of-work/unit-of-work.d.ts.map +1 -0
- package/dist/browser/query/unit-of-work/unit-of-work.js +1206 -0
- package/dist/browser/query/unit-of-work/unit-of-work.js.map +1 -0
- package/dist/browser/query/value-encoding.js +38 -0
- package/dist/browser/query/value-encoding.js.map +1 -0
- package/dist/browser/schema/create.d.ts +326 -0
- package/dist/browser/schema/create.d.ts.map +1 -0
- package/dist/browser/schema/create.js +89 -0
- package/dist/browser/schema/create.js.map +1 -0
- package/dist/browser/schema/generate-id.js +28 -0
- package/dist/browser/schema/generate-id.js.map +1 -0
- package/dist/browser/shared/providers.d.ts +6 -0
- package/dist/browser/shared/providers.d.ts.map +1 -0
- package/dist/browser/sql-driver/connection/connection-provider.d.ts +13 -0
- package/dist/browser/sql-driver/connection/connection-provider.d.ts.map +1 -0
- package/dist/browser/sql-driver/dialect-adapter/dialect-adapter.d.ts +7 -0
- package/dist/browser/sql-driver/dialect-adapter/dialect-adapter.d.ts.map +1 -0
- package/dist/browser/sql-driver/driver/runtime-driver.d.ts +23 -0
- package/dist/browser/sql-driver/driver/runtime-driver.d.ts.map +1 -0
- package/dist/browser/sql-driver/query-executor/plugin.d.ts +17 -0
- package/dist/browser/sql-driver/query-executor/plugin.d.ts.map +1 -0
- package/dist/browser/sql-driver/query-executor/query-executor.d.ts +36 -0
- package/dist/browser/sql-driver/query-executor/query-executor.d.ts.map +1 -0
- package/dist/browser/sql-driver/sql-driver-adapter.d.ts +29 -0
- package/dist/browser/sql-driver/sql-driver-adapter.d.ts.map +1 -0
- package/dist/browser/sql-driver/sql-driver.d.ts +38 -0
- package/dist/browser/sql-driver/sql-driver.d.ts.map +1 -0
- package/dist/browser/sync/commands.d.ts +15 -0
- package/dist/browser/sync/commands.d.ts.map +1 -0
- package/dist/browser/sync/commands.js +27 -0
- package/dist/browser/sync/commands.js.map +1 -0
- package/dist/browser/sync/types.d.ts +63 -0
- package/dist/browser/sync/types.d.ts.map +1 -0
- package/dist/browser/util/types.d.ts +8 -0
- package/dist/browser/util/types.d.ts.map +1 -0
- package/dist/browser/with-database.d.ts +29 -0
- package/dist/browser/with-database.d.ts.map +1 -0
- package/dist/client.d.ts +4 -0
- package/dist/client.js +5 -0
- package/dist/db-fragment-definition-builder.d.ts +85 -28
- package/dist/db-fragment-definition-builder.d.ts.map +1 -1
- package/dist/db-fragment-definition-builder.js +374 -46
- package/dist/db-fragment-definition-builder.js.map +1 -1
- package/dist/dispatchers/cloudflare-do/dispatcher.d.ts +20 -0
- package/dist/dispatchers/cloudflare-do/dispatcher.d.ts.map +1 -0
- package/dist/dispatchers/cloudflare-do/dispatcher.js +147 -0
- package/dist/dispatchers/cloudflare-do/dispatcher.js.map +1 -0
- package/dist/dispatchers/cloudflare-do/index.d.ts +5 -20
- package/dist/dispatchers/cloudflare-do/index.d.ts.map +1 -1
- package/dist/dispatchers/cloudflare-do/index.js +23 -55
- package/dist/dispatchers/cloudflare-do/index.js.map +1 -1
- package/dist/dispatchers/node/dispatcher.d.ts +14 -0
- package/dist/dispatchers/node/dispatcher.d.ts.map +1 -0
- package/dist/dispatchers/node/dispatcher.js +80 -0
- package/dist/dispatchers/node/dispatcher.js.map +1 -0
- package/dist/dispatchers/node/index.d.ts +5 -10
- package/dist/dispatchers/node/index.d.ts.map +1 -1
- package/dist/dispatchers/node/index.js +21 -53
- package/dist/dispatchers/node/index.js.map +1 -1
- package/dist/durable-hooks.d.ts +31 -0
- package/dist/durable-hooks.d.ts.map +1 -0
- package/dist/durable-hooks.js +23 -0
- package/dist/durable-hooks.js.map +1 -0
- package/dist/fragments/internal-fragment.d.ts +128 -27
- package/dist/fragments/internal-fragment.d.ts.map +1 -1
- package/dist/fragments/internal-fragment.js +125 -78
- package/dist/fragments/internal-fragment.js.map +1 -1
- package/dist/fragments/internal-fragment.routes.js +138 -3
- package/dist/fragments/internal-fragment.routes.js.map +1 -1
- package/dist/fragments/internal-fragment.schema.d.ts +7 -1
- package/dist/fragments/internal-fragment.schema.d.ts.map +1 -1
- package/dist/fragments/internal-fragment.schema.js +18 -1
- package/dist/fragments/internal-fragment.schema.js.map +1 -1
- package/dist/hooks/durable-hooks-logger.d.ts +10 -0
- package/dist/hooks/durable-hooks-logger.d.ts.map +1 -0
- package/dist/hooks/durable-hooks-logger.js +75 -0
- package/dist/hooks/durable-hooks-logger.js.map +1 -0
- package/dist/hooks/durable-hooks-processor.d.ts +1 -14
- package/dist/hooks/durable-hooks-processor.js +58 -10
- package/dist/hooks/durable-hooks-processor.js.map +1 -1
- package/dist/hooks/durable-hooks-runtime.js +44 -0
- package/dist/hooks/durable-hooks-runtime.js.map +1 -0
- package/dist/hooks/hooks.d.ts +60 -2
- package/dist/hooks/hooks.d.ts.map +1 -1
- package/dist/hooks/hooks.js +214 -53
- package/dist/hooks/hooks.js.map +1 -1
- package/dist/id.d.ts +2 -2
- package/dist/id.js +2 -2
- package/dist/internal/adapter-registry.d.ts +11 -0
- package/dist/internal/adapter-registry.d.ts.map +1 -0
- package/dist/internal/adapter-registry.js +135 -0
- package/dist/internal/adapter-registry.js.map +1 -0
- package/dist/internal/outbox-state.d.ts +2 -0
- package/dist/internal/outbox-state.js +26 -0
- package/dist/internal/outbox-state.js.map +1 -0
- package/dist/migration-engine/auto-from-schema.d.ts +33 -0
- package/dist/migration-engine/auto-from-schema.d.ts.map +1 -0
- package/dist/migration-engine/auto-from-schema.js +210 -27
- package/dist/migration-engine/auto-from-schema.js.map +1 -1
- package/dist/migration-engine/generation-engine.d.ts.map +1 -1
- package/dist/migration-engine/generation-engine.js +17 -5
- package/dist/migration-engine/generation-engine.js.map +1 -1
- package/dist/migration-engine/shared.d.ts +113 -0
- package/dist/migration-engine/shared.d.ts.map +1 -0
- package/dist/migration-engine/shared.js.map +1 -1
- package/dist/mod.d.ts +12 -11
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +10 -10
- package/dist/mod.js.map +1 -1
- package/dist/naming/sql-naming.d.ts.map +1 -1
- package/dist/naming/sql-naming.js.map +1 -1
- package/dist/outbox/outbox-builder.js.map +1 -1
- package/dist/outbox/outbox.d.ts +3 -1
- package/dist/outbox/outbox.d.ts.map +1 -1
- package/dist/outbox/outbox.js.map +1 -1
- package/dist/query/column-defaults.js.map +1 -1
- package/dist/query/condition-builder.d.ts +7 -1
- package/dist/query/condition-builder.d.ts.map +1 -1
- package/dist/query/condition-builder.js +5 -1
- package/dist/query/condition-builder.js.map +1 -1
- package/dist/query/cursor-client.d.ts +105 -0
- package/dist/query/cursor-client.d.ts.map +1 -0
- package/dist/query/cursor-client.js +165 -0
- package/dist/query/cursor-client.js.map +1 -0
- package/dist/query/cursor.d.ts.map +1 -1
- package/dist/query/cursor.js +7 -1
- package/dist/query/cursor.js.map +1 -1
- package/dist/query/db-now.d.ts +15 -1
- package/dist/query/db-now.d.ts.map +1 -1
- package/dist/query/db-now.js +30 -2
- package/dist/query/db-now.js.map +1 -1
- package/dist/query/orm/orm.js.map +1 -1
- package/dist/query/serialize/create-sql-serializer.js +2 -2
- package/dist/query/serialize/create-sql-serializer.js.map +1 -1
- package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -1
- package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -1
- package/dist/query/serialize/dialect/sqlite-serializer.js +6 -2
- package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -1
- package/dist/query/simple-query-interface.d.ts +7 -3
- package/dist/query/simple-query-interface.d.ts.map +1 -1
- package/dist/query/unit-of-work/execute-unit-of-work.d.ts +37 -2
- package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work/execute-unit-of-work.js +39 -18
- package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -1
- package/dist/query/unit-of-work/unit-of-work.d.ts +42 -16
- package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work/unit-of-work.js +50 -6
- package/dist/query/unit-of-work/unit-of-work.js.map +1 -1
- package/dist/query/value-decoding.js +8 -1
- package/dist/query/value-decoding.js.map +1 -1
- package/dist/query/value-encoding.js.map +1 -1
- package/dist/schema/create.d.ts +69 -25
- package/dist/schema/create.d.ts.map +1 -1
- package/dist/schema/create.js +91 -16
- package/dist/schema/create.js.map +1 -1
- package/dist/schema/type-conversion/create-sql-type-mapper.js +1 -1
- package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -1
- package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -1
- package/dist/schema/validator.d.ts.map +1 -1
- package/dist/schema/validator.js.map +1 -1
- package/dist/schema-output/drizzle.d.ts.map +1 -1
- package/dist/schema-output/drizzle.js +8 -6
- package/dist/schema-output/drizzle.js.map +1 -1
- package/dist/schema-output/prisma.d.ts.map +1 -1
- package/dist/schema-output/prisma.js +21 -10
- package/dist/schema-output/prisma.js.map +1 -1
- package/dist/sql-driver/dialects/durable-object-dialect.js +3 -9
- package/dist/sql-driver/dialects/durable-object-dialect.js.map +1 -1
- package/dist/sql-driver/query-executor/default-query-executor.js.map +1 -1
- package/dist/sql-driver/query-executor/query-executor-base.js.map +1 -1
- package/dist/sql-driver/sql-driver-adapter.js.map +1 -1
- package/dist/sql-driver/sql.js.map +1 -1
- package/dist/sync/commands.d.ts +15 -0
- package/dist/sync/commands.d.ts.map +1 -0
- package/dist/sync/commands.js +27 -0
- package/dist/sync/commands.js.map +1 -0
- package/dist/sync/index.d.ts +4 -0
- package/dist/sync/index.js +4 -0
- package/dist/sync/read-tracking.d.ts +25 -0
- package/dist/sync/read-tracking.d.ts.map +1 -0
- package/dist/sync/read-tracking.js +148 -0
- package/dist/sync/read-tracking.js.map +1 -0
- package/dist/sync/submit.js +213 -0
- package/dist/sync/submit.js.map +1 -0
- package/dist/sync/types.d.ts +63 -0
- package/dist/sync/types.d.ts.map +1 -0
- package/dist/util/default-database-adapter.js +6 -1
- package/dist/util/default-database-adapter.js.map +1 -1
- package/dist/with-database.d.ts +3 -6
- package/dist/with-database.d.ts.map +1 -1
- package/dist/with-database.js +7 -15
- package/dist/with-database.js.map +1 -1
- package/package.json +33 -41
- package/src/adapters/adapters.ts +5 -4
- package/src/adapters/drizzle/migrate-drizzle.test.ts +46 -9
- package/src/adapters/drizzle/migration-parity-drizzle-kit.test.ts +5 -3
- package/src/adapters/drizzle/test-utils.ts +2 -1
- package/src/adapters/generic-sql/generic-sql-adapter.test.ts +5 -3
- package/src/adapters/generic-sql/generic-sql-adapter.ts +21 -24
- package/src/adapters/generic-sql/generic-sql-uow-executor.test.ts +1 -0
- package/src/adapters/generic-sql/generic-sql-uow-executor.ts +81 -15
- package/src/adapters/generic-sql/migration/adapter-migration-parity.test.ts +4 -2
- package/src/adapters/generic-sql/migration/cold-kysely.ts +1 -0
- package/src/adapters/generic-sql/migration/dialect/mysql.test.ts +3 -2
- package/src/adapters/generic-sql/migration/dialect/mysql.ts +1 -0
- package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +5 -4
- package/src/adapters/generic-sql/migration/dialect/postgres.ts +2 -1
- package/src/adapters/generic-sql/migration/dialect/sqlite.test.ts +795 -3
- package/src/adapters/generic-sql/migration/dialect/sqlite.ts +385 -57
- package/src/adapters/generic-sql/migration/executor.test.ts +52 -0
- package/src/adapters/generic-sql/migration/executor.ts +47 -4
- package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +117 -14
- package/src/adapters/generic-sql/migration/prepared-migrations.ts +9 -8
- package/src/adapters/generic-sql/migration/sql-generator.ts +5 -3
- package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +3 -3
- package/src/adapters/generic-sql/query/cursor-utils.test.ts +3 -2
- package/src/adapters/generic-sql/query/cursor-utils.ts +1 -1
- package/src/adapters/generic-sql/query/db-now-sql.ts +49 -0
- package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +144 -8
- package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +16 -17
- package/src/adapters/generic-sql/query/select-builder.test.ts +1 -0
- package/src/adapters/generic-sql/query/select-builder.ts +2 -2
- package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +24 -5
- package/src/adapters/generic-sql/query/sql-query-compiler.ts +83 -13
- package/src/adapters/generic-sql/query/where-builder.test.ts +7 -5
- package/src/adapters/generic-sql/query/where-builder.ts +48 -29
- package/src/adapters/generic-sql/sql-adapter-pglite-migrations.test.ts +6 -15
- package/src/adapters/generic-sql/sql-adapter-pglite-pagination.test.ts +52 -7
- package/src/adapters/generic-sql/sql-adapter-pglite-queries.test.ts +9 -6
- package/src/adapters/generic-sql/sql-adapter-sqlite3-driver.test.ts +273 -5
- package/src/adapters/generic-sql/sql-adapter-sqlite3-uow.test.ts +123 -6
- package/src/adapters/generic-sql/sql-adapter-sqlocal.test.ts +4 -2
- package/src/adapters/generic-sql/uow-decoder.test.ts +4 -3
- package/src/adapters/generic-sql/uow-decoder.ts +3 -3
- package/src/adapters/generic-sql/uow-encoder.test.ts +4 -2
- package/src/adapters/generic-sql/uow-encoder.ts +14 -18
- package/src/adapters/in-memory/condition-evaluator.test.ts +2 -1
- package/src/adapters/in-memory/condition-evaluator.ts +9 -4
- package/src/adapters/in-memory/in-memory-adapter.ts +155 -44
- package/src/adapters/in-memory/in-memory-uow.mutations.test.ts +50 -2
- package/src/adapters/in-memory/in-memory-uow.retrieval.test.ts +158 -3
- package/src/adapters/in-memory/in-memory-uow.ts +402 -26
- package/src/adapters/in-memory/options.test.ts +1 -0
- package/src/adapters/in-memory/options.ts +5 -1
- package/src/adapters/in-memory/outbox.test.ts +361 -0
- package/src/adapters/in-memory/reference-resolution.test.ts +3 -2
- package/src/adapters/in-memory/reference-resolution.ts +2 -2
- package/src/adapters/in-memory/sorted-array-index.test.ts +1 -0
- package/src/adapters/in-memory/store.test.ts +1 -0
- package/src/adapters/in-memory/store.ts +3 -3
- package/src/adapters/in-memory/value-normalization.test.ts +1 -0
- package/src/adapters/prisma/prisma-adapter-sqlite3.test.ts +51 -7
- package/src/adapters/shared/from-unit-of-work-compiler.ts +156 -46
- package/src/adapters/shared/uow-operation-compiler.ts +3 -3
- package/src/browser/mod.ts +64 -0
- package/src/client.ts +19 -0
- package/src/db-fragment-definition-builder.test.ts +821 -47
- package/src/db-fragment-definition-builder.ts +857 -110
- package/src/db-fragment-instantiator.test.ts +114 -90
- package/src/db-fragment-integration.test.ts +9 -6
- package/src/dispatchers/cloudflare-do/dispatcher.ts +204 -0
- package/src/dispatchers/cloudflare-do/index.test.ts +145 -12
- package/src/dispatchers/cloudflare-do/index.ts +49 -90
- package/src/dispatchers/node/dispatcher.ts +112 -0
- package/src/dispatchers/node/index.test.ts +43 -14
- package/src/dispatchers/node/index.ts +38 -75
- package/src/durable-hooks.test.ts +80 -0
- package/src/durable-hooks.ts +67 -0
- package/src/fragments/internal-fragment.routes.test.ts +570 -0
- package/src/fragments/internal-fragment.routes.ts +297 -5
- package/src/fragments/internal-fragment.schema.ts +45 -1
- package/src/fragments/internal-fragment.test.ts +223 -251
- package/src/fragments/internal-fragment.ts +278 -154
- package/src/hooks/durable-hooks-logger.ts +126 -0
- package/src/hooks/durable-hooks-processor.pglite.test.ts +87 -0
- package/src/hooks/durable-hooks-processor.test.ts +179 -14
- package/src/hooks/durable-hooks-processor.ts +120 -14
- package/src/hooks/durable-hooks-runtime.test.ts +65 -0
- package/src/hooks/durable-hooks-runtime.ts +81 -0
- package/src/hooks/hooks.test.ts +314 -53
- package/src/hooks/hooks.ts +360 -81
- package/src/id.test.ts +34 -0
- package/src/id.ts +1 -3
- package/src/internal/adapter-registry.test.ts +93 -0
- package/src/internal/adapter-registry.ts +239 -0
- package/src/internal/outbox-state.ts +43 -0
- package/src/migration-engine/auto-from-schema.test.ts +93 -0
- package/src/migration-engine/auto-from-schema.ts +360 -42
- package/src/migration-engine/create.test.ts +2 -1
- package/src/migration-engine/create.ts +1 -1
- package/src/migration-engine/generation-engine.test.ts +66 -9
- package/src/migration-engine/generation-engine.ts +31 -10
- package/src/migration-engine/shared.ts +13 -0
- package/src/mod.ts +45 -27
- package/src/naming/sql-naming.ts +1 -0
- package/src/outbox/outbox-builder.ts +2 -2
- package/src/outbox/outbox.test.ts +216 -45
- package/src/outbox/outbox.ts +3 -1
- package/src/query/column-defaults.ts +1 -1
- package/src/query/condition-builder.test.ts +15 -0
- package/src/query/condition-builder.ts +7 -0
- package/src/query/cursor-client.test.ts +70 -0
- package/src/query/cursor-client.ts +263 -0
- package/src/query/cursor.test.ts +3 -2
- package/src/query/cursor.ts +15 -3
- package/src/query/db-now.ts +69 -2
- package/src/query/orm/orm.ts +2 -2
- package/src/query/query-type.test.ts +2 -1
- package/src/query/serialize/create-sql-serializer.ts +3 -3
- package/src/query/serialize/dialect/mysql-serializer.ts +1 -1
- package/src/query/serialize/dialect/postgres-serializer.ts +1 -1
- package/src/query/serialize/dialect/sqlite-serializer.test.ts +39 -2
- package/src/query/serialize/dialect/sqlite-serializer.ts +18 -5
- package/src/query/simple-query-interface.ts +10 -4
- package/src/query/unit-of-work/execute-unit-of-work.test.ts +347 -9
- package/src/query/unit-of-work/execute-unit-of-work.ts +63 -20
- package/src/query/unit-of-work/retry-policy.test.ts +1 -0
- package/src/query/unit-of-work/tx-builder.test.ts +73 -1
- package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +5 -4
- package/src/query/unit-of-work/unit-of-work-types.test.ts +41 -11
- package/src/query/unit-of-work/unit-of-work.test.ts +28 -2
- package/src/query/unit-of-work/unit-of-work.ts +105 -19
- package/src/query/value-decoding.test.ts +50 -2
- package/src/query/value-decoding.ts +17 -4
- package/src/query/value-encoding.test.ts +1 -0
- package/src/query/value-encoding.ts +1 -1
- package/src/schema/create.test.ts +164 -5
- package/src/schema/create.ts +222 -24
- package/src/schema/generate-id.test.ts +1 -0
- package/src/schema/serialize.test.ts +4 -3
- package/src/schema/type-conversion/create-sql-type-mapper.ts +1 -1
- package/src/schema/type-conversion/dialect/sqlite.ts +2 -2
- package/src/schema/type-conversion/type-mapping.test.ts +2 -1
- package/src/schema/validator.test.ts +4 -2
- package/src/schema/validator.ts +1 -0
- package/src/schema-output/drizzle.test.ts +72 -19
- package/src/schema-output/drizzle.ts +24 -18
- package/src/schema-output/prisma.test.ts +172 -14
- package/src/schema-output/prisma.ts +34 -14
- package/src/sql-driver/better-sqlite3.test.ts +5 -3
- package/src/sql-driver/dialects/durable-object-dialect.ts +3 -8
- package/src/sql-driver/query-executor/default-query-executor.ts +1 -1
- package/src/sql-driver/query-executor/query-executor-base.ts +1 -1
- package/src/sql-driver/query-executor/query-executor.ts +1 -1
- package/src/sql-driver/sql-driver-adapter.ts +2 -2
- package/src/sql-driver/sql.ts +2 -1
- package/src/sql-driver/sqlocal.test.ts +4 -2
- package/src/sync/commands.test.ts +39 -0
- package/src/sync/commands.ts +51 -0
- package/src/sync/conflict-checker.test.ts +450 -0
- package/src/sync/conflict-checker.ts +248 -0
- package/src/sync/index.ts +14 -0
- package/src/sync/plan.ts +9 -0
- package/src/sync/read-tracking.test.ts +177 -0
- package/src/sync/read-tracking.ts +287 -0
- package/src/sync/submit.test.ts +205 -0
- package/src/sync/submit.ts +328 -0
- package/src/sync/types.ts +80 -0
- package/src/util/default-database-adapter.ts +15 -2
- package/src/with-database.ts +20 -50
- package/tsconfig.json +1 -1
- package/tsdown.config.ts +38 -26
- package/vitest.config.ts +1 -0
- package/dist/hooks/durable-hooks-processor.d.ts.map +0 -1
- package/dist/node_modules/.pnpm/rou3@0.7.12/node_modules/rou3/dist/index.js +0 -168
- package/dist/node_modules/.pnpm/rou3@0.7.12/node_modules/rou3/dist/index.js.map +0 -1
- package/dist/packages/fragno/dist/api/bind-services.js +0 -20
- package/dist/packages/fragno/dist/api/bind-services.js.map +0 -1
- package/dist/packages/fragno/dist/api/error.js +0 -48
- package/dist/packages/fragno/dist/api/error.js.map +0 -1
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js +0 -321
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +0 -1
- package/dist/packages/fragno/dist/api/fragment-instantiator.js +0 -669
- package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +0 -1
- package/dist/packages/fragno/dist/api/fragno-response.js +0 -73
- package/dist/packages/fragno/dist/api/fragno-response.js.map +0 -1
- package/dist/packages/fragno/dist/api/internal/response-stream.js +0 -81
- package/dist/packages/fragno/dist/api/internal/response-stream.js.map +0 -1
- package/dist/packages/fragno/dist/api/internal/route.js +0 -10
- package/dist/packages/fragno/dist/api/internal/route.js.map +0 -1
- package/dist/packages/fragno/dist/api/mutable-request-state.js +0 -97
- package/dist/packages/fragno/dist/api/mutable-request-state.js.map +0 -1
- package/dist/packages/fragno/dist/api/request-context-storage.js +0 -43
- package/dist/packages/fragno/dist/api/request-context-storage.js.map +0 -1
- package/dist/packages/fragno/dist/api/request-input-context.js +0 -185
- package/dist/packages/fragno/dist/api/request-input-context.js.map +0 -1
- package/dist/packages/fragno/dist/api/request-middleware.js +0 -83
- package/dist/packages/fragno/dist/api/request-middleware.js.map +0 -1
- package/dist/packages/fragno/dist/api/request-output-context.js +0 -119
- package/dist/packages/fragno/dist/api/request-output-context.js.map +0 -1
- package/dist/packages/fragno/dist/api/route.js +0 -30
- package/dist/packages/fragno/dist/api/route.js.map +0 -1
- package/dist/packages/fragno/dist/internal/symbols.js +0 -10
- package/dist/packages/fragno/dist/internal/symbols.js.map +0 -1
- package/dist/packages/fragno/dist/internal/trace-context.js +0 -12
- package/dist/packages/fragno/dist/internal/trace-context.js.map +0 -1
package/src/mod.ts
CHANGED
|
@@ -1,25 +1,31 @@
|
|
|
1
|
+
import type { FragnoInstantiatedFragment } from "@fragno-dev/core";
|
|
2
|
+
|
|
1
3
|
import type { DatabaseAdapter } from "./adapters/adapters";
|
|
2
|
-
import type { AnySchema } from "./schema/create";
|
|
3
|
-
import type { CursorResult } from "./query/cursor";
|
|
4
|
-
import { Cursor } from "./query/cursor";
|
|
5
|
-
import { dbNow, type DbNow } from "./query/db-now";
|
|
6
|
-
import type { FragnoInstantiatedFragment, AnyFragnoInstantiatedFragment } from "@fragno-dev/core";
|
|
7
4
|
import type {
|
|
8
5
|
FragnoPublicConfigWithDatabase,
|
|
9
6
|
ImplicitDatabaseDependencies,
|
|
7
|
+
DatabaseHandlerContext,
|
|
10
8
|
} from "./db-fragment-definition-builder";
|
|
9
|
+
import { getSchemaVersionFromDatabase } from "./fragments/internal-fragment";
|
|
10
|
+
import { getInternalFragment } from "./internal/adapter-registry";
|
|
11
|
+
import type { CursorResult } from "./query/cursor";
|
|
12
|
+
import { Cursor } from "./query/cursor";
|
|
11
13
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
dbInterval,
|
|
15
|
+
dbNow,
|
|
16
|
+
type DbInterval,
|
|
17
|
+
type DbIntervalInput,
|
|
18
|
+
type DbNow,
|
|
19
|
+
} from "./query/db-now";
|
|
20
|
+
import type { AnySchema } from "./schema/create";
|
|
16
21
|
|
|
17
22
|
export type { DatabaseAdapter, CursorResult };
|
|
18
23
|
export { Cursor };
|
|
19
|
-
export { dbNow };
|
|
20
|
-
export type { DbNow };
|
|
24
|
+
export { dbNow, dbInterval };
|
|
25
|
+
export type { DbNow, DbInterval, DbIntervalInput };
|
|
21
26
|
export { InMemoryAdapter, type InMemoryAdapterOptions } from "./adapters/in-memory";
|
|
22
27
|
export { internalSchema } from "./fragments/internal-fragment";
|
|
28
|
+
export { getInternalFragment } from "./internal/adapter-registry";
|
|
23
29
|
|
|
24
30
|
export const fragnoDatabaseFakeSymbol = "$fragno-database" as const;
|
|
25
31
|
export const fragnoDatabaseLibraryVersion = "0.1" as const;
|
|
@@ -82,6 +88,7 @@ export class FragnoDatabase<const T extends AnySchema, TUOWConfig = void> {
|
|
|
82
88
|
|
|
83
89
|
export {
|
|
84
90
|
DatabaseFragmentDefinitionBuilder,
|
|
91
|
+
type DbRoundtripGuardConfig,
|
|
85
92
|
type FragnoPublicConfigWithDatabase,
|
|
86
93
|
type DatabaseFragmentContext,
|
|
87
94
|
type DatabaseServiceContext,
|
|
@@ -118,8 +125,10 @@ export {
|
|
|
118
125
|
HandlerTxBuilder,
|
|
119
126
|
createServiceTxBuilder,
|
|
120
127
|
createHandlerTxBuilder,
|
|
128
|
+
serviceCalls,
|
|
121
129
|
type TxResult,
|
|
122
130
|
// Builder context types
|
|
131
|
+
type HandlerTxContext,
|
|
123
132
|
type ServiceBuilderMutateContext,
|
|
124
133
|
type HandlerBuilderMutateContext,
|
|
125
134
|
type BuilderTransformContextWithMutate,
|
|
@@ -144,6 +153,7 @@ export type {
|
|
|
144
153
|
HookContext,
|
|
145
154
|
HooksMap,
|
|
146
155
|
HookFn,
|
|
156
|
+
HookHandlerTx,
|
|
147
157
|
HookPayload,
|
|
148
158
|
TriggerHookOptions,
|
|
149
159
|
DurableHooksProcessingOptions,
|
|
@@ -151,10 +161,25 @@ export type {
|
|
|
151
161
|
StuckHookProcessingEvent,
|
|
152
162
|
StuckHookProcessingTimeoutMinutes,
|
|
153
163
|
} from "./hooks/hooks";
|
|
154
|
-
export {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
164
|
+
export { defineSyncCommands } from "./sync/commands";
|
|
165
|
+
export type {
|
|
166
|
+
DurableHookRecord,
|
|
167
|
+
DurableHookStatus,
|
|
168
|
+
DurableHooksAccessor,
|
|
169
|
+
DurableHooksService,
|
|
170
|
+
} from "./durable-hooks";
|
|
171
|
+
export { getDurableHooksService } from "./durable-hooks";
|
|
172
|
+
export type {
|
|
173
|
+
SubmitAppliedResponse,
|
|
174
|
+
SubmitConflictReason,
|
|
175
|
+
SubmitConflictResponse,
|
|
176
|
+
SubmitRequest,
|
|
177
|
+
SubmitResponse,
|
|
178
|
+
SyncCommandDefinition,
|
|
179
|
+
SyncCommandHandler,
|
|
180
|
+
SyncCommandRegistry,
|
|
181
|
+
SyncCommandTxFactory,
|
|
182
|
+
} from "./sync/types";
|
|
158
183
|
|
|
159
184
|
export type AnyFragnoInstantiatedDatabaseFragment<TSchema extends AnySchema = AnySchema> =
|
|
160
185
|
FragnoInstantiatedFragment<
|
|
@@ -165,13 +190,10 @@ export type AnyFragnoInstantiatedDatabaseFragment<TSchema extends AnySchema = An
|
|
|
165
190
|
any,
|
|
166
191
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
167
192
|
any,
|
|
193
|
+
DatabaseHandlerContext,
|
|
168
194
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
169
195
|
any,
|
|
170
|
-
|
|
171
|
-
any,
|
|
172
|
-
FragnoPublicConfigWithDatabase,
|
|
173
|
-
// Ensure the fragment has the internal fragment linked
|
|
174
|
-
{ _fragno_internal: InternalFragmentInstance } & Record<string, AnyFragnoInstantiatedFragment>
|
|
196
|
+
FragnoPublicConfigWithDatabase
|
|
175
197
|
>;
|
|
176
198
|
|
|
177
199
|
/**
|
|
@@ -199,8 +221,8 @@ export type AnyFragnoInstantiatedDatabaseFragment<TSchema extends AnySchema = An
|
|
|
199
221
|
export async function migrate<TSchema extends AnySchema>(
|
|
200
222
|
fragment: AnyFragnoInstantiatedDatabaseFragment<TSchema>,
|
|
201
223
|
): Promise<void> {
|
|
202
|
-
const {
|
|
203
|
-
const adapter =
|
|
224
|
+
const { deps } = fragment.$internal;
|
|
225
|
+
const adapter = deps.databaseAdapter;
|
|
204
226
|
|
|
205
227
|
// Check if adapter supports prepareMigrations
|
|
206
228
|
if (!adapter.prepareMigrations) {
|
|
@@ -213,11 +235,7 @@ export async function migrate<TSchema extends AnySchema>(
|
|
|
213
235
|
const namespace = deps.namespace ?? schema.name;
|
|
214
236
|
|
|
215
237
|
// Step 1: Ensure the internal fragment (settings table) is migrated first
|
|
216
|
-
const internalFragment =
|
|
217
|
-
|
|
218
|
-
if (!internalFragment) {
|
|
219
|
-
throw new Error("Internal fragment not found. Please ensure the internal fragment is linked.");
|
|
220
|
-
}
|
|
238
|
+
const internalFragment = getInternalFragment(adapter);
|
|
221
239
|
|
|
222
240
|
if (!(await adapter.isConnectionHealthy())) {
|
|
223
241
|
throw new Error(
|
package/src/naming/sql-naming.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { internalSchema } from "../fragments/internal-fragment.schema";
|
|
1
2
|
import type { MutationOperation } from "../query/unit-of-work/unit-of-work";
|
|
2
3
|
import type { AnySchema, AnyTable } from "../schema/create";
|
|
3
4
|
import { FragnoId, FragnoReference } from "../schema/create";
|
|
4
|
-
import { internalSchema } from "../fragments/internal-fragment.schema";
|
|
5
5
|
import type { OutboxRefLookup, OutboxPayload, OutboxMutation } from "./outbox";
|
|
6
6
|
import { encodeVersionstamp, versionstampToHex } from "./outbox";
|
|
7
7
|
|
|
@@ -91,7 +91,7 @@ export function buildOutboxPlan(operations: MutationOperation<AnySchema>[]): Out
|
|
|
91
91
|
export function finalizeOutboxPayload(plan: OutboxPlan, transactionVersion: bigint): OutboxPayload {
|
|
92
92
|
const mutations: OutboxMutation[] = plan.drafts.map((draft, index) => {
|
|
93
93
|
const versionstamp = versionstampToHex(encodeVersionstamp(transactionVersion, index));
|
|
94
|
-
return { ...draft, versionstamp }
|
|
94
|
+
return { ...draft, versionstamp };
|
|
95
95
|
});
|
|
96
96
|
|
|
97
97
|
return {
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { SQLocalKysely } from "sqlocal/kysely";
|
|
2
|
+
|
|
4
3
|
import { KyselyPGlite } from "kysely-pglite";
|
|
5
|
-
import {
|
|
4
|
+
import { SQLocalKysely } from "sqlocal/kysely";
|
|
6
5
|
import superjson, { type SuperJSONResult } from "superjson";
|
|
7
|
-
|
|
6
|
+
|
|
7
|
+
import { defineFragment, instantiate } from "@fragno-dev/core";
|
|
8
|
+
|
|
9
|
+
import { PGlite } from "@electric-sql/pglite";
|
|
10
|
+
|
|
8
11
|
import { PGLiteDriverConfig, SQLocalDriverConfig } from "../adapters/generic-sql/driver-config";
|
|
9
|
-
import
|
|
10
|
-
import { withDatabase } from "../with-database";
|
|
12
|
+
import { SqlAdapter } from "../adapters/generic-sql/generic-sql-adapter";
|
|
11
13
|
import { internalSchema, type InternalFragmentInstance } from "../fragments/internal-fragment";
|
|
14
|
+
import { getInternalFragment } from "../internal/adapter-registry";
|
|
15
|
+
import type { AnyFragnoInstantiatedDatabaseFragment, DatabaseRequestContext } from "../mod";
|
|
16
|
+
import type { AnySchema } from "../schema/create";
|
|
12
17
|
import { schema, idColumn, column, referenceColumn, FragnoReference } from "../schema/create";
|
|
13
|
-
import
|
|
18
|
+
import { withDatabase } from "../with-database";
|
|
19
|
+
import type { OutboxEntry, OutboxPayload } from "./outbox";
|
|
14
20
|
|
|
15
21
|
const outboxSchema = schema("outbox", (s) => {
|
|
16
22
|
return s
|
|
@@ -33,24 +39,36 @@ const outboxSchema = schema("outbox", (s) => {
|
|
|
33
39
|
});
|
|
34
40
|
});
|
|
35
41
|
|
|
42
|
+
const alphaSchema = schema("alpha", (s) =>
|
|
43
|
+
s.addTable("alpha_items", (t) =>
|
|
44
|
+
t.addColumn("id", idColumn()).addColumn("name", column("string")),
|
|
45
|
+
),
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const betaSchema = schema("beta", (s) =>
|
|
49
|
+
s.addTable("beta_items", (t) =>
|
|
50
|
+
t.addColumn("id", idColumn()).addColumn("title", column("string")),
|
|
51
|
+
),
|
|
52
|
+
);
|
|
53
|
+
|
|
36
54
|
const outboxFragmentName = "outbox-test";
|
|
37
55
|
const outboxFragmentDef = defineFragment(outboxFragmentName)
|
|
38
56
|
.extend(withDatabase(outboxSchema))
|
|
39
57
|
.build();
|
|
40
58
|
|
|
41
59
|
type OutboxAdapterConfig =
|
|
42
|
-
| { type: "kysely-sqlite";
|
|
43
|
-
| { type: "kysely-pglite";
|
|
60
|
+
| { type: "kysely-sqlite"; outboxEnabled?: boolean }
|
|
61
|
+
| { type: "kysely-pglite"; outboxEnabled?: boolean };
|
|
44
62
|
|
|
45
63
|
type OutboxTestContext = {
|
|
46
|
-
|
|
64
|
+
fragment: AnyFragnoInstantiatedDatabaseFragment<typeof outboxSchema>;
|
|
47
65
|
internalFragment: InternalFragmentInstance;
|
|
48
66
|
cleanup: () => Promise<void>;
|
|
49
67
|
};
|
|
50
68
|
|
|
51
69
|
async function migrateSchema(
|
|
52
70
|
adapter: SqlAdapter,
|
|
53
|
-
schemaToMigrate:
|
|
71
|
+
schemaToMigrate: AnySchema,
|
|
54
72
|
namespace: string,
|
|
55
73
|
): Promise<void> {
|
|
56
74
|
const migrations = adapter.prepareMigrations(schemaToMigrate, namespace);
|
|
@@ -66,7 +84,6 @@ async function createAdapter(config: OutboxAdapterConfig): Promise<{
|
|
|
66
84
|
const adapter = new SqlAdapter({
|
|
67
85
|
dialect,
|
|
68
86
|
driverConfig: new SQLocalDriverConfig(),
|
|
69
|
-
outbox: config.outbox,
|
|
70
87
|
});
|
|
71
88
|
|
|
72
89
|
await migrateSchema(adapter, internalSchema, "");
|
|
@@ -85,7 +102,6 @@ async function createAdapter(config: OutboxAdapterConfig): Promise<{
|
|
|
85
102
|
const adapter = new SqlAdapter({
|
|
86
103
|
dialect,
|
|
87
104
|
driverConfig: new PGLiteDriverConfig(),
|
|
88
|
-
outbox: config.outbox,
|
|
89
105
|
});
|
|
90
106
|
|
|
91
107
|
await migrateSchema(adapter, internalSchema, "");
|
|
@@ -104,13 +120,15 @@ async function buildOutboxTest(adapterConfig: OutboxAdapterConfig): Promise<Outb
|
|
|
104
120
|
const fragment = instantiate(outboxFragmentDef)
|
|
105
121
|
.withConfig({})
|
|
106
122
|
.withRoutes([])
|
|
107
|
-
.withOptions({
|
|
123
|
+
.withOptions({
|
|
124
|
+
databaseAdapter: adapter,
|
|
125
|
+
outbox: adapterConfig.outboxEnabled ? { enabled: true } : undefined,
|
|
126
|
+
})
|
|
108
127
|
.build();
|
|
109
|
-
const deps = fragment.$internal.deps as { db: SimpleQueryInterface<typeof outboxSchema> };
|
|
110
128
|
|
|
111
129
|
return {
|
|
112
|
-
|
|
113
|
-
internalFragment:
|
|
130
|
+
fragment,
|
|
131
|
+
internalFragment: getInternalFragment(adapter),
|
|
114
132
|
cleanup,
|
|
115
133
|
};
|
|
116
134
|
}
|
|
@@ -119,7 +137,7 @@ async function listOutbox(
|
|
|
119
137
|
internalFragment: InternalFragmentInstance,
|
|
120
138
|
options?: { afterVersionstamp?: string; limit?: number },
|
|
121
139
|
): Promise<OutboxEntry[]> {
|
|
122
|
-
return internalFragment.inContext(async function () {
|
|
140
|
+
return internalFragment.inContext(async function (this: DatabaseRequestContext) {
|
|
123
141
|
return (await this.handlerTx()
|
|
124
142
|
.withServiceCalls(() => [internalFragment.services.outboxService.list(options)] as const)
|
|
125
143
|
.transform(({ serviceResult: [result] }) => result)
|
|
@@ -127,39 +145,98 @@ async function listOutbox(
|
|
|
127
145
|
});
|
|
128
146
|
}
|
|
129
147
|
|
|
148
|
+
async function listOutboxMutations(internalFragment: InternalFragmentInstance): Promise<
|
|
149
|
+
Array<{
|
|
150
|
+
entryVersionstamp: string;
|
|
151
|
+
mutationVersionstamp: string;
|
|
152
|
+
uowId: string;
|
|
153
|
+
schema: string;
|
|
154
|
+
table: string;
|
|
155
|
+
externalId: string;
|
|
156
|
+
op: string;
|
|
157
|
+
}>
|
|
158
|
+
> {
|
|
159
|
+
return internalFragment.inContext(async function (this: DatabaseRequestContext) {
|
|
160
|
+
return await this.handlerTx()
|
|
161
|
+
.retrieve(({ forSchema }) =>
|
|
162
|
+
forSchema(internalSchema).find("fragno_db_outbox_mutations", (b) =>
|
|
163
|
+
b
|
|
164
|
+
.whereIndex("idx_outbox_mutations_entry")
|
|
165
|
+
.orderByIndex("idx_outbox_mutations_entry", "asc"),
|
|
166
|
+
),
|
|
167
|
+
)
|
|
168
|
+
.transformRetrieve(([result]) => result)
|
|
169
|
+
.execute();
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async function createUser(
|
|
174
|
+
fragment: AnyFragnoInstantiatedDatabaseFragment<typeof outboxSchema>,
|
|
175
|
+
email: string,
|
|
176
|
+
) {
|
|
177
|
+
return fragment.inContext(async function (this: DatabaseRequestContext) {
|
|
178
|
+
await this.handlerTx()
|
|
179
|
+
.mutate(({ forSchema }) => forSchema(outboxSchema).create("users", { email }))
|
|
180
|
+
.execute();
|
|
181
|
+
|
|
182
|
+
const user = await this.handlerTx()
|
|
183
|
+
.retrieve(({ forSchema }) =>
|
|
184
|
+
forSchema(outboxSchema).findFirst("users", (b) =>
|
|
185
|
+
b.whereIndex("idx_users_email", (eb) => eb("email", "=", email)),
|
|
186
|
+
),
|
|
187
|
+
)
|
|
188
|
+
.transformRetrieve(([result]) => result)
|
|
189
|
+
.execute();
|
|
190
|
+
|
|
191
|
+
if (!user) {
|
|
192
|
+
throw new Error("Expected user to be created.");
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return user.id;
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async function createPost(
|
|
200
|
+
fragment: AnyFragnoInstantiatedDatabaseFragment<typeof outboxSchema>,
|
|
201
|
+
title: string,
|
|
202
|
+
authorId: FragnoReference,
|
|
203
|
+
) {
|
|
204
|
+
return fragment.inContext(async function (this: DatabaseRequestContext) {
|
|
205
|
+
return await this.handlerTx()
|
|
206
|
+
.mutate(({ forSchema }) => forSchema(outboxSchema).create("posts", { title, authorId }))
|
|
207
|
+
.transform(({ mutateResult }) => mutateResult)
|
|
208
|
+
.execute();
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
130
212
|
const adapterConfigs = [{ type: "kysely-sqlite" as const }, { type: "kysely-pglite" as const }];
|
|
131
213
|
|
|
132
214
|
describe("Fragno DB Outbox", () => {
|
|
133
215
|
it("does not write outbox entries when disabled", async () => {
|
|
134
|
-
const {
|
|
216
|
+
const { fragment, internalFragment, cleanup } = await buildOutboxTest({
|
|
135
217
|
type: "kysely-sqlite",
|
|
136
218
|
});
|
|
137
219
|
|
|
138
|
-
await
|
|
220
|
+
await createUser(fragment, "disabled@example.com");
|
|
139
221
|
|
|
140
222
|
const entries = await listOutbox(internalFragment);
|
|
141
223
|
expect(entries).toHaveLength(0);
|
|
224
|
+
const mutations = await listOutboxMutations(internalFragment);
|
|
225
|
+
expect(mutations).toHaveLength(0);
|
|
142
226
|
|
|
143
227
|
await cleanup();
|
|
144
228
|
});
|
|
145
229
|
|
|
146
230
|
it("stores refMap placeholders and lists entries in order", async () => {
|
|
147
|
-
const {
|
|
231
|
+
const { fragment, internalFragment, cleanup } = await buildOutboxTest({
|
|
148
232
|
type: "kysely-sqlite",
|
|
149
|
-
|
|
233
|
+
outboxEnabled: true,
|
|
150
234
|
});
|
|
151
235
|
|
|
152
|
-
await
|
|
153
|
-
|
|
154
|
-
b.whereIndex("idx_users_email", (eb) => eb("email", "=", "alpha@example.com")),
|
|
155
|
-
);
|
|
156
|
-
expect(user).not.toBeNull();
|
|
157
|
-
expect(user?.id.internalId).toBeDefined();
|
|
236
|
+
const userId = await createUser(fragment, "alpha@example.com");
|
|
237
|
+
expect(userId.internalId).toBeDefined();
|
|
158
238
|
|
|
159
|
-
await
|
|
160
|
-
title: "Hello",
|
|
161
|
-
authorId: FragnoReference.fromInternal(user!.id.internalId!),
|
|
162
|
-
});
|
|
239
|
+
await createPost(fragment, "Hello", FragnoReference.fromInternal(userId.internalId!));
|
|
163
240
|
|
|
164
241
|
const entries = await listOutbox(internalFragment);
|
|
165
242
|
expect(entries).toHaveLength(2);
|
|
@@ -183,10 +260,10 @@ describe("Fragno DB Outbox", () => {
|
|
|
183
260
|
authorId: { __fragno_ref: "0.authorId" },
|
|
184
261
|
});
|
|
185
262
|
expect(entries[1].refMap).toEqual({
|
|
186
|
-
"0.authorId":
|
|
263
|
+
"0.authorId": userId.externalId,
|
|
187
264
|
});
|
|
188
265
|
|
|
189
|
-
await internalFragment.inContext(async function () {
|
|
266
|
+
await internalFragment.inContext(async function (this: DatabaseRequestContext) {
|
|
190
267
|
await this.handlerTx()
|
|
191
268
|
.withServiceCalls(() => [
|
|
192
269
|
internalFragment.services.settingsService.set("outbox-test", "noop", "1"),
|
|
@@ -200,19 +277,60 @@ describe("Fragno DB Outbox", () => {
|
|
|
200
277
|
await cleanup();
|
|
201
278
|
});
|
|
202
279
|
|
|
280
|
+
it("writes mutation log rows for each outbox entry", async () => {
|
|
281
|
+
const { fragment, internalFragment, cleanup } = await buildOutboxTest({
|
|
282
|
+
type: "kysely-sqlite",
|
|
283
|
+
outboxEnabled: true,
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
const userId = await createUser(fragment, "log-alpha@example.com");
|
|
287
|
+
expect(userId.internalId).toBeDefined();
|
|
288
|
+
|
|
289
|
+
await createPost(fragment, "Log", FragnoReference.fromInternal(userId.internalId!));
|
|
290
|
+
|
|
291
|
+
const entries = await listOutbox(internalFragment);
|
|
292
|
+
const mutations = await listOutboxMutations(internalFragment);
|
|
293
|
+
|
|
294
|
+
expect(entries).toHaveLength(2);
|
|
295
|
+
expect(mutations).toHaveLength(2);
|
|
296
|
+
|
|
297
|
+
const entryByVersion = new Map(entries.map((entry) => [entry.versionstamp, entry]));
|
|
298
|
+
|
|
299
|
+
for (const entry of entries) {
|
|
300
|
+
const payload = superjson.deserialize(entry.payload as SuperJSONResult) as OutboxPayload;
|
|
301
|
+
expect(payload.mutations).toHaveLength(1);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
for (const mutationRow of mutations) {
|
|
305
|
+
const entry = entryByVersion.get(mutationRow.entryVersionstamp);
|
|
306
|
+
expect(entry).toBeDefined();
|
|
307
|
+
const payload = superjson.deserialize(entry!.payload as SuperJSONResult) as OutboxPayload;
|
|
308
|
+
const mutation = payload.mutations[0];
|
|
309
|
+
expect(mutationRow.mutationVersionstamp).toBe(mutation.versionstamp);
|
|
310
|
+
expect(mutationRow.uowId).toBe(entry!.uowId);
|
|
311
|
+
expect(mutationRow.schema).toBe(mutation.schema);
|
|
312
|
+
expect(mutationRow.table).toBe(mutation.table);
|
|
313
|
+
expect(mutationRow.externalId).toBe(mutation.externalId);
|
|
314
|
+
expect(mutationRow.op).toBe(mutation.op);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
await cleanup();
|
|
318
|
+
});
|
|
319
|
+
|
|
203
320
|
it("orders outbox entries by commit order across concurrent UOWs", async () => {
|
|
204
|
-
const {
|
|
321
|
+
const { fragment, internalFragment, cleanup } = await buildOutboxTest({
|
|
205
322
|
type: "kysely-sqlite",
|
|
206
|
-
|
|
323
|
+
outboxEnabled: true,
|
|
207
324
|
});
|
|
208
325
|
|
|
209
|
-
const
|
|
210
|
-
const
|
|
326
|
+
const createUow = fragment.$internal.deps.createUnitOfWork;
|
|
327
|
+
const uow1 = createUow();
|
|
328
|
+
const uow2 = createUow();
|
|
211
329
|
const uow1Id = uow1.idempotencyKey;
|
|
212
330
|
const uow2Id = uow2.idempotencyKey;
|
|
213
331
|
|
|
214
|
-
uow1.create("users", { email: "order-1@example.com" });
|
|
215
|
-
uow2.create("users", { email: "order-2@example.com" });
|
|
332
|
+
uow1.forSchema(outboxSchema).create("users", { email: "order-1@example.com" });
|
|
333
|
+
uow2.forSchema(outboxSchema).create("users", { email: "order-2@example.com" });
|
|
216
334
|
|
|
217
335
|
const completionOrder: string[] = [];
|
|
218
336
|
await Promise.all([
|
|
@@ -227,24 +345,77 @@ describe("Fragno DB Outbox", () => {
|
|
|
227
345
|
await cleanup();
|
|
228
346
|
});
|
|
229
347
|
|
|
348
|
+
it("only writes outbox entries for schemas that opt in", async () => {
|
|
349
|
+
const { dialect } = new SQLocalKysely(":memory:");
|
|
350
|
+
const adapter = new SqlAdapter({
|
|
351
|
+
dialect,
|
|
352
|
+
driverConfig: new SQLocalDriverConfig(),
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
try {
|
|
356
|
+
await migrateSchema(adapter, internalSchema, "");
|
|
357
|
+
await migrateSchema(adapter, alphaSchema, alphaSchema.name);
|
|
358
|
+
await migrateSchema(adapter, betaSchema, betaSchema.name);
|
|
359
|
+
|
|
360
|
+
const alphaDef = defineFragment("alpha-fragment").extend(withDatabase(alphaSchema)).build();
|
|
361
|
+
const betaDef = defineFragment("beta-fragment").extend(withDatabase(betaSchema)).build();
|
|
362
|
+
|
|
363
|
+
const alphaFragment = instantiate(alphaDef)
|
|
364
|
+
.withConfig({})
|
|
365
|
+
.withRoutes([])
|
|
366
|
+
.withOptions({ databaseAdapter: adapter, outbox: { enabled: true } })
|
|
367
|
+
.build();
|
|
368
|
+
|
|
369
|
+
const betaFragment = instantiate(betaDef)
|
|
370
|
+
.withConfig({})
|
|
371
|
+
.withRoutes([])
|
|
372
|
+
.withOptions({ databaseAdapter: adapter })
|
|
373
|
+
.build();
|
|
374
|
+
|
|
375
|
+
await alphaFragment.inContext(async function (this: DatabaseRequestContext) {
|
|
376
|
+
await this.handlerTx()
|
|
377
|
+
.mutate(({ forSchema }) =>
|
|
378
|
+
forSchema(alphaSchema).create("alpha_items", { name: "alpha" }),
|
|
379
|
+
)
|
|
380
|
+
.execute();
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
await betaFragment.inContext(async function (this: DatabaseRequestContext) {
|
|
384
|
+
await this.handlerTx()
|
|
385
|
+
.mutate(({ forSchema }) => forSchema(betaSchema).create("beta_items", { title: "beta" }))
|
|
386
|
+
.execute();
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
const entries = await listOutbox(getInternalFragment(adapter));
|
|
390
|
+
const mutationSchemas = entries
|
|
391
|
+
.map((entry) => superjson.deserialize(entry.payload as SuperJSONResult) as OutboxPayload)
|
|
392
|
+
.flatMap((payload) => payload.mutations.map((mutation) => mutation.schema));
|
|
393
|
+
|
|
394
|
+
expect(mutationSchemas).toContain(alphaSchema.name);
|
|
395
|
+
expect(mutationSchemas).not.toContain(betaSchema.name);
|
|
396
|
+
} finally {
|
|
397
|
+
await adapter.close();
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
|
|
230
401
|
describe.each(adapterConfigs)("adapter opt-in (%s)", (adapterConfig) => {
|
|
231
402
|
it("writes outbox rows only when enabled", async () => {
|
|
232
|
-
const {
|
|
403
|
+
const { fragment, internalFragment, cleanup } = await buildOutboxTest(adapterConfig);
|
|
233
404
|
|
|
234
|
-
await
|
|
405
|
+
await createUser(fragment, "disabled@example.com");
|
|
235
406
|
const disabledEntries = await listOutbox(internalFragment);
|
|
236
407
|
expect(disabledEntries).toHaveLength(0);
|
|
237
408
|
await cleanup();
|
|
238
409
|
|
|
239
410
|
const {
|
|
240
|
-
|
|
411
|
+
fragment: enabledFragment,
|
|
241
412
|
internalFragment: enabledInternal,
|
|
242
413
|
cleanup: enabledCleanup,
|
|
243
414
|
} = await buildOutboxTest({
|
|
244
415
|
...adapterConfig,
|
|
245
|
-
|
|
416
|
+
outboxEnabled: true,
|
|
246
417
|
});
|
|
247
|
-
await
|
|
418
|
+
await createUser(enabledFragment, "enabled@example.com");
|
|
248
419
|
const enabledEntries = await listOutbox(enabledInternal);
|
|
249
420
|
expect(enabledEntries).toHaveLength(1);
|
|
250
421
|
await enabledCleanup();
|
package/src/outbox/outbox.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { MutationOperation } from "../query/unit-of-work/unit-of-work";
|
|
2
|
+
import type { AnySchema, AnyTable, FragnoId } from "../schema/create";
|
|
2
3
|
|
|
3
4
|
export type OutboxConfig = {
|
|
4
5
|
enabled: boolean;
|
|
6
|
+
shouldInclude?: (operation: MutationOperation<AnySchema>) => boolean;
|
|
5
7
|
};
|
|
6
8
|
|
|
7
9
|
export type OutboxVersionstampStrategy =
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
2
3
|
import { column, idColumn, schema } from "../schema/create";
|
|
3
4
|
import { createBuilder, createIndexedBuilder } from "./condition-builder";
|
|
4
5
|
|
|
@@ -101,6 +102,20 @@ describe("ConditionBuilder", () => {
|
|
|
101
102
|
});
|
|
102
103
|
});
|
|
103
104
|
|
|
105
|
+
it("should expose db now helper", () => {
|
|
106
|
+
const builder = createBuilder(usersTable.columns);
|
|
107
|
+
|
|
108
|
+
const now = builder.now();
|
|
109
|
+
expect(now).toMatchObject({ tag: "db-now" });
|
|
110
|
+
expect(typeof now.plus).toBe("function");
|
|
111
|
+
expect(now.plus({ seconds: 1 })).toMatchObject({ tag: "db-now", offsetMs: 1000 });
|
|
112
|
+
expect(now.plus({ seconds: 1 }).plus({ minutes: 1 })).toMatchObject({
|
|
113
|
+
tag: "db-now",
|
|
114
|
+
offsetMs: 61_000,
|
|
115
|
+
});
|
|
116
|
+
expect(builder.interval({ minutes: 1 })).toEqual({ tag: "db-interval", ms: 60_000 });
|
|
117
|
+
});
|
|
118
|
+
|
|
104
119
|
it("should support boolean columns", () => {
|
|
105
120
|
const postsTable = testSchema.tables.posts;
|
|
106
121
|
const builder = createBuilder(postsTable.columns);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AnyColumn, FragnoId, IdColumn } from "../schema/create";
|
|
2
|
+
import { dbInterval, dbNow, type DbInterval, type DbIntervalInput, type DbNow } from "./db-now";
|
|
2
3
|
|
|
3
4
|
export type ConditionType = "compare" | "and" | "or" | "not";
|
|
4
5
|
|
|
@@ -54,6 +55,8 @@ export type ConditionBuilder<Columns extends Record<string, AnyColumn>> = {
|
|
|
54
55
|
|
|
55
56
|
isNull: (a: keyof Columns) => Condition;
|
|
56
57
|
isNotNull: (a: keyof Columns) => Condition;
|
|
58
|
+
now: () => DbNow;
|
|
59
|
+
interval: (input: DbIntervalInput) => DbInterval;
|
|
57
60
|
};
|
|
58
61
|
|
|
59
62
|
// replacement for `like` (Prisma doesn't support `like`)
|
|
@@ -117,6 +120,8 @@ export function createBuilder<Columns extends Record<string, AnyColumn>>(
|
|
|
117
120
|
|
|
118
121
|
builder.isNull = (a) => builder(a, "is", null);
|
|
119
122
|
builder.isNotNull = (a) => builder(a, "is not", null);
|
|
123
|
+
builder.now = () => dbNow();
|
|
124
|
+
builder.interval = (input) => dbInterval(input);
|
|
120
125
|
builder.not = (condition) => {
|
|
121
126
|
if (typeof condition === "boolean") {
|
|
122
127
|
return !condition;
|
|
@@ -249,6 +254,8 @@ export function createIndexedBuilder<Columns extends Record<string, AnyColumn>>(
|
|
|
249
254
|
|
|
250
255
|
builder.isNull = (a) => builder(a, "is", null);
|
|
251
256
|
builder.isNotNull = (a) => builder(a, "is not", null);
|
|
257
|
+
builder.now = () => dbNow();
|
|
258
|
+
builder.interval = (input) => dbInterval(input);
|
|
252
259
|
builder.not = (condition) => {
|
|
253
260
|
if (typeof condition === "boolean") {
|
|
254
261
|
return !condition;
|