@fragno-dev/db 0.2.2 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +404 -175
- package/CHANGELOG.md +109 -0
- package/README.md +54 -9
- package/dist/adapters/adapters.d.ts +23 -21
- package/dist/adapters/adapters.d.ts.map +1 -1
- package/dist/adapters/adapters.js.map +1 -1
- package/dist/adapters/generic-sql/driver-config.d.ts +16 -1
- package/dist/adapters/generic-sql/driver-config.d.ts.map +1 -1
- package/dist/adapters/generic-sql/driver-config.js +23 -1
- package/dist/adapters/generic-sql/driver-config.js.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-adapter.d.ts +24 -9
- package/dist/adapters/generic-sql/generic-sql-adapter.d.ts.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-adapter.js +60 -22
- package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-uow-executor.js +169 -3
- package/dist/adapters/generic-sql/generic-sql-uow-executor.js.map +1 -1
- package/dist/adapters/generic-sql/migration/cold-kysely.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/mysql.js +25 -6
- package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/postgres.js +7 -6
- package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/sqlite.js +193 -16
- package/dist/adapters/generic-sql/migration/dialect/sqlite.js.map +1 -1
- package/dist/adapters/generic-sql/migration/executor.d.ts.map +1 -1
- package/dist/adapters/generic-sql/migration/executor.js +30 -3
- package/dist/adapters/generic-sql/migration/executor.js.map +1 -1
- package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -1
- package/dist/adapters/generic-sql/migration/prepared-migrations.js +9 -9
- package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -1
- package/dist/adapters/generic-sql/migration/sql-generator.js +75 -52
- package/dist/adapters/generic-sql/migration/sql-generator.js.map +1 -1
- package/dist/adapters/generic-sql/query/create-sql-query-compiler.js +7 -6
- package/dist/adapters/generic-sql/query/create-sql-query-compiler.js.map +1 -1
- package/dist/adapters/generic-sql/query/cursor-utils.js +42 -4
- package/dist/adapters/generic-sql/query/cursor-utils.js.map +1 -1
- package/dist/adapters/generic-sql/query/db-now-sql.js +27 -0
- package/dist/adapters/generic-sql/query/db-now-sql.js.map +1 -0
- package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js +32 -21
- package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js.map +1 -1
- package/dist/adapters/generic-sql/query/select-builder.js +5 -3
- package/dist/adapters/generic-sql/query/select-builder.js.map +1 -1
- package/dist/adapters/generic-sql/query/sql-query-compiler.js +49 -18
- package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -1
- package/dist/adapters/generic-sql/query/where-builder.js +43 -29
- package/dist/adapters/generic-sql/query/where-builder.js.map +1 -1
- package/dist/adapters/generic-sql/sqlite-storage.d.ts +13 -0
- package/dist/adapters/generic-sql/sqlite-storage.d.ts.map +1 -0
- package/dist/adapters/generic-sql/sqlite-storage.js +15 -0
- package/dist/adapters/generic-sql/sqlite-storage.js.map +1 -0
- package/dist/adapters/generic-sql/uow-decoder.js +6 -2
- package/dist/adapters/generic-sql/uow-decoder.js.map +1 -1
- package/dist/adapters/generic-sql/uow-encoder.js +27 -8
- package/dist/adapters/generic-sql/uow-encoder.js.map +1 -1
- package/dist/adapters/in-memory/condition-evaluator.js +135 -0
- package/dist/adapters/in-memory/condition-evaluator.js.map +1 -0
- package/dist/adapters/in-memory/errors.d.ts +13 -0
- package/dist/adapters/in-memory/errors.d.ts.map +1 -0
- package/dist/adapters/in-memory/errors.js +23 -0
- package/dist/adapters/in-memory/errors.js.map +1 -0
- package/dist/adapters/in-memory/in-memory-adapter.d.ts +27 -0
- package/dist/adapters/in-memory/in-memory-adapter.d.ts.map +1 -0
- package/dist/adapters/in-memory/in-memory-adapter.js +196 -0
- package/dist/adapters/in-memory/in-memory-adapter.js.map +1 -0
- package/dist/adapters/in-memory/in-memory-uow.js +871 -0
- package/dist/adapters/in-memory/in-memory-uow.js.map +1 -0
- package/dist/adapters/in-memory/index.d.ts +4 -0
- package/dist/adapters/in-memory/index.js +4 -0
- package/dist/adapters/in-memory/options.d.ts +30 -0
- package/dist/adapters/in-memory/options.d.ts.map +1 -0
- package/dist/adapters/in-memory/options.js +62 -0
- package/dist/adapters/in-memory/options.js.map +1 -0
- package/dist/adapters/in-memory/reference-resolution.js +26 -0
- package/dist/adapters/in-memory/reference-resolution.js.map +1 -0
- package/dist/adapters/in-memory/sorted-array-index.js +129 -0
- package/dist/adapters/in-memory/sorted-array-index.js.map +1 -0
- package/dist/adapters/in-memory/store.js +71 -0
- package/dist/adapters/in-memory/store.js.map +1 -0
- package/dist/adapters/in-memory/value-comparison.js +28 -0
- package/dist/adapters/in-memory/value-comparison.js.map +1 -0
- package/dist/adapters/shared/from-unit-of-work-compiler.js +51 -24
- package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -1
- package/dist/adapters/shared/uow-operation-compiler.js +11 -11
- package/dist/adapters/shared/uow-operation-compiler.js.map +1 -1
- package/dist/adapters/sql/index.d.ts +5 -0
- package/dist/adapters/sql/index.js +4 -0
- package/dist/browser/adapters/adapters.d.ts +61 -0
- package/dist/browser/adapters/adapters.d.ts.map +1 -0
- package/dist/browser/adapters/generic-sql/migration/executor.d.ts +15 -0
- package/dist/browser/adapters/generic-sql/migration/executor.d.ts.map +1 -0
- package/dist/browser/adapters/generic-sql/migration/prepared-migrations.d.ts +66 -0
- package/dist/browser/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -0
- package/dist/browser/adapters/generic-sql/sqlite-storage.d.ts +11 -0
- package/dist/browser/adapters/generic-sql/sqlite-storage.d.ts.map +1 -0
- package/dist/browser/adapters/in-memory/in-memory-adapter.d.ts +5 -0
- package/dist/browser/adapters/in-memory/index.d.ts +2 -0
- package/dist/browser/adapters/in-memory/options.d.ts +1 -0
- package/dist/browser/db-fragment-definition-builder.d.ts +237 -0
- package/dist/browser/db-fragment-definition-builder.d.ts.map +1 -0
- package/dist/browser/durable-hooks.d.ts +3 -0
- package/dist/browser/fragments/internal-fragment.d.ts +317 -0
- package/dist/browser/fragments/internal-fragment.d.ts.map +1 -0
- package/dist/browser/fragments/internal-fragment.schema.d.ts +1 -0
- package/dist/browser/hooks/durable-hooks-logger.d.ts +10 -0
- package/dist/browser/hooks/durable-hooks-logger.d.ts.map +1 -0
- package/dist/browser/hooks/hooks.d.ts +146 -0
- package/dist/browser/hooks/hooks.d.ts.map +1 -0
- package/dist/browser/id.js +1 -0
- package/dist/browser/internal/adapter-registry.d.ts +4 -0
- package/dist/browser/internal/outbox-state.d.ts +2 -0
- package/dist/browser/mod.d.ts +15 -0
- package/dist/browser/mod.d.ts.map +1 -0
- package/dist/browser/mod.js +17 -0
- package/dist/browser/mod.js.map +1 -0
- package/dist/browser/mod2.d.ts +48 -0
- package/dist/browser/mod2.d.ts.map +1 -0
- package/dist/browser/naming/sql-naming.d.ts +19 -0
- package/dist/browser/naming/sql-naming.d.ts.map +1 -0
- package/dist/browser/outbox/outbox.d.ts +21 -0
- package/dist/browser/outbox/outbox.d.ts.map +1 -0
- package/dist/browser/query/column-defaults.js +1 -0
- package/dist/browser/query/condition-builder.d.ts +44 -0
- package/dist/browser/query/condition-builder.d.ts.map +1 -0
- package/dist/browser/query/condition-builder.js +97 -0
- package/dist/browser/query/condition-builder.js.map +1 -0
- package/dist/browser/query/cursor.d.ts +105 -0
- package/dist/browser/query/cursor.d.ts.map +1 -0
- package/dist/browser/query/cursor.js +150 -0
- package/dist/browser/query/cursor.js.map +1 -0
- package/dist/browser/query/db-now.d.ts +22 -0
- package/dist/browser/query/db-now.d.ts.map +1 -0
- package/dist/browser/query/db-now.js +33 -0
- package/dist/browser/query/db-now.js.map +1 -0
- package/dist/browser/query/orm/orm.d.ts +18 -0
- package/dist/browser/query/orm/orm.d.ts.map +1 -0
- package/dist/browser/query/simple-query-interface.d.ts +108 -0
- package/dist/browser/query/simple-query-interface.d.ts.map +1 -0
- package/dist/browser/query/unit-of-work/execute-unit-of-work.d.ts +423 -0
- package/dist/browser/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -0
- package/dist/browser/query/unit-of-work/execute-unit-of-work.js +507 -0
- package/dist/browser/query/unit-of-work/execute-unit-of-work.js.map +1 -0
- package/dist/browser/query/unit-of-work/retry-policy.d.ts +23 -0
- package/dist/browser/query/unit-of-work/retry-policy.d.ts.map +1 -0
- package/dist/browser/query/unit-of-work/retry-policy.js +40 -0
- package/dist/browser/query/unit-of-work/retry-policy.js.map +1 -0
- package/dist/browser/query/unit-of-work/unit-of-work.d.ts +703 -0
- package/dist/browser/query/unit-of-work/unit-of-work.d.ts.map +1 -0
- package/dist/browser/query/unit-of-work/unit-of-work.js +1206 -0
- package/dist/browser/query/unit-of-work/unit-of-work.js.map +1 -0
- package/dist/browser/query/value-encoding.js +38 -0
- package/dist/browser/query/value-encoding.js.map +1 -0
- package/dist/browser/schema/create.d.ts +326 -0
- package/dist/browser/schema/create.d.ts.map +1 -0
- package/dist/browser/schema/create.js +89 -0
- package/dist/browser/schema/create.js.map +1 -0
- package/dist/browser/schema/generate-id.js +28 -0
- package/dist/browser/schema/generate-id.js.map +1 -0
- package/dist/browser/shared/providers.d.ts +6 -0
- package/dist/browser/shared/providers.d.ts.map +1 -0
- package/dist/browser/sql-driver/connection/connection-provider.d.ts +13 -0
- package/dist/browser/sql-driver/connection/connection-provider.d.ts.map +1 -0
- package/dist/browser/sql-driver/dialect-adapter/dialect-adapter.d.ts +7 -0
- package/dist/browser/sql-driver/dialect-adapter/dialect-adapter.d.ts.map +1 -0
- package/dist/browser/sql-driver/driver/runtime-driver.d.ts +23 -0
- package/dist/browser/sql-driver/driver/runtime-driver.d.ts.map +1 -0
- package/dist/browser/sql-driver/query-executor/plugin.d.ts +17 -0
- package/dist/browser/sql-driver/query-executor/plugin.d.ts.map +1 -0
- package/dist/browser/sql-driver/query-executor/query-executor.d.ts +36 -0
- package/dist/browser/sql-driver/query-executor/query-executor.d.ts.map +1 -0
- package/dist/browser/sql-driver/sql-driver-adapter.d.ts +29 -0
- package/dist/browser/sql-driver/sql-driver-adapter.d.ts.map +1 -0
- package/dist/browser/sql-driver/sql-driver.d.ts +38 -0
- package/dist/browser/sql-driver/sql-driver.d.ts.map +1 -0
- package/dist/browser/sync/commands.d.ts +15 -0
- package/dist/browser/sync/commands.d.ts.map +1 -0
- package/dist/browser/sync/commands.js +27 -0
- package/dist/browser/sync/commands.js.map +1 -0
- package/dist/browser/sync/types.d.ts +63 -0
- package/dist/browser/sync/types.d.ts.map +1 -0
- package/dist/browser/util/types.d.ts +8 -0
- package/dist/browser/util/types.d.ts.map +1 -0
- package/dist/browser/with-database.d.ts +29 -0
- package/dist/browser/with-database.d.ts.map +1 -0
- package/dist/client.d.ts +4 -0
- package/dist/client.js +5 -0
- package/dist/db-fragment-definition-builder.d.ts +101 -33
- package/dist/db-fragment-definition-builder.d.ts.map +1 -1
- package/dist/db-fragment-definition-builder.js +450 -60
- package/dist/db-fragment-definition-builder.js.map +1 -1
- package/dist/dispatchers/cloudflare-do/dispatcher.d.ts +20 -0
- package/dist/dispatchers/cloudflare-do/dispatcher.d.ts.map +1 -0
- package/dist/dispatchers/cloudflare-do/dispatcher.js +147 -0
- package/dist/dispatchers/cloudflare-do/dispatcher.js.map +1 -0
- package/dist/dispatchers/cloudflare-do/index.d.ts +11 -0
- package/dist/dispatchers/cloudflare-do/index.d.ts.map +1 -0
- package/dist/dispatchers/cloudflare-do/index.js +31 -0
- package/dist/dispatchers/cloudflare-do/index.js.map +1 -0
- package/dist/dispatchers/node/dispatcher.d.ts +14 -0
- package/dist/dispatchers/node/dispatcher.d.ts.map +1 -0
- package/dist/dispatchers/node/dispatcher.js +80 -0
- package/dist/dispatchers/node/dispatcher.js.map +1 -0
- package/dist/dispatchers/node/index.d.ts +12 -0
- package/dist/dispatchers/node/index.d.ts.map +1 -0
- package/dist/dispatchers/node/index.js +27 -0
- package/dist/dispatchers/node/index.js.map +1 -0
- package/dist/durable-hooks.d.ts +31 -0
- package/dist/durable-hooks.d.ts.map +1 -0
- package/dist/durable-hooks.js +23 -0
- package/dist/durable-hooks.js.map +1 -0
- package/dist/fragments/internal-fragment.d.ts +186 -8
- package/dist/fragments/internal-fragment.d.ts.map +1 -1
- package/dist/fragments/internal-fragment.js +203 -38
- package/dist/fragments/internal-fragment.js.map +1 -1
- package/dist/fragments/internal-fragment.routes.js +164 -0
- package/dist/fragments/internal-fragment.routes.js.map +1 -0
- package/dist/fragments/internal-fragment.schema.d.ts +15 -0
- package/dist/fragments/internal-fragment.schema.d.ts.map +1 -0
- package/dist/fragments/internal-fragment.schema.js +39 -0
- package/dist/fragments/internal-fragment.schema.js.map +1 -0
- package/dist/hooks/durable-hooks-logger.d.ts +10 -0
- package/dist/hooks/durable-hooks-logger.d.ts.map +1 -0
- package/dist/hooks/durable-hooks-logger.js +75 -0
- package/dist/hooks/durable-hooks-logger.js.map +1 -0
- package/dist/hooks/durable-hooks-processor.d.ts +1 -0
- package/dist/hooks/durable-hooks-processor.js +80 -0
- package/dist/hooks/durable-hooks-processor.js.map +1 -0
- package/dist/hooks/durable-hooks-runtime.js +44 -0
- package/dist/hooks/durable-hooks-runtime.js.map +1 -0
- package/dist/hooks/hooks.d.ts +100 -1
- package/dist/hooks/hooks.d.ts.map +1 -1
- package/dist/hooks/hooks.js +254 -27
- package/dist/hooks/hooks.js.map +1 -1
- package/dist/id.d.ts +2 -2
- package/dist/id.js +2 -2
- package/dist/internal/adapter-registry.d.ts +11 -0
- package/dist/internal/adapter-registry.d.ts.map +1 -0
- package/dist/internal/adapter-registry.js +135 -0
- package/dist/internal/adapter-registry.js.map +1 -0
- package/dist/internal/outbox-state.d.ts +2 -0
- package/dist/internal/outbox-state.js +26 -0
- package/dist/internal/outbox-state.js.map +1 -0
- package/dist/migration-engine/auto-from-schema.d.ts +33 -0
- package/dist/migration-engine/auto-from-schema.d.ts.map +1 -0
- package/dist/migration-engine/auto-from-schema.js +223 -37
- package/dist/migration-engine/auto-from-schema.js.map +1 -1
- package/dist/migration-engine/generation-engine.d.ts +16 -10
- package/dist/migration-engine/generation-engine.d.ts.map +1 -1
- package/dist/migration-engine/generation-engine.js +86 -35
- package/dist/migration-engine/generation-engine.js.map +1 -1
- package/dist/migration-engine/shared.d.ts +113 -0
- package/dist/migration-engine/shared.d.ts.map +1 -0
- package/dist/migration-engine/shared.js.map +1 -1
- package/dist/mod.d.ts +20 -12
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +18 -12
- package/dist/mod.js.map +1 -1
- package/dist/naming/sql-naming.d.ts +19 -0
- package/dist/naming/sql-naming.d.ts.map +1 -0
- package/dist/naming/sql-naming.js +116 -0
- package/dist/naming/sql-naming.js.map +1 -0
- package/dist/outbox/outbox-builder.js +156 -0
- package/dist/outbox/outbox-builder.js.map +1 -0
- package/dist/outbox/outbox.d.ts +54 -0
- package/dist/outbox/outbox.d.ts.map +1 -0
- package/dist/outbox/outbox.js +37 -0
- package/dist/outbox/outbox.js.map +1 -0
- package/dist/query/column-defaults.js +20 -4
- package/dist/query/column-defaults.js.map +1 -1
- package/dist/query/condition-builder.d.ts +7 -1
- package/dist/query/condition-builder.d.ts.map +1 -1
- package/dist/query/condition-builder.js +5 -1
- package/dist/query/condition-builder.js.map +1 -1
- package/dist/query/cursor-client.d.ts +105 -0
- package/dist/query/cursor-client.d.ts.map +1 -0
- package/dist/query/cursor-client.js +165 -0
- package/dist/query/cursor-client.js.map +1 -0
- package/dist/query/cursor.d.ts +3 -1
- package/dist/query/cursor.d.ts.map +1 -1
- package/dist/query/cursor.js +51 -14
- package/dist/query/cursor.js.map +1 -1
- package/dist/query/db-now.d.ts +22 -0
- package/dist/query/db-now.d.ts.map +1 -0
- package/dist/query/db-now.js +35 -0
- package/dist/query/db-now.js.map +1 -0
- package/dist/query/orm/orm.js.map +1 -1
- package/dist/query/serialize/create-sql-serializer.js +5 -4
- package/dist/query/serialize/create-sql-serializer.js.map +1 -1
- package/dist/query/serialize/dialect/mysql-serializer.js +12 -6
- package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -1
- package/dist/query/serialize/dialect/postgres-serializer.js +25 -7
- package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -1
- package/dist/query/serialize/dialect/sqlite-serializer.js +60 -12
- package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -1
- package/dist/query/serialize/sql-serializer.js +2 -2
- package/dist/query/serialize/sql-serializer.js.map +1 -1
- package/dist/query/simple-query-interface.d.ts +13 -4
- package/dist/query/simple-query-interface.d.ts.map +1 -1
- package/dist/query/unit-of-work/execute-unit-of-work.d.ts +37 -2
- package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work/execute-unit-of-work.js +50 -24
- package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -1
- package/dist/query/unit-of-work/unit-of-work.d.ts +92 -30
- package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work/unit-of-work.js +136 -11
- package/dist/query/unit-of-work/unit-of-work.js.map +1 -1
- package/dist/query/value-decoding.js +16 -6
- package/dist/query/value-decoding.js.map +1 -1
- package/dist/query/value-encoding.js +29 -9
- package/dist/query/value-encoding.js.map +1 -1
- package/dist/schema/create.d.ts +103 -35
- package/dist/schema/create.d.ts.map +1 -1
- package/dist/schema/create.js +172 -58
- package/dist/schema/create.js.map +1 -1
- package/dist/schema/generate-id.js +2 -2
- package/dist/schema/generate-id.js.map +1 -1
- package/dist/schema/type-conversion/create-sql-type-mapper.js +4 -3
- package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -1
- package/dist/schema/type-conversion/dialect/sqlite.js +9 -0
- package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -1
- package/dist/schema/validator.d.ts +10 -0
- package/dist/schema/validator.d.ts.map +1 -0
- package/dist/schema/validator.js +123 -0
- package/dist/schema/validator.js.map +1 -0
- package/dist/schema-output/drizzle.d.ts +30 -0
- package/dist/schema-output/drizzle.d.ts.map +1 -0
- package/dist/{adapters/drizzle/generate.js → schema-output/drizzle.js} +88 -60
- package/dist/schema-output/drizzle.js.map +1 -0
- package/dist/schema-output/prisma.d.ts +17 -0
- package/dist/schema-output/prisma.d.ts.map +1 -0
- package/dist/schema-output/prisma.js +307 -0
- package/dist/schema-output/prisma.js.map +1 -0
- package/dist/sql-driver/dialects/durable-object-dialect.js +3 -9
- package/dist/sql-driver/dialects/durable-object-dialect.js.map +1 -1
- package/dist/sql-driver/query-executor/default-query-executor.js.map +1 -1
- package/dist/sql-driver/query-executor/query-executor-base.js.map +1 -1
- package/dist/sql-driver/sql-driver-adapter.js.map +1 -1
- package/dist/sql-driver/sql.js.map +1 -1
- package/dist/sync/commands.d.ts +15 -0
- package/dist/sync/commands.d.ts.map +1 -0
- package/dist/sync/commands.js +27 -0
- package/dist/sync/commands.js.map +1 -0
- package/dist/sync/index.d.ts +4 -0
- package/dist/sync/index.js +4 -0
- package/dist/sync/read-tracking.d.ts +25 -0
- package/dist/sync/read-tracking.d.ts.map +1 -0
- package/dist/sync/read-tracking.js +148 -0
- package/dist/sync/read-tracking.js.map +1 -0
- package/dist/sync/submit.js +213 -0
- package/dist/sync/submit.js.map +1 -0
- package/dist/sync/types.d.ts +63 -0
- package/dist/sync/types.d.ts.map +1 -0
- package/dist/util/default-database-adapter.js +66 -0
- package/dist/util/default-database-adapter.js.map +1 -0
- package/dist/with-database.d.ts +3 -6
- package/dist/with-database.d.ts.map +1 -1
- package/dist/with-database.js +8 -7
- package/dist/with-database.js.map +1 -1
- package/package.json +62 -55
- package/src/adapters/adapters.ts +33 -26
- package/src/adapters/drizzle/migrate-drizzle.test.ts +99 -41
- package/src/adapters/drizzle/migration-parity-drizzle-kit.test.ts +601 -0
- package/src/adapters/drizzle/test-utils.ts +13 -8
- package/src/adapters/generic-sql/driver-config.ts +38 -0
- package/src/adapters/generic-sql/generic-sql-adapter.test.ts +10 -8
- package/src/adapters/generic-sql/generic-sql-adapter.ts +117 -34
- package/src/adapters/generic-sql/generic-sql-uow-executor.test.ts +55 -0
- package/src/adapters/generic-sql/generic-sql-uow-executor.ts +297 -3
- package/src/adapters/generic-sql/migration/adapter-migration-parity.test.ts +120 -0
- package/src/adapters/generic-sql/migration/cold-kysely.ts +1 -0
- package/src/adapters/generic-sql/migration/dialect/mysql.test.ts +27 -8
- package/src/adapters/generic-sql/migration/dialect/mysql.ts +47 -8
- package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +28 -9
- package/src/adapters/generic-sql/migration/dialect/postgres.ts +9 -4
- package/src/adapters/generic-sql/migration/dialect/sqlite.test.ts +839 -8
- package/src/adapters/generic-sql/migration/dialect/sqlite.ts +396 -53
- package/src/adapters/generic-sql/migration/executor.test.ts +52 -0
- package/src/adapters/generic-sql/migration/executor.ts +47 -4
- package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +238 -46
- package/src/adapters/generic-sql/migration/prepared-migrations.ts +21 -13
- package/src/adapters/generic-sql/migration/sql-generator.ts +145 -66
- package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +11 -8
- package/src/adapters/generic-sql/query/cursor-utils.test.ts +272 -0
- package/src/adapters/generic-sql/query/cursor-utils.ts +42 -7
- package/src/adapters/generic-sql/query/db-now-sql.ts +49 -0
- package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +171 -35
- package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +53 -40
- package/src/adapters/generic-sql/query/select-builder.test.ts +16 -11
- package/src/adapters/generic-sql/query/select-builder.ts +7 -3
- package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +75 -6
- package/src/adapters/generic-sql/query/sql-query-compiler.ts +129 -24
- package/src/adapters/generic-sql/query/where-builder.test.ts +96 -20
- package/src/adapters/generic-sql/query/where-builder.ts +112 -41
- package/src/adapters/{kysely/kysely-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-migrations.test.ts} +11 -20
- package/src/adapters/generic-sql/sql-adapter-pglite-pagination.test.ts +851 -0
- package/src/adapters/{drizzle/drizzle-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-queries.test.ts} +18 -15
- package/src/adapters/generic-sql/{test/generic-drizzle-adapter-sqlite3.test.ts → sql-adapter-sqlite3-driver.test.ts} +282 -14
- package/src/adapters/{drizzle/drizzle-adapter-sqlite3.test.ts → generic-sql/sql-adapter-sqlite3-uow.test.ts} +129 -12
- package/src/adapters/{kysely/kysely-adapter-sqlocal.test.ts → generic-sql/sql-adapter-sqlocal.test.ts} +9 -7
- package/src/adapters/generic-sql/sqlite-storage.ts +20 -0
- package/src/adapters/generic-sql/uow-decoder.test.ts +5 -4
- package/src/adapters/generic-sql/uow-decoder.ts +23 -5
- package/src/adapters/generic-sql/uow-encoder.test.ts +36 -3
- package/src/adapters/generic-sql/uow-encoder.ts +48 -13
- package/src/adapters/in-memory/condition-evaluator.test.ts +194 -0
- package/src/adapters/in-memory/condition-evaluator.ts +280 -0
- package/src/adapters/in-memory/errors.ts +20 -0
- package/src/adapters/in-memory/in-memory-adapter.ts +388 -0
- package/src/adapters/in-memory/in-memory-uow.mutations.test.ts +344 -0
- package/src/adapters/in-memory/in-memory-uow.retrieval.test.ts +255 -0
- package/src/adapters/in-memory/in-memory-uow.ts +1724 -0
- package/src/adapters/in-memory/index.ts +3 -0
- package/src/adapters/in-memory/options.test.ts +42 -0
- package/src/adapters/in-memory/options.ts +91 -0
- package/src/adapters/in-memory/outbox.test.ts +361 -0
- package/src/adapters/in-memory/reference-resolution.test.ts +51 -0
- package/src/adapters/in-memory/reference-resolution.ts +67 -0
- package/src/adapters/in-memory/sorted-array-index.test.ts +124 -0
- package/src/adapters/in-memory/sorted-array-index.ts +228 -0
- package/src/adapters/in-memory/store.test.ts +69 -0
- package/src/adapters/in-memory/store.ts +145 -0
- package/src/adapters/in-memory/value-comparison.ts +53 -0
- package/src/adapters/in-memory/value-normalization.test.ts +58 -0
- package/src/adapters/prisma/prisma-adapter-sqlite3.test.ts +1207 -0
- package/src/adapters/shared/from-unit-of-work-compiler.ts +159 -47
- package/src/adapters/shared/uow-operation-compiler.ts +28 -18
- package/src/adapters/sql/index.ts +12 -0
- package/src/browser/mod.ts +64 -0
- package/src/client.ts +19 -0
- package/src/db-fragment-definition-builder.test.ts +845 -53
- package/src/db-fragment-definition-builder.ts +911 -95
- package/src/db-fragment-instantiator.test.ts +210 -94
- package/src/db-fragment-integration.test.ts +17 -12
- package/src/dispatchers/cloudflare-do/dispatcher.ts +204 -0
- package/src/dispatchers/cloudflare-do/index.test.ts +206 -0
- package/src/dispatchers/cloudflare-do/index.ts +63 -0
- package/src/dispatchers/node/dispatcher.ts +112 -0
- package/src/dispatchers/node/index.test.ts +120 -0
- package/src/dispatchers/node/index.ts +50 -0
- package/src/durable-hooks.test.ts +80 -0
- package/src/durable-hooks.ts +67 -0
- package/src/fragments/internal-fragment.routes.test.ts +570 -0
- package/src/fragments/internal-fragment.routes.ts +334 -0
- package/src/fragments/internal-fragment.schema.ts +95 -0
- package/src/fragments/internal-fragment.test.ts +505 -83
- package/src/fragments/internal-fragment.ts +453 -70
- package/src/hooks/durable-hooks-logger.ts +126 -0
- package/src/hooks/durable-hooks-processor.pglite.test.ts +87 -0
- package/src/hooks/durable-hooks-processor.test.ts +282 -0
- package/src/hooks/durable-hooks-processor.ts +173 -0
- package/src/hooks/durable-hooks-runtime.test.ts +65 -0
- package/src/hooks/durable-hooks-runtime.ts +81 -0
- package/src/hooks/hooks.test.ts +455 -34
- package/src/hooks/hooks.ts +501 -34
- package/src/id.test.ts +34 -0
- package/src/id.ts +1 -3
- package/src/internal/adapter-registry.test.ts +93 -0
- package/src/internal/adapter-registry.ts +239 -0
- package/src/internal/outbox-state.ts +43 -0
- package/src/migration-engine/auto-from-schema.test.ts +107 -14
- package/src/migration-engine/auto-from-schema.ts +365 -44
- package/src/migration-engine/create.test.ts +4 -3
- package/src/migration-engine/create.ts +1 -1
- package/src/migration-engine/generation-engine.test.ts +292 -110
- package/src/migration-engine/generation-engine.ts +117 -66
- package/src/migration-engine/shared.ts +14 -0
- package/src/mod.ts +95 -39
- package/src/naming/sql-naming.ts +181 -0
- package/src/outbox/outbox-builder.ts +241 -0
- package/src/outbox/outbox.test.ts +424 -0
- package/src/outbox/outbox.ts +139 -0
- package/src/query/column-defaults.ts +42 -4
- package/src/query/condition-builder.test.ts +18 -3
- package/src/query/condition-builder.ts +7 -0
- package/src/query/cursor-client.test.ts +70 -0
- package/src/query/cursor-client.ts +263 -0
- package/src/query/cursor.test.ts +119 -20
- package/src/query/cursor.ts +88 -27
- package/src/query/db-now.ts +73 -0
- package/src/query/orm/orm.ts +2 -2
- package/src/query/query-type.test.ts +4 -3
- package/src/query/serialize/create-sql-serializer.ts +10 -5
- package/src/query/serialize/dialect/mysql-serializer.ts +13 -5
- package/src/query/serialize/dialect/postgres-serializer.ts +35 -5
- package/src/query/serialize/dialect/sqlite-serializer.test.ts +90 -3
- package/src/query/serialize/dialect/sqlite-serializer.ts +108 -12
- package/src/query/serialize/sql-serializer.ts +4 -4
- package/src/query/simple-query-interface.ts +15 -4
- package/src/query/unit-of-work/execute-unit-of-work.test.ts +372 -10
- package/src/query/unit-of-work/execute-unit-of-work.ts +87 -27
- package/src/query/unit-of-work/retry-policy.test.ts +1 -0
- package/src/query/unit-of-work/tx-builder.test.ts +73 -1
- package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +17 -16
- package/src/query/unit-of-work/unit-of-work-types.test.ts +42 -12
- package/src/query/unit-of-work/unit-of-work.test.ts +196 -39
- package/src/query/unit-of-work/unit-of-work.ts +309 -38
- package/src/query/value-decoding.test.ts +63 -4
- package/src/query/value-decoding.ts +32 -6
- package/src/query/value-encoding.test.ts +86 -2
- package/src/query/value-encoding.ts +56 -6
- package/src/schema/create.test.ts +293 -47
- package/src/schema/create.ts +406 -70
- package/src/schema/generate-id.test.ts +3 -2
- package/src/schema/generate-id.ts +2 -2
- package/src/schema/serialize.test.ts +18 -5
- package/src/schema/type-conversion/create-sql-type-mapper.ts +8 -3
- package/src/schema/type-conversion/dialect/sqlite.ts +18 -0
- package/src/schema/type-conversion/type-mapping.test.ts +26 -1
- package/src/schema/validator.test.ts +199 -0
- package/src/schema/validator.ts +232 -0
- package/src/{adapters/drizzle/generate.test.ts → schema-output/drizzle.test.ts} +232 -129
- package/src/{adapters/drizzle/generate.ts → schema-output/drizzle.ts} +155 -99
- package/src/schema-output/prisma.test.ts +694 -0
- package/src/schema-output/prisma.ts +593 -0
- package/src/sql-driver/better-sqlite3.test.ts +5 -3
- package/src/sql-driver/dialects/durable-object-dialect.ts +3 -8
- package/src/sql-driver/query-executor/default-query-executor.ts +1 -1
- package/src/sql-driver/query-executor/query-executor-base.ts +1 -1
- package/src/sql-driver/query-executor/query-executor.ts +1 -1
- package/src/sql-driver/sql-driver-adapter.ts +2 -2
- package/src/sql-driver/sql.ts +2 -1
- package/src/sql-driver/sqlocal.test.ts +4 -2
- package/src/sync/commands.test.ts +39 -0
- package/src/sync/commands.ts +51 -0
- package/src/sync/conflict-checker.test.ts +450 -0
- package/src/sync/conflict-checker.ts +248 -0
- package/src/sync/index.ts +14 -0
- package/src/sync/plan.ts +9 -0
- package/src/sync/read-tracking.test.ts +177 -0
- package/src/sync/read-tracking.ts +287 -0
- package/src/sync/submit.test.ts +205 -0
- package/src/sync/submit.ts +328 -0
- package/src/sync/types.ts +80 -0
- package/src/util/default-database-adapter.ts +119 -0
- package/src/with-database.ts +20 -31
- package/tsconfig.json +1 -1
- package/tsdown.config.ts +38 -24
- package/vitest.config.ts +1 -0
- package/dist/adapters/drizzle/drizzle-adapter.d.ts +0 -20
- package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +0 -1
- package/dist/adapters/drizzle/drizzle-adapter.js +0 -27
- package/dist/adapters/drizzle/drizzle-adapter.js.map +0 -1
- package/dist/adapters/drizzle/generate.d.ts +0 -30
- package/dist/adapters/drizzle/generate.d.ts.map +0 -1
- package/dist/adapters/drizzle/generate.js.map +0 -1
- package/dist/adapters/kysely/kysely-adapter.d.ts +0 -19
- package/dist/adapters/kysely/kysely-adapter.d.ts.map +0 -1
- package/dist/adapters/kysely/kysely-adapter.js +0 -17
- package/dist/adapters/kysely/kysely-adapter.js.map +0 -1
- package/dist/adapters/shared/table-name-mapper.d.ts +0 -12
- package/dist/adapters/shared/table-name-mapper.d.ts.map +0 -1
- package/dist/adapters/shared/table-name-mapper.js +0 -43
- package/dist/adapters/shared/table-name-mapper.js.map +0 -1
- package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js +0 -165
- package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js.map +0 -1
- package/dist/packages/fragno/dist/api/bind-services.js +0 -20
- package/dist/packages/fragno/dist/api/bind-services.js.map +0 -1
- package/dist/packages/fragno/dist/api/error.js +0 -48
- package/dist/packages/fragno/dist/api/error.js.map +0 -1
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js +0 -320
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +0 -1
- package/dist/packages/fragno/dist/api/fragment-instantiator.js +0 -525
- package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +0 -1
- package/dist/packages/fragno/dist/api/fragno-response.js +0 -73
- package/dist/packages/fragno/dist/api/fragno-response.js.map +0 -1
- package/dist/packages/fragno/dist/api/internal/response-stream.js +0 -81
- package/dist/packages/fragno/dist/api/internal/response-stream.js.map +0 -1
- package/dist/packages/fragno/dist/api/internal/route.js +0 -10
- package/dist/packages/fragno/dist/api/internal/route.js.map +0 -1
- package/dist/packages/fragno/dist/api/mutable-request-state.js +0 -97
- package/dist/packages/fragno/dist/api/mutable-request-state.js.map +0 -1
- package/dist/packages/fragno/dist/api/request-context-storage.js +0 -43
- package/dist/packages/fragno/dist/api/request-context-storage.js.map +0 -1
- package/dist/packages/fragno/dist/api/request-input-context.js +0 -118
- package/dist/packages/fragno/dist/api/request-input-context.js.map +0 -1
- package/dist/packages/fragno/dist/api/request-middleware.js +0 -83
- package/dist/packages/fragno/dist/api/request-middleware.js.map +0 -1
- package/dist/packages/fragno/dist/api/request-output-context.js +0 -119
- package/dist/packages/fragno/dist/api/request-output-context.js.map +0 -1
- package/dist/packages/fragno/dist/api/route.js +0 -17
- package/dist/packages/fragno/dist/api/route.js.map +0 -1
- package/dist/packages/fragno/dist/internal/symbols.js +0 -10
- package/dist/packages/fragno/dist/internal/symbols.js.map +0 -1
- package/dist/schema-generator/schema-generator.d.ts +0 -15
- package/dist/schema-generator/schema-generator.d.ts.map +0 -1
- package/src/adapters/drizzle/drizzle-adapter.ts +0 -39
- package/src/adapters/kysely/kysely-adapter.ts +0 -27
- package/src/adapters/shared/table-name-mapper.ts +0 -50
- package/src/schema-generator/schema-generator.ts +0 -12
|
@@ -1,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;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { beforeAll, describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import type { AnyColumn } from "../schema/create";
|
|
4
|
+
import { Cursor, createCursorFromRecord, decodeCursor } from "./cursor-client";
|
|
5
|
+
|
|
6
|
+
const ensureBase64Helpers = () => {
|
|
7
|
+
const g = globalThis as typeof globalThis & {
|
|
8
|
+
btoa?: (input: string) => string;
|
|
9
|
+
atob?: (input: string) => string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
if (!g.btoa) {
|
|
13
|
+
g.btoa = (input: string) => Buffer.from(input, "binary").toString("base64");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (!g.atob) {
|
|
17
|
+
g.atob = (input: string) => Buffer.from(input, "base64").toString("binary");
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
beforeAll(() => {
|
|
22
|
+
ensureBase64Helpers();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe("cursor-client", () => {
|
|
26
|
+
it("roundtrips cursor data with unicode values", () => {
|
|
27
|
+
const cursor = new Cursor({
|
|
28
|
+
indexName: "idx_created",
|
|
29
|
+
orderDirection: "asc",
|
|
30
|
+
pageSize: 25,
|
|
31
|
+
indexValues: {
|
|
32
|
+
createdAt: 1730000000000,
|
|
33
|
+
name: "München",
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const encoded = cursor.encode();
|
|
38
|
+
const decoded = decodeCursor(encoded);
|
|
39
|
+
|
|
40
|
+
expect(decoded.indexName).toBe("idx_created");
|
|
41
|
+
expect(decoded.orderDirection).toBe("asc");
|
|
42
|
+
expect(decoded.pageSize).toBe(25);
|
|
43
|
+
expect(decoded.indexValues).toEqual({
|
|
44
|
+
createdAt: 1730000000000,
|
|
45
|
+
name: "München",
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("creates a cursor from a record", () => {
|
|
50
|
+
const column: AnyColumn = {
|
|
51
|
+
name: "createdAt",
|
|
52
|
+
type: "timestamp",
|
|
53
|
+
role: "regular",
|
|
54
|
+
isNullable: false,
|
|
55
|
+
} as AnyColumn;
|
|
56
|
+
|
|
57
|
+
const cursor = createCursorFromRecord({ createdAt: 123, other: "ignore" }, [column], {
|
|
58
|
+
indexName: "idx_created",
|
|
59
|
+
orderDirection: "desc",
|
|
60
|
+
pageSize: 10,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
expect(cursor.indexValues).toEqual({ createdAt: 123 });
|
|
64
|
+
expect(cursor.orderDirection).toBe("desc");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("rejects malformed cursor payloads", () => {
|
|
68
|
+
expect(() => decodeCursor("not-base64")).toThrowError(/Invalid cursor/);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import type { AnyColumn } from "../schema/create";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Cursor object containing all information needed for pagination
|
|
5
|
+
*/
|
|
6
|
+
export class Cursor {
|
|
7
|
+
readonly #indexName: string;
|
|
8
|
+
readonly #orderDirection: "asc" | "desc";
|
|
9
|
+
readonly #pageSize: number;
|
|
10
|
+
readonly #indexValues: Record<string, unknown>;
|
|
11
|
+
|
|
12
|
+
constructor(data: {
|
|
13
|
+
indexName: string;
|
|
14
|
+
orderDirection: "asc" | "desc";
|
|
15
|
+
pageSize: number;
|
|
16
|
+
indexValues: Record<string, unknown>;
|
|
17
|
+
}) {
|
|
18
|
+
this.#indexName = data.indexName;
|
|
19
|
+
this.#orderDirection = data.orderDirection;
|
|
20
|
+
this.#pageSize = data.pageSize;
|
|
21
|
+
this.#indexValues = data.indexValues;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Get the index name being used for pagination
|
|
26
|
+
*/
|
|
27
|
+
get indexName(): string {
|
|
28
|
+
return this.#indexName;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Get the ordering direction
|
|
33
|
+
*/
|
|
34
|
+
get orderDirection(): "asc" | "desc" {
|
|
35
|
+
return this.#orderDirection;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get the page size
|
|
40
|
+
*/
|
|
41
|
+
get pageSize(): number {
|
|
42
|
+
return this.#pageSize;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get the cursor position values
|
|
47
|
+
*/
|
|
48
|
+
get indexValues(): Record<string, unknown> {
|
|
49
|
+
return this.#indexValues;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Encode cursor to an opaque base64 string (safe to send to client)
|
|
54
|
+
*/
|
|
55
|
+
encode(): string {
|
|
56
|
+
assertSerializableIndexValues(this.#indexValues);
|
|
57
|
+
const data: CursorData = {
|
|
58
|
+
v: 1,
|
|
59
|
+
indexName: this.#indexName,
|
|
60
|
+
orderDirection: this.#orderDirection,
|
|
61
|
+
pageSize: this.#pageSize,
|
|
62
|
+
indexValues: this.#indexValues,
|
|
63
|
+
};
|
|
64
|
+
return encodeCursorData(data);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Result of a cursor-based query containing items and pagination cursor
|
|
70
|
+
*/
|
|
71
|
+
export interface CursorResult<T> {
|
|
72
|
+
/**
|
|
73
|
+
* The query results
|
|
74
|
+
*/
|
|
75
|
+
items: T[];
|
|
76
|
+
/**
|
|
77
|
+
* Cursor to fetch the next page (undefined if no more results)
|
|
78
|
+
*/
|
|
79
|
+
cursor?: Cursor;
|
|
80
|
+
/**
|
|
81
|
+
* Whether there are more results available after this page
|
|
82
|
+
*/
|
|
83
|
+
hasNextPage: boolean;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Cursor data structure for serialization
|
|
88
|
+
*/
|
|
89
|
+
export interface CursorData {
|
|
90
|
+
v: number; // version
|
|
91
|
+
indexName: string;
|
|
92
|
+
orderDirection: "asc" | "desc";
|
|
93
|
+
pageSize: number;
|
|
94
|
+
indexValues: Record<string, unknown>;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const getBase64Helpers = () => {
|
|
98
|
+
const { btoa, atob, TextEncoder, TextDecoder } = globalThis;
|
|
99
|
+
|
|
100
|
+
if (!btoa || !atob) {
|
|
101
|
+
throw new Error("Base64 helpers (btoa/atob) are not available in this environment.");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (!TextEncoder || !TextDecoder) {
|
|
105
|
+
throw new Error("TextEncoder/TextDecoder are required for cursor encoding.");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const encodeBase64 = (input: string): string => {
|
|
109
|
+
const bytes = new TextEncoder().encode(input);
|
|
110
|
+
let binary = "";
|
|
111
|
+
for (const byte of bytes) {
|
|
112
|
+
binary += String.fromCharCode(byte);
|
|
113
|
+
}
|
|
114
|
+
return btoa(binary);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const decodeBase64 = (input: string): string => {
|
|
118
|
+
const binary = atob(input);
|
|
119
|
+
const bytes = new Uint8Array(binary.length);
|
|
120
|
+
for (let i = 0; i < binary.length; i += 1) {
|
|
121
|
+
bytes[i] = binary.charCodeAt(i);
|
|
122
|
+
}
|
|
123
|
+
return new TextDecoder().decode(bytes);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
return { encodeBase64, decodeBase64 };
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Encode cursor data to a base64 string (internal)
|
|
131
|
+
*/
|
|
132
|
+
function encodeCursorData(data: CursorData): string {
|
|
133
|
+
let json: string;
|
|
134
|
+
try {
|
|
135
|
+
json = JSON.stringify(data);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
throw new Error(`Invalid cursor: ${error instanceof Error ? error.message : "malformed data"}`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return getBase64Helpers().encodeBase64(json);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Decode a base64 cursor string back to a Cursor object
|
|
145
|
+
*
|
|
146
|
+
* @param cursor - The base64-encoded cursor string
|
|
147
|
+
* @returns Decoded Cursor object
|
|
148
|
+
* @throws Error if cursor is invalid or malformed
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* const cursor = decodeCursor("eyJpbmRleFZhbHVlcyI6e30sImRpcmVjdGlvbiI6ImZvcndhcmQifQ==");
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
export function decodeCursor(cursor: string): Cursor {
|
|
156
|
+
try {
|
|
157
|
+
const json = getBase64Helpers().decodeBase64(cursor);
|
|
158
|
+
const data = JSON.parse(json);
|
|
159
|
+
const record = data as Record<string, unknown>;
|
|
160
|
+
|
|
161
|
+
// Validate structure
|
|
162
|
+
if (
|
|
163
|
+
!isPlainObject(data) ||
|
|
164
|
+
!isPlainObject(record["indexValues"]) ||
|
|
165
|
+
typeof record["indexName"] !== "string" ||
|
|
166
|
+
record["indexName"].length === 0 ||
|
|
167
|
+
typeof record["orderDirection"] !== "string" ||
|
|
168
|
+
(record["orderDirection"] !== "asc" && record["orderDirection"] !== "desc") ||
|
|
169
|
+
typeof record["pageSize"] !== "number" ||
|
|
170
|
+
!Number.isFinite(record["pageSize"]) ||
|
|
171
|
+
!Number.isInteger(record["pageSize"]) ||
|
|
172
|
+
record["pageSize"] <= 0
|
|
173
|
+
) {
|
|
174
|
+
throw new Error("Invalid cursor structure");
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Only support v1
|
|
178
|
+
if (typeof record["v"] !== "number") {
|
|
179
|
+
throw new Error("Unsupported cursor version: missing. Only v1 is supported.");
|
|
180
|
+
}
|
|
181
|
+
const version = record["v"];
|
|
182
|
+
if (version !== 1) {
|
|
183
|
+
throw new Error(`Unsupported cursor version: ${version}. Only v1 is supported.`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return new Cursor({
|
|
187
|
+
indexName: record["indexName"],
|
|
188
|
+
orderDirection: record["orderDirection"],
|
|
189
|
+
pageSize: record["pageSize"],
|
|
190
|
+
indexValues: record["indexValues"],
|
|
191
|
+
});
|
|
192
|
+
} catch (error) {
|
|
193
|
+
throw new Error(`Invalid cursor: ${error instanceof Error ? error.message : "malformed data"}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Create a cursor from a record and pagination metadata
|
|
199
|
+
*
|
|
200
|
+
* @param record - The database record
|
|
201
|
+
* @param indexColumns - The columns that make up the index
|
|
202
|
+
* @param metadata - Pagination metadata (index name, order direction, page size)
|
|
203
|
+
* @returns Cursor object
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```ts
|
|
207
|
+
* const cursor = createCursorFromRecord(
|
|
208
|
+
* { id: "abc", name: "Alice", createdAt: 123 },
|
|
209
|
+
* [table.columns.createdAt, table.columns.id],
|
|
210
|
+
* {
|
|
211
|
+
* indexName: "idx_created",
|
|
212
|
+
* orderDirection: "asc",
|
|
213
|
+
* pageSize: 10
|
|
214
|
+
* }
|
|
215
|
+
* );
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
export function createCursorFromRecord(
|
|
219
|
+
record: Record<string, unknown>,
|
|
220
|
+
indexColumns: AnyColumn[],
|
|
221
|
+
metadata: {
|
|
222
|
+
indexName: string;
|
|
223
|
+
orderDirection: "asc" | "desc";
|
|
224
|
+
pageSize: number;
|
|
225
|
+
},
|
|
226
|
+
): Cursor {
|
|
227
|
+
const indexValues: Record<string, unknown> = {};
|
|
228
|
+
|
|
229
|
+
for (const col of indexColumns) {
|
|
230
|
+
const value = record[col.name];
|
|
231
|
+
if (value === undefined) {
|
|
232
|
+
throw new Error(`Record is missing value for index column "${col.name}".`);
|
|
233
|
+
}
|
|
234
|
+
indexValues[col.name] = value;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return new Cursor({
|
|
238
|
+
indexName: metadata.indexName,
|
|
239
|
+
orderDirection: metadata.orderDirection,
|
|
240
|
+
pageSize: metadata.pageSize,
|
|
241
|
+
indexValues,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const isPlainObject = (value: unknown): value is Record<string, unknown> =>
|
|
246
|
+
typeof value === "object" && value !== null && !Array.isArray(value);
|
|
247
|
+
|
|
248
|
+
const assertSerializableIndexValues = (values: Record<string, unknown>): void => {
|
|
249
|
+
for (const [key, value] of Object.entries(values)) {
|
|
250
|
+
if (value === undefined) {
|
|
251
|
+
throw new Error(`Cursor index value "${key}" is undefined.`);
|
|
252
|
+
}
|
|
253
|
+
if (typeof value === "number" && !Number.isFinite(value)) {
|
|
254
|
+
throw new Error(`Cursor index value "${key}" must be a finite number.`);
|
|
255
|
+
}
|
|
256
|
+
if (typeof value === "bigint") {
|
|
257
|
+
throw new Error(`Cursor index value "${key}" must not be a BigInt.`);
|
|
258
|
+
}
|
|
259
|
+
if (typeof value === "function" || typeof value === "symbol") {
|
|
260
|
+
throw new Error(`Cursor index value "${key}" is not JSON-serializable.`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
};
|
package/src/query/cursor.test.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { column, idColumn, schema } from "../schema/create";
|
|
2
|
+
|
|
4
3
|
import {
|
|
5
4
|
BetterSQLite3DriverConfig,
|
|
6
5
|
MySQL2DriverConfig,
|
|
7
6
|
NodePostgresDriverConfig,
|
|
8
7
|
} from "../adapters/generic-sql/driver-config";
|
|
8
|
+
import { column, idColumn, schema } from "../schema/create";
|
|
9
|
+
import { decodeCursor, createCursorFromRecord, serializeCursorValues, Cursor } from "./cursor";
|
|
9
10
|
|
|
10
11
|
describe("Cursor utilities", () => {
|
|
11
12
|
describe("Cursor class encode and decode", () => {
|
|
@@ -92,6 +93,39 @@ describe("Cursor utilities", () => {
|
|
|
92
93
|
const decoded = decodeCursor(encoded);
|
|
93
94
|
expect(decoded.indexValues).toEqual({});
|
|
94
95
|
});
|
|
96
|
+
|
|
97
|
+
it("should throw when index values contain undefined", () => {
|
|
98
|
+
const cursor = new Cursor({
|
|
99
|
+
indexName: "_primary",
|
|
100
|
+
orderDirection: "asc",
|
|
101
|
+
pageSize: 10,
|
|
102
|
+
indexValues: { id: undefined },
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
expect(() => cursor.encode()).toThrow(/undefined/i);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("should throw when index values contain BigInt", () => {
|
|
109
|
+
const cursor = new Cursor({
|
|
110
|
+
indexName: "_primary",
|
|
111
|
+
orderDirection: "asc",
|
|
112
|
+
pageSize: 10,
|
|
113
|
+
indexValues: { id: 1n },
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
expect(() => cursor.encode()).toThrow(/bigint/i);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("should throw when index values contain non-finite numbers", () => {
|
|
120
|
+
const cursor = new Cursor({
|
|
121
|
+
indexName: "_primary",
|
|
122
|
+
orderDirection: "asc",
|
|
123
|
+
pageSize: 10,
|
|
124
|
+
indexValues: { id: Number.NaN },
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
expect(() => cursor.encode()).toThrow(/finite/i);
|
|
128
|
+
});
|
|
95
129
|
});
|
|
96
130
|
|
|
97
131
|
describe("decodeCursor error handling", () => {
|
|
@@ -145,11 +179,58 @@ describe("Cursor utilities", () => {
|
|
|
145
179
|
const encoded = Buffer.from(JSON.stringify(invalidData), "utf-8").toString("base64");
|
|
146
180
|
expect(() => decodeCursor(encoded)).toThrow(/invalid cursor/i);
|
|
147
181
|
});
|
|
182
|
+
|
|
183
|
+
it("should throw error for array indexValues", () => {
|
|
184
|
+
const invalidData = {
|
|
185
|
+
v: 1,
|
|
186
|
+
indexValues: [],
|
|
187
|
+
indexName: "test",
|
|
188
|
+
orderDirection: "asc",
|
|
189
|
+
pageSize: 10,
|
|
190
|
+
};
|
|
191
|
+
const encoded = Buffer.from(JSON.stringify(invalidData), "utf-8").toString("base64");
|
|
192
|
+
expect(() => decodeCursor(encoded)).toThrow(/invalid cursor/i);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("should throw error for non-string indexName", () => {
|
|
196
|
+
const invalidData = {
|
|
197
|
+
v: 1,
|
|
198
|
+
indexValues: { id: "test" },
|
|
199
|
+
indexName: 123,
|
|
200
|
+
orderDirection: "asc",
|
|
201
|
+
pageSize: 10,
|
|
202
|
+
};
|
|
203
|
+
const encoded = Buffer.from(JSON.stringify(invalidData), "utf-8").toString("base64");
|
|
204
|
+
expect(() => decodeCursor(encoded)).toThrow(/invalid cursor/i);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("should throw error for invalid pageSize values", () => {
|
|
208
|
+
const invalidData = {
|
|
209
|
+
v: 1,
|
|
210
|
+
indexValues: { id: "test" },
|
|
211
|
+
indexName: "test",
|
|
212
|
+
orderDirection: "asc",
|
|
213
|
+
pageSize: 0,
|
|
214
|
+
};
|
|
215
|
+
const encoded = Buffer.from(JSON.stringify(invalidData), "utf-8").toString("base64");
|
|
216
|
+
expect(() => decodeCursor(encoded)).toThrow(/invalid cursor/i);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it("should throw error for missing cursor version", () => {
|
|
220
|
+
const invalidData = {
|
|
221
|
+
indexValues: { id: "test" },
|
|
222
|
+
indexName: "test",
|
|
223
|
+
orderDirection: "asc",
|
|
224
|
+
pageSize: 10,
|
|
225
|
+
};
|
|
226
|
+
const encoded = Buffer.from(JSON.stringify(invalidData), "utf-8").toString("base64");
|
|
227
|
+
expect(() => decodeCursor(encoded)).toThrow(/unsupported cursor version/i);
|
|
228
|
+
});
|
|
148
229
|
});
|
|
149
230
|
|
|
150
231
|
describe("createCursorFromRecord", () => {
|
|
151
232
|
it("should create a cursor from a record with single column index", () => {
|
|
152
|
-
const testSchema = schema((s) =>
|
|
233
|
+
const testSchema = schema("test", (s) =>
|
|
153
234
|
s.addTable("users", (t) =>
|
|
154
235
|
t.addColumn("id", idColumn()).addColumn("name", column("string")),
|
|
155
236
|
),
|
|
@@ -172,7 +253,7 @@ describe("Cursor utilities", () => {
|
|
|
172
253
|
});
|
|
173
254
|
|
|
174
255
|
it("should create a cursor from a record with multi-column index", () => {
|
|
175
|
-
const testSchema = schema((s) =>
|
|
256
|
+
const testSchema = schema("test", (s) =>
|
|
176
257
|
s.addTable("posts", (t) =>
|
|
177
258
|
t
|
|
178
259
|
.addColumn("id", idColumn())
|
|
@@ -207,8 +288,31 @@ describe("Cursor utilities", () => {
|
|
|
207
288
|
});
|
|
208
289
|
});
|
|
209
290
|
|
|
291
|
+
it("should throw when record is missing index columns", () => {
|
|
292
|
+
const testSchema = schema("test", (s) =>
|
|
293
|
+
s.addTable("posts", (t) =>
|
|
294
|
+
t
|
|
295
|
+
.addColumn("id", idColumn())
|
|
296
|
+
.addColumn("createdAt", column("integer"))
|
|
297
|
+
.createIndex("created", ["createdAt"]),
|
|
298
|
+
),
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
const table = testSchema.tables.posts;
|
|
302
|
+
const record = { id: "post123" };
|
|
303
|
+
const indexColumns = table.indexes.created.columns;
|
|
304
|
+
|
|
305
|
+
expect(() =>
|
|
306
|
+
createCursorFromRecord(record, indexColumns, {
|
|
307
|
+
indexName: "created",
|
|
308
|
+
orderDirection: "asc",
|
|
309
|
+
pageSize: 10,
|
|
310
|
+
}),
|
|
311
|
+
).toThrow(/missing value/i);
|
|
312
|
+
});
|
|
313
|
+
|
|
210
314
|
it("should only include columns that are in the index", () => {
|
|
211
|
-
const testSchema = schema((s) =>
|
|
315
|
+
const testSchema = schema("test", (s) =>
|
|
212
316
|
s.addTable("users", (t) =>
|
|
213
317
|
t
|
|
214
318
|
.addColumn("id", idColumn())
|
|
@@ -235,7 +339,7 @@ describe("Cursor utilities", () => {
|
|
|
235
339
|
|
|
236
340
|
describe("serializeCursorValues", () => {
|
|
237
341
|
it("should serialize cursor values for database queries", () => {
|
|
238
|
-
const testSchema = schema((s) =>
|
|
342
|
+
const testSchema = schema("test", (s) =>
|
|
239
343
|
s.addTable("users", (t) =>
|
|
240
344
|
t.addColumn("id", idColumn()).addColumn("age", column("integer")),
|
|
241
345
|
),
|
|
@@ -260,8 +364,8 @@ describe("Cursor utilities", () => {
|
|
|
260
364
|
expect(serialized).toHaveProperty("age", 25);
|
|
261
365
|
});
|
|
262
366
|
|
|
263
|
-
it("should
|
|
264
|
-
const testSchema = schema((s) =>
|
|
367
|
+
it("should throw when cursor data is missing index values", () => {
|
|
368
|
+
const testSchema = schema("test", (s) =>
|
|
265
369
|
s.addTable("users", (t) =>
|
|
266
370
|
t.addColumn("id", idColumn()).addColumn("name", column("string")),
|
|
267
371
|
),
|
|
@@ -276,20 +380,15 @@ describe("Cursor utilities", () => {
|
|
|
276
380
|
});
|
|
277
381
|
|
|
278
382
|
const indexColumns = [table.columns.id, table.columns.name];
|
|
279
|
-
|
|
280
|
-
cursor,
|
|
281
|
-
|
|
282
|
-
new NodePostgresDriverConfig(),
|
|
283
|
-
);
|
|
284
|
-
|
|
285
|
-
expect(serialized).toHaveProperty("id", "user123");
|
|
286
|
-
expect(serialized).not.toHaveProperty("name");
|
|
383
|
+
expect(() =>
|
|
384
|
+
serializeCursorValues(cursor, indexColumns, new NodePostgresDriverConfig()),
|
|
385
|
+
).toThrow(/missing values/i);
|
|
287
386
|
});
|
|
288
387
|
});
|
|
289
388
|
|
|
290
389
|
describe("round-trip integration", () => {
|
|
291
390
|
it("should successfully round-trip cursor data through encode/decode", () => {
|
|
292
|
-
const testSchema = schema((s) =>
|
|
391
|
+
const testSchema = schema("test", (s) =>
|
|
293
392
|
s.addTable("posts", (t) =>
|
|
294
393
|
t
|
|
295
394
|
.addColumn("id", idColumn())
|
|
@@ -332,7 +431,7 @@ describe("Cursor utilities", () => {
|
|
|
332
431
|
});
|
|
333
432
|
|
|
334
433
|
it("should handle Date objects in cursors for PostgreSQL", () => {
|
|
335
|
-
const testSchema = schema((s) =>
|
|
434
|
+
const testSchema = schema("test", (s) =>
|
|
336
435
|
s.addTable("posts", (t) =>
|
|
337
436
|
t
|
|
338
437
|
.addColumn("id", idColumn())
|
|
@@ -379,7 +478,7 @@ describe("Cursor utilities", () => {
|
|
|
379
478
|
});
|
|
380
479
|
|
|
381
480
|
it("should handle Date objects in cursors for SQLite", () => {
|
|
382
|
-
const testSchema = schema((s) =>
|
|
481
|
+
const testSchema = schema("test", (s) =>
|
|
383
482
|
s.addTable("posts", (t) =>
|
|
384
483
|
t
|
|
385
484
|
.addColumn("id", idColumn())
|
|
@@ -421,7 +520,7 @@ describe("Cursor utilities", () => {
|
|
|
421
520
|
});
|
|
422
521
|
|
|
423
522
|
it("should handle Date objects in cursors for MySQL", () => {
|
|
424
|
-
const testSchema = schema((s) =>
|
|
523
|
+
const testSchema = schema("test", (s) =>
|
|
425
524
|
s.addTable("posts", (t) =>
|
|
426
525
|
t
|
|
427
526
|
.addColumn("id", idColumn())
|