@fragno-dev/db 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +202 -140
- package/CHANGELOG.md +35 -0
- package/README.md +30 -9
- package/dist/adapters/adapters.d.ts +23 -21
- package/dist/adapters/adapters.d.ts.map +1 -1
- package/dist/adapters/adapters.js.map +1 -1
- package/dist/adapters/generic-sql/driver-config.d.ts +16 -1
- package/dist/adapters/generic-sql/driver-config.d.ts.map +1 -1
- package/dist/adapters/generic-sql/driver-config.js +23 -1
- package/dist/adapters/generic-sql/driver-config.js.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-adapter.d.ts +27 -9
- package/dist/adapters/generic-sql/generic-sql-adapter.d.ts.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-adapter.js +55 -16
- package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -1
- package/dist/adapters/generic-sql/generic-sql-uow-executor.js +129 -3
- package/dist/adapters/generic-sql/generic-sql-uow-executor.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/mysql.js +24 -5
- package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/postgres.js +6 -5
- package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -1
- package/dist/adapters/generic-sql/migration/dialect/sqlite.js +21 -10
- package/dist/adapters/generic-sql/migration/dialect/sqlite.js.map +1 -1
- package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -1
- package/dist/adapters/generic-sql/migration/prepared-migrations.js +8 -8
- package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -1
- package/dist/adapters/generic-sql/migration/sql-generator.js +74 -51
- package/dist/adapters/generic-sql/migration/sql-generator.js.map +1 -1
- package/dist/adapters/generic-sql/query/create-sql-query-compiler.js +6 -5
- package/dist/adapters/generic-sql/query/create-sql-query-compiler.js.map +1 -1
- package/dist/adapters/generic-sql/query/cursor-utils.js +42 -4
- package/dist/adapters/generic-sql/query/cursor-utils.js.map +1 -1
- package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js +25 -17
- package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js.map +1 -1
- package/dist/adapters/generic-sql/query/select-builder.js +5 -3
- package/dist/adapters/generic-sql/query/select-builder.js.map +1 -1
- package/dist/adapters/generic-sql/query/sql-query-compiler.js +15 -12
- package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -1
- package/dist/adapters/generic-sql/query/where-builder.js +39 -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 +7 -3
- package/dist/adapters/generic-sql/uow-decoder.js.map +1 -1
- package/dist/adapters/generic-sql/uow-encoder.js +28 -8
- package/dist/adapters/generic-sql/uow-encoder.js.map +1 -1
- package/dist/adapters/in-memory/condition-evaluator.js +131 -0
- package/dist/adapters/in-memory/condition-evaluator.js.map +1 -0
- package/dist/adapters/in-memory/errors.d.ts +13 -0
- package/dist/adapters/in-memory/errors.d.ts.map +1 -0
- package/dist/adapters/in-memory/errors.js +23 -0
- package/dist/adapters/in-memory/errors.js.map +1 -0
- package/dist/adapters/in-memory/in-memory-adapter.d.ts +27 -0
- package/dist/adapters/in-memory/in-memory-adapter.d.ts.map +1 -0
- package/dist/adapters/in-memory/in-memory-adapter.js +176 -0
- package/dist/adapters/in-memory/in-memory-adapter.js.map +1 -0
- package/dist/adapters/in-memory/in-memory-uow.js +648 -0
- package/dist/adapters/in-memory/in-memory-uow.js.map +1 -0
- package/dist/adapters/in-memory/index.d.ts +4 -0
- package/dist/adapters/in-memory/index.js +4 -0
- package/dist/adapters/in-memory/options.d.ts +28 -0
- package/dist/adapters/in-memory/options.d.ts.map +1 -0
- package/dist/adapters/in-memory/options.js +61 -0
- package/dist/adapters/in-memory/options.js.map +1 -0
- package/dist/adapters/in-memory/reference-resolution.js +26 -0
- package/dist/adapters/in-memory/reference-resolution.js.map +1 -0
- package/dist/adapters/in-memory/sorted-array-index.js +129 -0
- package/dist/adapters/in-memory/sorted-array-index.js.map +1 -0
- package/dist/adapters/in-memory/store.js +71 -0
- package/dist/adapters/in-memory/store.js.map +1 -0
- package/dist/adapters/in-memory/value-comparison.js +28 -0
- package/dist/adapters/in-memory/value-comparison.js.map +1 -0
- package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -1
- package/dist/adapters/shared/uow-operation-compiler.js +11 -11
- package/dist/adapters/shared/uow-operation-compiler.js.map +1 -1
- package/dist/adapters/sql/index.d.ts +5 -0
- package/dist/adapters/sql/index.js +4 -0
- package/dist/db-fragment-definition-builder.d.ts +18 -7
- package/dist/db-fragment-definition-builder.d.ts.map +1 -1
- package/dist/db-fragment-definition-builder.js +116 -54
- package/dist/db-fragment-definition-builder.js.map +1 -1
- package/dist/dispatchers/cloudflare-do/index.d.ts +26 -0
- package/dist/dispatchers/cloudflare-do/index.d.ts.map +1 -0
- package/dist/dispatchers/cloudflare-do/index.js +63 -0
- package/dist/dispatchers/cloudflare-do/index.js.map +1 -0
- package/dist/dispatchers/node/index.d.ts +17 -0
- package/dist/dispatchers/node/index.d.ts.map +1 -0
- package/dist/dispatchers/node/index.js +59 -0
- package/dist/dispatchers/node/index.js.map +1 -0
- package/dist/fragments/internal-fragment.d.ts +79 -2
- package/dist/fragments/internal-fragment.d.ts.map +1 -1
- package/dist/fragments/internal-fragment.js +150 -32
- package/dist/fragments/internal-fragment.js.map +1 -1
- package/dist/fragments/internal-fragment.routes.js +29 -0
- package/dist/fragments/internal-fragment.routes.js.map +1 -0
- package/dist/fragments/internal-fragment.schema.d.ts +9 -0
- package/dist/fragments/internal-fragment.schema.d.ts.map +1 -0
- package/dist/fragments/internal-fragment.schema.js +22 -0
- package/dist/fragments/internal-fragment.schema.js.map +1 -0
- package/dist/hooks/durable-hooks-processor.d.ts +14 -0
- package/dist/hooks/durable-hooks-processor.d.ts.map +1 -0
- package/dist/hooks/durable-hooks-processor.js +32 -0
- package/dist/hooks/durable-hooks-processor.js.map +1 -0
- package/dist/hooks/hooks.d.ts +42 -1
- package/dist/hooks/hooks.d.ts.map +1 -1
- package/dist/hooks/hooks.js +72 -6
- package/dist/hooks/hooks.js.map +1 -1
- package/dist/migration-engine/auto-from-schema.js +14 -11
- package/dist/migration-engine/auto-from-schema.js.map +1 -1
- package/dist/migration-engine/generation-engine.d.ts +16 -10
- package/dist/migration-engine/generation-engine.d.ts.map +1 -1
- package/dist/migration-engine/generation-engine.js +72 -33
- package/dist/migration-engine/generation-engine.js.map +1 -1
- package/dist/migration-engine/shared.js.map +1 -1
- package/dist/mod.d.ts +15 -8
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +14 -8
- package/dist/mod.js.map +1 -1
- package/dist/naming/sql-naming.d.ts +19 -0
- package/dist/naming/sql-naming.d.ts.map +1 -0
- package/dist/naming/sql-naming.js +116 -0
- package/dist/naming/sql-naming.js.map +1 -0
- package/dist/node_modules/.pnpm/{rou3@0.7.10 → rou3@0.7.12}/node_modules/rou3/dist/index.js +8 -5
- package/dist/node_modules/.pnpm/rou3@0.7.12/node_modules/rou3/dist/index.js.map +1 -0
- package/dist/outbox/outbox-builder.js +156 -0
- package/dist/outbox/outbox-builder.js.map +1 -0
- package/dist/outbox/outbox.d.ts +52 -0
- package/dist/outbox/outbox.d.ts.map +1 -0
- package/dist/outbox/outbox.js +37 -0
- package/dist/outbox/outbox.js.map +1 -0
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js +3 -2
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +1 -1
- package/dist/packages/fragno/dist/api/fragment-instantiator.js +164 -20
- package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +1 -1
- package/dist/packages/fragno/dist/api/request-input-context.js +67 -0
- package/dist/packages/fragno/dist/api/request-input-context.js.map +1 -1
- package/dist/packages/fragno/dist/api/route.js +14 -1
- package/dist/packages/fragno/dist/api/route.js.map +1 -1
- package/dist/packages/fragno/dist/internal/trace-context.js +12 -0
- package/dist/packages/fragno/dist/internal/trace-context.js.map +1 -0
- package/dist/query/column-defaults.js +20 -4
- package/dist/query/column-defaults.js.map +1 -1
- package/dist/query/cursor.d.ts +3 -1
- package/dist/query/cursor.d.ts.map +1 -1
- package/dist/query/cursor.js +45 -14
- package/dist/query/cursor.js.map +1 -1
- package/dist/query/db-now.d.ts +8 -0
- package/dist/query/db-now.d.ts.map +1 -0
- package/dist/query/db-now.js +7 -0
- package/dist/query/db-now.js.map +1 -0
- package/dist/query/serialize/create-sql-serializer.js +3 -2
- package/dist/query/serialize/create-sql-serializer.js.map +1 -1
- package/dist/query/serialize/dialect/mysql-serializer.js +12 -6
- package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -1
- package/dist/query/serialize/dialect/postgres-serializer.js +25 -7
- package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -1
- package/dist/query/serialize/dialect/sqlite-serializer.js +55 -11
- package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -1
- package/dist/query/serialize/sql-serializer.js +2 -2
- package/dist/query/serialize/sql-serializer.js.map +1 -1
- package/dist/query/simple-query-interface.d.ts +6 -1
- package/dist/query/simple-query-interface.d.ts.map +1 -1
- package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work/execute-unit-of-work.js +11 -6
- 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 +50 -14
- package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work/unit-of-work.js +86 -5
- package/dist/query/unit-of-work/unit-of-work.js.map +1 -1
- package/dist/query/value-decoding.js +9 -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 +38 -14
- package/dist/schema/create.d.ts.map +1 -1
- package/dist/schema/create.js +81 -42
- 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 +3 -2
- package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -1
- package/dist/schema/type-conversion/dialect/sqlite.js +9 -0
- package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -1
- package/dist/schema/validator.d.ts +10 -0
- package/dist/schema/validator.d.ts.map +1 -0
- package/dist/schema/validator.js +123 -0
- package/dist/schema/validator.js.map +1 -0
- package/dist/schema-output/drizzle.d.ts +30 -0
- package/dist/schema-output/drizzle.d.ts.map +1 -0
- package/dist/{adapters/drizzle/generate.js → schema-output/drizzle.js} +82 -56
- package/dist/schema-output/drizzle.js.map +1 -0
- package/dist/schema-output/prisma.d.ts +17 -0
- package/dist/schema-output/prisma.d.ts.map +1 -0
- package/dist/schema-output/prisma.js +296 -0
- package/dist/schema-output/prisma.js.map +1 -0
- package/dist/util/default-database-adapter.js +61 -0
- package/dist/util/default-database-adapter.js.map +1 -0
- package/dist/with-database.d.ts +1 -1
- package/dist/with-database.d.ts.map +1 -1
- package/dist/with-database.js +12 -3
- package/dist/with-database.js.map +1 -1
- package/package.json +43 -28
- package/src/adapters/adapters.ts +30 -24
- package/src/adapters/drizzle/migrate-drizzle.test.ts +54 -33
- package/src/adapters/drizzle/migration-parity-drizzle-kit.test.ts +599 -0
- package/src/adapters/drizzle/test-utils.ts +12 -8
- package/src/adapters/generic-sql/driver-config.ts +38 -0
- package/src/adapters/generic-sql/generic-sql-adapter.test.ts +5 -5
- package/src/adapters/generic-sql/generic-sql-adapter.ts +110 -24
- package/src/adapters/generic-sql/generic-sql-uow-executor.test.ts +54 -0
- package/src/adapters/generic-sql/generic-sql-uow-executor.ts +231 -3
- package/src/adapters/generic-sql/migration/adapter-migration-parity.test.ts +118 -0
- package/src/adapters/generic-sql/migration/dialect/mysql.test.ts +26 -8
- package/src/adapters/generic-sql/migration/dialect/mysql.ts +46 -8
- package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +25 -7
- package/src/adapters/generic-sql/migration/dialect/postgres.ts +8 -4
- package/src/adapters/generic-sql/migration/dialect/sqlite.test.ts +47 -8
- package/src/adapters/generic-sql/migration/dialect/sqlite.ts +27 -12
- package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +128 -39
- package/src/adapters/generic-sql/migration/prepared-migrations.ts +15 -8
- package/src/adapters/generic-sql/migration/sql-generator.ts +142 -65
- package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +9 -6
- package/src/adapters/generic-sql/query/cursor-utils.test.ts +271 -0
- package/src/adapters/generic-sql/query/cursor-utils.ts +41 -6
- package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +27 -27
- package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +38 -24
- package/src/adapters/generic-sql/query/select-builder.test.ts +15 -11
- package/src/adapters/generic-sql/query/select-builder.ts +6 -2
- package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +52 -2
- package/src/adapters/generic-sql/query/sql-query-compiler.ts +50 -15
- package/src/adapters/generic-sql/query/where-builder.test.ts +91 -17
- package/src/adapters/generic-sql/query/where-builder.ts +90 -38
- package/src/adapters/{kysely/kysely-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-migrations.test.ts} +6 -6
- package/src/adapters/generic-sql/sql-adapter-pglite-pagination.test.ts +806 -0
- package/src/adapters/{drizzle/drizzle-adapter-pglite.test.ts → generic-sql/sql-adapter-pglite-queries.test.ts} +11 -11
- package/src/adapters/generic-sql/{test/generic-drizzle-adapter-sqlite3.test.ts → sql-adapter-sqlite3-driver.test.ts} +10 -10
- package/src/adapters/{drizzle/drizzle-adapter-sqlite3.test.ts → generic-sql/sql-adapter-sqlite3-uow.test.ts} +7 -7
- package/src/adapters/{kysely/kysely-adapter-sqlocal.test.ts → generic-sql/sql-adapter-sqlocal.test.ts} +6 -6
- package/src/adapters/generic-sql/sqlite-storage.ts +20 -0
- package/src/adapters/generic-sql/uow-decoder.test.ts +1 -1
- package/src/adapters/generic-sql/uow-decoder.ts +21 -3
- package/src/adapters/generic-sql/uow-encoder.test.ts +33 -2
- package/src/adapters/generic-sql/uow-encoder.ts +50 -11
- package/src/adapters/in-memory/condition-evaluator.test.ts +193 -0
- package/src/adapters/in-memory/condition-evaluator.ts +275 -0
- package/src/adapters/in-memory/errors.ts +20 -0
- package/src/adapters/in-memory/in-memory-adapter.ts +277 -0
- package/src/adapters/in-memory/in-memory-uow.mutations.test.ts +296 -0
- package/src/adapters/in-memory/in-memory-uow.retrieval.test.ts +100 -0
- package/src/adapters/in-memory/in-memory-uow.ts +1348 -0
- package/src/adapters/in-memory/index.ts +3 -0
- package/src/adapters/in-memory/options.test.ts +41 -0
- package/src/adapters/in-memory/options.ts +87 -0
- package/src/adapters/in-memory/reference-resolution.test.ts +50 -0
- package/src/adapters/in-memory/reference-resolution.ts +67 -0
- package/src/adapters/in-memory/sorted-array-index.test.ts +123 -0
- package/src/adapters/in-memory/sorted-array-index.ts +228 -0
- package/src/adapters/in-memory/store.test.ts +68 -0
- package/src/adapters/in-memory/store.ts +145 -0
- package/src/adapters/in-memory/value-comparison.ts +53 -0
- package/src/adapters/in-memory/value-normalization.test.ts +57 -0
- package/src/adapters/prisma/prisma-adapter-sqlite3.test.ts +1163 -0
- package/src/adapters/shared/from-unit-of-work-compiler.ts +3 -1
- package/src/adapters/shared/uow-operation-compiler.ts +26 -16
- package/src/adapters/sql/index.ts +12 -0
- package/src/db-fragment-definition-builder.test.ts +30 -12
- package/src/db-fragment-definition-builder.ts +142 -73
- package/src/db-fragment-instantiator.test.ts +105 -13
- package/src/db-fragment-integration.test.ts +9 -7
- package/src/dispatchers/cloudflare-do/index.test.ts +73 -0
- package/src/dispatchers/cloudflare-do/index.ts +104 -0
- package/src/dispatchers/node/index.test.ts +91 -0
- package/src/dispatchers/node/index.ts +87 -0
- package/src/fragments/internal-fragment.routes.ts +42 -0
- package/src/fragments/internal-fragment.schema.ts +51 -0
- package/src/fragments/internal-fragment.test.ts +458 -8
- package/src/fragments/internal-fragment.ts +322 -63
- package/src/hooks/durable-hooks-processor.test.ts +117 -0
- package/src/hooks/durable-hooks-processor.ts +67 -0
- package/src/hooks/hooks.test.ts +165 -5
- package/src/hooks/hooks.ts +197 -9
- package/src/migration-engine/auto-from-schema.test.ts +14 -14
- package/src/migration-engine/auto-from-schema.ts +5 -2
- package/src/migration-engine/create.test.ts +2 -2
- package/src/migration-engine/generation-engine.test.ts +229 -104
- package/src/migration-engine/generation-engine.ts +94 -64
- package/src/migration-engine/shared.ts +1 -0
- package/src/mod.ts +64 -26
- package/src/naming/sql-naming.ts +180 -0
- package/src/outbox/outbox-builder.ts +241 -0
- package/src/outbox/outbox.test.ts +253 -0
- package/src/outbox/outbox.ts +137 -0
- package/src/query/column-defaults.ts +41 -3
- package/src/query/condition-builder.test.ts +3 -3
- package/src/query/cursor.test.ts +116 -18
- package/src/query/cursor.ts +75 -26
- package/src/query/db-now.ts +6 -0
- package/src/query/query-type.test.ts +2 -2
- package/src/query/serialize/create-sql-serializer.ts +7 -2
- package/src/query/serialize/dialect/mysql-serializer.ts +12 -4
- package/src/query/serialize/dialect/postgres-serializer.ts +34 -4
- package/src/query/serialize/dialect/sqlite-serializer.test.ts +51 -1
- package/src/query/serialize/dialect/sqlite-serializer.ts +92 -9
- package/src/query/serialize/sql-serializer.ts +4 -4
- package/src/query/simple-query-interface.ts +5 -0
- package/src/query/unit-of-work/execute-unit-of-work.test.ts +25 -1
- package/src/query/unit-of-work/execute-unit-of-work.ts +25 -8
- package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +12 -12
- package/src/query/unit-of-work/unit-of-work-types.test.ts +1 -1
- package/src/query/unit-of-work/unit-of-work.test.ts +168 -37
- package/src/query/unit-of-work/unit-of-work.ts +203 -18
- package/src/query/value-decoding.test.ts +13 -2
- package/src/query/value-decoding.ts +17 -4
- package/src/query/value-encoding.test.ts +85 -2
- package/src/query/value-encoding.ts +56 -6
- package/src/schema/create.test.ts +129 -42
- package/src/schema/create.ts +185 -47
- package/src/schema/generate-id.test.ts +2 -2
- package/src/schema/generate-id.ts +2 -2
- package/src/schema/serialize.test.ts +14 -2
- package/src/schema/type-conversion/create-sql-type-mapper.ts +7 -2
- package/src/schema/type-conversion/dialect/sqlite.ts +18 -0
- package/src/schema/type-conversion/type-mapping.test.ts +25 -1
- package/src/schema/validator.test.ts +197 -0
- package/src/schema/validator.ts +231 -0
- package/src/{adapters/drizzle/generate.test.ts → schema-output/drizzle.test.ts} +179 -129
- package/src/{adapters/drizzle/generate.ts → schema-output/drizzle.ts} +143 -93
- package/src/schema-output/prisma.test.ts +536 -0
- package/src/schema-output/prisma.ts +573 -0
- package/src/util/default-database-adapter.ts +106 -0
- package/src/with-database.ts +22 -3
- package/tsdown.config.ts +6 -4
- package/dist/adapters/drizzle/drizzle-adapter.d.ts +0 -20
- package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +0 -1
- package/dist/adapters/drizzle/drizzle-adapter.js +0 -27
- package/dist/adapters/drizzle/drizzle-adapter.js.map +0 -1
- package/dist/adapters/drizzle/generate.d.ts +0 -30
- package/dist/adapters/drizzle/generate.d.ts.map +0 -1
- package/dist/adapters/drizzle/generate.js.map +0 -1
- package/dist/adapters/kysely/kysely-adapter.d.ts +0 -19
- package/dist/adapters/kysely/kysely-adapter.d.ts.map +0 -1
- package/dist/adapters/kysely/kysely-adapter.js +0 -17
- package/dist/adapters/kysely/kysely-adapter.js.map +0 -1
- package/dist/adapters/shared/table-name-mapper.d.ts +0 -12
- package/dist/adapters/shared/table-name-mapper.d.ts.map +0 -1
- package/dist/adapters/shared/table-name-mapper.js +0 -43
- package/dist/adapters/shared/table-name-mapper.js.map +0 -1
- package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js.map +0 -1
- package/dist/schema-generator/schema-generator.d.ts +0 -15
- package/dist/schema-generator/schema-generator.d.ts.map +0 -1
- package/src/adapters/drizzle/drizzle-adapter.ts +0 -39
- package/src/adapters/kysely/kysely-adapter.ts +0 -27
- package/src/adapters/shared/table-name-mapper.ts +0 -50
- package/src/schema-generator/schema-generator.ts +0 -12
|
@@ -91,6 +91,72 @@ var RequestInputContext = class RequestInputContext$1 {
|
|
|
91
91
|
return this.#body;
|
|
92
92
|
}
|
|
93
93
|
/**
|
|
94
|
+
* Access the request body as FormData.
|
|
95
|
+
*
|
|
96
|
+
* Use this method when handling file uploads or multipart form submissions.
|
|
97
|
+
* The request must have been sent with Content-Type: multipart/form-data.
|
|
98
|
+
*
|
|
99
|
+
* @throws Error if the request body is not FormData
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* defineRoute({
|
|
104
|
+
* method: "POST",
|
|
105
|
+
* path: "/upload",
|
|
106
|
+
* async handler(ctx, res) {
|
|
107
|
+
* const formData = ctx.formData();
|
|
108
|
+
* const file = formData.get("file") as File;
|
|
109
|
+
* const description = formData.get("description") as string;
|
|
110
|
+
* // ... process file
|
|
111
|
+
* }
|
|
112
|
+
* });
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
formData() {
|
|
116
|
+
if (!(this.#parsedBody instanceof FormData)) throw new Error("Request body is not FormData. Ensure the request was sent with Content-Type: multipart/form-data.");
|
|
117
|
+
return this.#parsedBody;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Check if the request body is FormData.
|
|
121
|
+
*
|
|
122
|
+
* Useful for routes that accept both JSON and FormData payloads.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```typescript
|
|
126
|
+
* defineRoute({
|
|
127
|
+
* method: "POST",
|
|
128
|
+
* path: "/upload",
|
|
129
|
+
* async handler(ctx, res) {
|
|
130
|
+
* if (ctx.isFormData()) {
|
|
131
|
+
* const formData = ctx.formData();
|
|
132
|
+
* // handle file upload
|
|
133
|
+
* } else {
|
|
134
|
+
* const json = await ctx.input.valid();
|
|
135
|
+
* // handle JSON payload
|
|
136
|
+
* }
|
|
137
|
+
* }
|
|
138
|
+
* });
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
isFormData() {
|
|
142
|
+
return this.#parsedBody instanceof FormData;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Access the request body as a ReadableStream (application/octet-stream).
|
|
146
|
+
*
|
|
147
|
+
* @throws Error if the request body is not a ReadableStream
|
|
148
|
+
*/
|
|
149
|
+
bodyStream() {
|
|
150
|
+
if (!(this.#parsedBody instanceof ReadableStream)) throw new Error("Request body is not a ReadableStream. Ensure the request was sent with Content-Type: application/octet-stream.");
|
|
151
|
+
return this.#parsedBody;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Check if the request body is a ReadableStream.
|
|
155
|
+
*/
|
|
156
|
+
isBodyStream() {
|
|
157
|
+
return this.#parsedBody instanceof ReadableStream;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
94
160
|
* Input validation context (only if inputSchema is defined)
|
|
95
161
|
* @remarks `InputContext`
|
|
96
162
|
*/
|
|
@@ -107,6 +173,7 @@ var RequestInputContext = class RequestInputContext$1 {
|
|
|
107
173
|
async #validateInput() {
|
|
108
174
|
if (!this.#inputSchema) throw new Error("No input schema defined for this route");
|
|
109
175
|
if (this.#parsedBody instanceof FormData || this.#parsedBody instanceof Blob) throw new Error("Schema validation is only supported for JSON data, not FormData or Blob");
|
|
176
|
+
if (this.#parsedBody instanceof ReadableStream) throw new Error("Schema validation is only supported for JSON data, not FormData, Blob, or ReadableStream");
|
|
110
177
|
const result = await this.#inputSchema["~standard"].validate(this.#parsedBody);
|
|
111
178
|
if (result.issues) throw new FragnoApiValidationError("Validation failed", result.issues);
|
|
112
179
|
return result.value;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-input-context.js","names":["RequestInputContext","#path","#method","#pathParams","#searchParams","#headers","#body","#parsedBody","#inputSchema","#shouldValidateInput","#validateInput"],"sources":["../../../../../../fragno/dist/api/request-input-context.js"],"sourcesContent":["import { FragnoApiValidationError } from \"./error.js\";\n\n//#region src/api/request-input-context.ts\nvar RequestInputContext = class RequestInputContext {\n\t#path;\n\t#method;\n\t#pathParams;\n\t#searchParams;\n\t#headers;\n\t#body;\n\t#parsedBody;\n\t#inputSchema;\n\t#shouldValidateInput;\n\tconstructor(config) {\n\t\tthis.#path = config.path;\n\t\tthis.#method = config.method;\n\t\tthis.#pathParams = config.pathParams;\n\t\tthis.#searchParams = config.searchParams;\n\t\tthis.#headers = config.headers;\n\t\tthis.#body = config.rawBody;\n\t\tthis.#parsedBody = config.parsedBody;\n\t\tthis.#inputSchema = config.inputSchema;\n\t\tthis.#shouldValidateInput = config.shouldValidateInput ?? true;\n\t}\n\t/**\n\t* Create a RequestContext from a Request object for server-side handling\n\t*/\n\tstatic async fromRequest(config) {\n\t\treturn new RequestInputContext({\n\t\t\tmethod: config.method,\n\t\t\tpath: config.path,\n\t\t\tpathParams: config.state.pathParams,\n\t\t\tsearchParams: config.state.searchParams,\n\t\t\theaders: config.state.headers,\n\t\t\tparsedBody: config.state.body,\n\t\t\trawBody: config.rawBody,\n\t\t\tinputSchema: config.inputSchema,\n\t\t\tshouldValidateInput: config.shouldValidateInput\n\t\t});\n\t}\n\t/**\n\t* Create a RequestContext for server-side rendering contexts (no Request object)\n\t*/\n\tstatic fromSSRContext(config) {\n\t\treturn new RequestInputContext({\n\t\t\tmethod: config.method,\n\t\t\tpath: config.path,\n\t\t\tpathParams: config.pathParams,\n\t\t\tsearchParams: config.searchParams ?? new URLSearchParams(),\n\t\t\theaders: config.headers ?? new Headers(),\n\t\t\tparsedBody: \"body\" in config ? config.body : void 0,\n\t\t\tinputSchema: \"inputSchema\" in config ? config.inputSchema : void 0,\n\t\t\tshouldValidateInput: false\n\t\t});\n\t}\n\t/**\n\t* The HTTP method as string (e.g., `GET`, `POST`)\n\t*/\n\tget method() {\n\t\treturn this.#method;\n\t}\n\t/**\n\t* The matched route path (e.g., `/users/:id`)\n\t* @remarks `string`\n\t*/\n\tget path() {\n\t\treturn this.#path;\n\t}\n\t/**\n\t* Extracted path parameters as object (e.g., `{ id: '123' }`)\n\t* @remarks `Record<string, string>`\n\t*/\n\tget pathParams() {\n\t\treturn this.#pathParams;\n\t}\n\t/**\n\t* [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) object for query parameters\n\t* @remarks `URLSearchParams`\n\t*/\n\tget query() {\n\t\treturn this.#searchParams;\n\t}\n\t/**\n\t* [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) object for request headers\n\t* @remarks `Headers`\n\t*/\n\tget headers() {\n\t\treturn this.#headers;\n\t}\n\tget rawBody() {\n\t\treturn this.#body;\n\t}\n\t/**\n\t* Input validation context (only if inputSchema is defined)\n\t* @remarks `InputContext`\n\t*/\n\tget input() {\n\t\tif (!this.#inputSchema) return;\n\t\treturn {\n\t\t\tschema: this.#inputSchema,\n\t\t\tvalid: async () => {\n\t\t\t\tif (!this.#shouldValidateInput) return this.#parsedBody;\n\t\t\t\treturn this.#validateInput();\n\t\t\t}\n\t\t};\n\t}\n\tasync #validateInput() {\n\t\tif (!this.#inputSchema) throw new Error(\"No input schema defined for this route\");\n\t\tif (this.#parsedBody instanceof FormData || this.#parsedBody instanceof Blob) throw new Error(\"Schema validation is only supported for JSON data, not FormData or Blob\");\n\t\tconst result = await this.#inputSchema[\"~standard\"].validate(this.#parsedBody);\n\t\tif (result.issues) throw new FragnoApiValidationError(\"Validation failed\", result.issues);\n\t\treturn result.value;\n\t}\n};\n\n//#endregion\nexport { RequestInputContext };\n//# sourceMappingURL=request-input-context.js.map"],"mappings":";;;AAGA,IAAI,sBAAsB,MAAMA,sBAAoB;CACnD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,YAAY,QAAQ;AACnB,QAAKC,OAAQ,OAAO;AACpB,QAAKC,SAAU,OAAO;AACtB,QAAKC,aAAc,OAAO;AAC1B,QAAKC,eAAgB,OAAO;AAC5B,QAAKC,UAAW,OAAO;AACvB,QAAKC,OAAQ,OAAO;AACpB,QAAKC,aAAc,OAAO;AAC1B,QAAKC,cAAe,OAAO;AAC3B,QAAKC,sBAAuB,OAAO,uBAAuB;;;;;CAK3D,aAAa,YAAY,QAAQ;AAChC,SAAO,IAAIT,sBAAoB;GAC9B,QAAQ,OAAO;GACf,MAAM,OAAO;GACb,YAAY,OAAO,MAAM;GACzB,cAAc,OAAO,MAAM;GAC3B,SAAS,OAAO,MAAM;GACtB,YAAY,OAAO,MAAM;GACzB,SAAS,OAAO;GAChB,aAAa,OAAO;GACpB,qBAAqB,OAAO;GAC5B,CAAC;;;;;CAKH,OAAO,eAAe,QAAQ;AAC7B,SAAO,IAAIA,sBAAoB;GAC9B,QAAQ,OAAO;GACf,MAAM,OAAO;GACb,YAAY,OAAO;GACnB,cAAc,OAAO,gBAAgB,IAAI,iBAAiB;GAC1D,SAAS,OAAO,WAAW,IAAI,SAAS;GACxC,YAAY,UAAU,SAAS,OAAO,OAAO,KAAK;GAClD,aAAa,iBAAiB,SAAS,OAAO,cAAc,KAAK;GACjE,qBAAqB;GACrB,CAAC;;;;;CAKH,IAAI,SAAS;AACZ,SAAO,MAAKE;;;;;;CAMb,IAAI,OAAO;AACV,SAAO,MAAKD;;;;;;CAMb,IAAI,aAAa;AAChB,SAAO,MAAKE;;;;;;CAMb,IAAI,QAAQ;AACX,SAAO,MAAKC;;;;;;CAMb,IAAI,UAAU;AACb,SAAO,MAAKC;;CAEb,IAAI,UAAU;AACb,SAAO,MAAKC;;;;;;
|
|
1
|
+
{"version":3,"file":"request-input-context.js","names":["RequestInputContext","#path","#method","#pathParams","#searchParams","#headers","#body","#parsedBody","#inputSchema","#shouldValidateInput","#validateInput"],"sources":["../../../../../../fragno/dist/api/request-input-context.js"],"sourcesContent":["import { FragnoApiValidationError } from \"./error.js\";\n\n//#region src/api/request-input-context.ts\nvar RequestInputContext = class RequestInputContext {\n\t#path;\n\t#method;\n\t#pathParams;\n\t#searchParams;\n\t#headers;\n\t#body;\n\t#parsedBody;\n\t#inputSchema;\n\t#shouldValidateInput;\n\tconstructor(config) {\n\t\tthis.#path = config.path;\n\t\tthis.#method = config.method;\n\t\tthis.#pathParams = config.pathParams;\n\t\tthis.#searchParams = config.searchParams;\n\t\tthis.#headers = config.headers;\n\t\tthis.#body = config.rawBody;\n\t\tthis.#parsedBody = config.parsedBody;\n\t\tthis.#inputSchema = config.inputSchema;\n\t\tthis.#shouldValidateInput = config.shouldValidateInput ?? true;\n\t}\n\t/**\n\t* Create a RequestContext from a Request object for server-side handling\n\t*/\n\tstatic async fromRequest(config) {\n\t\treturn new RequestInputContext({\n\t\t\tmethod: config.method,\n\t\t\tpath: config.path,\n\t\t\tpathParams: config.state.pathParams,\n\t\t\tsearchParams: config.state.searchParams,\n\t\t\theaders: config.state.headers,\n\t\t\tparsedBody: config.state.body,\n\t\t\trawBody: config.rawBody,\n\t\t\tinputSchema: config.inputSchema,\n\t\t\tshouldValidateInput: config.shouldValidateInput\n\t\t});\n\t}\n\t/**\n\t* Create a RequestContext for server-side rendering contexts (no Request object)\n\t*/\n\tstatic fromSSRContext(config) {\n\t\treturn new RequestInputContext({\n\t\t\tmethod: config.method,\n\t\t\tpath: config.path,\n\t\t\tpathParams: config.pathParams,\n\t\t\tsearchParams: config.searchParams ?? new URLSearchParams(),\n\t\t\theaders: config.headers ?? new Headers(),\n\t\t\tparsedBody: \"body\" in config ? config.body : void 0,\n\t\t\tinputSchema: \"inputSchema\" in config ? config.inputSchema : void 0,\n\t\t\tshouldValidateInput: false\n\t\t});\n\t}\n\t/**\n\t* The HTTP method as string (e.g., `GET`, `POST`)\n\t*/\n\tget method() {\n\t\treturn this.#method;\n\t}\n\t/**\n\t* The matched route path (e.g., `/users/:id`)\n\t* @remarks `string`\n\t*/\n\tget path() {\n\t\treturn this.#path;\n\t}\n\t/**\n\t* Extracted path parameters as object (e.g., `{ id: '123' }`)\n\t* @remarks `Record<string, string>`\n\t*/\n\tget pathParams() {\n\t\treturn this.#pathParams;\n\t}\n\t/**\n\t* [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) object for query parameters\n\t* @remarks `URLSearchParams`\n\t*/\n\tget query() {\n\t\treturn this.#searchParams;\n\t}\n\t/**\n\t* [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) object for request headers\n\t* @remarks `Headers`\n\t*/\n\tget headers() {\n\t\treturn this.#headers;\n\t}\n\tget rawBody() {\n\t\treturn this.#body;\n\t}\n\t/**\n\t* Access the request body as FormData.\n\t*\n\t* Use this method when handling file uploads or multipart form submissions.\n\t* The request must have been sent with Content-Type: multipart/form-data.\n\t*\n\t* @throws Error if the request body is not FormData\n\t*\n\t* @example\n\t* ```typescript\n\t* defineRoute({\n\t* method: \"POST\",\n\t* path: \"/upload\",\n\t* async handler(ctx, res) {\n\t* const formData = ctx.formData();\n\t* const file = formData.get(\"file\") as File;\n\t* const description = formData.get(\"description\") as string;\n\t* // ... process file\n\t* }\n\t* });\n\t* ```\n\t*/\n\tformData() {\n\t\tif (!(this.#parsedBody instanceof FormData)) throw new Error(\"Request body is not FormData. Ensure the request was sent with Content-Type: multipart/form-data.\");\n\t\treturn this.#parsedBody;\n\t}\n\t/**\n\t* Check if the request body is FormData.\n\t*\n\t* Useful for routes that accept both JSON and FormData payloads.\n\t*\n\t* @example\n\t* ```typescript\n\t* defineRoute({\n\t* method: \"POST\",\n\t* path: \"/upload\",\n\t* async handler(ctx, res) {\n\t* if (ctx.isFormData()) {\n\t* const formData = ctx.formData();\n\t* // handle file upload\n\t* } else {\n\t* const json = await ctx.input.valid();\n\t* // handle JSON payload\n\t* }\n\t* }\n\t* });\n\t* ```\n\t*/\n\tisFormData() {\n\t\treturn this.#parsedBody instanceof FormData;\n\t}\n\t/**\n\t* Access the request body as a ReadableStream (application/octet-stream).\n\t*\n\t* @throws Error if the request body is not a ReadableStream\n\t*/\n\tbodyStream() {\n\t\tif (!(this.#parsedBody instanceof ReadableStream)) throw new Error(\"Request body is not a ReadableStream. Ensure the request was sent with Content-Type: application/octet-stream.\");\n\t\treturn this.#parsedBody;\n\t}\n\t/**\n\t* Check if the request body is a ReadableStream.\n\t*/\n\tisBodyStream() {\n\t\treturn this.#parsedBody instanceof ReadableStream;\n\t}\n\t/**\n\t* Input validation context (only if inputSchema is defined)\n\t* @remarks `InputContext`\n\t*/\n\tget input() {\n\t\tif (!this.#inputSchema) return;\n\t\treturn {\n\t\t\tschema: this.#inputSchema,\n\t\t\tvalid: async () => {\n\t\t\t\tif (!this.#shouldValidateInput) return this.#parsedBody;\n\t\t\t\treturn this.#validateInput();\n\t\t\t}\n\t\t};\n\t}\n\tasync #validateInput() {\n\t\tif (!this.#inputSchema) throw new Error(\"No input schema defined for this route\");\n\t\tif (this.#parsedBody instanceof FormData || this.#parsedBody instanceof Blob) throw new Error(\"Schema validation is only supported for JSON data, not FormData or Blob\");\n\t\tif (this.#parsedBody instanceof ReadableStream) throw new Error(\"Schema validation is only supported for JSON data, not FormData, Blob, or ReadableStream\");\n\t\tconst result = await this.#inputSchema[\"~standard\"].validate(this.#parsedBody);\n\t\tif (result.issues) throw new FragnoApiValidationError(\"Validation failed\", result.issues);\n\t\treturn result.value;\n\t}\n};\n\n//#endregion\nexport { RequestInputContext };\n//# sourceMappingURL=request-input-context.js.map"],"mappings":";;;AAGA,IAAI,sBAAsB,MAAMA,sBAAoB;CACnD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,YAAY,QAAQ;AACnB,QAAKC,OAAQ,OAAO;AACpB,QAAKC,SAAU,OAAO;AACtB,QAAKC,aAAc,OAAO;AAC1B,QAAKC,eAAgB,OAAO;AAC5B,QAAKC,UAAW,OAAO;AACvB,QAAKC,OAAQ,OAAO;AACpB,QAAKC,aAAc,OAAO;AAC1B,QAAKC,cAAe,OAAO;AAC3B,QAAKC,sBAAuB,OAAO,uBAAuB;;;;;CAK3D,aAAa,YAAY,QAAQ;AAChC,SAAO,IAAIT,sBAAoB;GAC9B,QAAQ,OAAO;GACf,MAAM,OAAO;GACb,YAAY,OAAO,MAAM;GACzB,cAAc,OAAO,MAAM;GAC3B,SAAS,OAAO,MAAM;GACtB,YAAY,OAAO,MAAM;GACzB,SAAS,OAAO;GAChB,aAAa,OAAO;GACpB,qBAAqB,OAAO;GAC5B,CAAC;;;;;CAKH,OAAO,eAAe,QAAQ;AAC7B,SAAO,IAAIA,sBAAoB;GAC9B,QAAQ,OAAO;GACf,MAAM,OAAO;GACb,YAAY,OAAO;GACnB,cAAc,OAAO,gBAAgB,IAAI,iBAAiB;GAC1D,SAAS,OAAO,WAAW,IAAI,SAAS;GACxC,YAAY,UAAU,SAAS,OAAO,OAAO,KAAK;GAClD,aAAa,iBAAiB,SAAS,OAAO,cAAc,KAAK;GACjE,qBAAqB;GACrB,CAAC;;;;;CAKH,IAAI,SAAS;AACZ,SAAO,MAAKE;;;;;;CAMb,IAAI,OAAO;AACV,SAAO,MAAKD;;;;;;CAMb,IAAI,aAAa;AAChB,SAAO,MAAKE;;;;;;CAMb,IAAI,QAAQ;AACX,SAAO,MAAKC;;;;;;CAMb,IAAI,UAAU;AACb,SAAO,MAAKC;;CAEb,IAAI,UAAU;AACb,SAAO,MAAKC;;;;;;;;;;;;;;;;;;;;;;;;CAwBb,WAAW;AACV,MAAI,EAAE,MAAKC,sBAAuB,UAAW,OAAM,IAAI,MAAM,oGAAoG;AACjK,SAAO,MAAKA;;;;;;;;;;;;;;;;;;;;;;;;CAwBb,aAAa;AACZ,SAAO,MAAKA,sBAAuB;;;;;;;CAOpC,aAAa;AACZ,MAAI,EAAE,MAAKA,sBAAuB,gBAAiB,OAAM,IAAI,MAAM,iHAAiH;AACpL,SAAO,MAAKA;;;;;CAKb,eAAe;AACd,SAAO,MAAKA,sBAAuB;;;;;;CAMpC,IAAI,QAAQ;AACX,MAAI,CAAC,MAAKC,YAAc;AACxB,SAAO;GACN,QAAQ,MAAKA;GACb,OAAO,YAAY;AAClB,QAAI,CAAC,MAAKC,oBAAsB,QAAO,MAAKF;AAC5C,WAAO,MAAKG,eAAgB;;GAE7B;;CAEF,OAAMA,gBAAiB;AACtB,MAAI,CAAC,MAAKF,YAAc,OAAM,IAAI,MAAM,yCAAyC;AACjF,MAAI,MAAKD,sBAAuB,YAAY,MAAKA,sBAAuB,KAAM,OAAM,IAAI,MAAM,0EAA0E;AACxK,MAAI,MAAKA,sBAAuB,eAAgB,OAAM,IAAI,MAAM,2FAA2F;EAC3J,MAAM,SAAS,MAAM,MAAKC,YAAa,aAAa,SAAS,MAAKD,WAAY;AAC9E,MAAI,OAAO,OAAQ,OAAM,IAAI,yBAAyB,qBAAqB,OAAO,OAAO;AACzF,SAAO,OAAO"}
|
|
@@ -11,7 +11,20 @@ function resolveRouteFactories(context, routesOrFactories) {
|
|
|
11
11
|
} else routes.push(item);
|
|
12
12
|
return routes;
|
|
13
13
|
}
|
|
14
|
+
function defineRoute(config) {
|
|
15
|
+
return config;
|
|
16
|
+
}
|
|
17
|
+
function defineRoutes(_definition) {
|
|
18
|
+
return { create: (fn) => {
|
|
19
|
+
return (ctx) => {
|
|
20
|
+
return fn({
|
|
21
|
+
...ctx,
|
|
22
|
+
defineRoute
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
} };
|
|
26
|
+
}
|
|
14
27
|
|
|
15
28
|
//#endregion
|
|
16
|
-
export { resolveRouteFactories };
|
|
29
|
+
export { defineRoutes, resolveRouteFactories };
|
|
17
30
|
//# sourceMappingURL=route.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.js","names":[],"sources":["../../../../../../fragno/dist/api/route.js"],"sourcesContent":["//#region src/api/route.ts\n/**\n* Helper to resolve route factories into routes\n* @internal\n*/\nfunction resolveRouteFactories(context, routesOrFactories) {\n\tconst routes = [];\n\tfor (const item of routesOrFactories) if (typeof item === \"function\") {\n\t\tconst factoryRoutes = item(context);\n\t\troutes.push(...factoryRoutes);\n\t} else routes.push(item);\n\treturn routes;\n}\nfunction defineRoute(config) {\n\treturn config;\n}\nfunction defineRoutes(_definition) {\n\treturn { create: (fn) => {\n\t\treturn (ctx) => {\n\t\t\treturn fn({\n\t\t\t\t...ctx,\n\t\t\t\tdefineRoute\n\t\t\t});\n\t\t};\n\t} };\n}\n\n//#endregion\nexport { defineRoute, defineRoutes, resolveRouteFactories };\n//# sourceMappingURL=route.js.map"],"mappings":";;;;;AAKA,SAAS,sBAAsB,SAAS,mBAAmB;CAC1D,MAAM,SAAS,EAAE;AACjB,MAAK,MAAM,QAAQ,kBAAmB,KAAI,OAAO,SAAS,YAAY;EACrE,MAAM,gBAAgB,KAAK,QAAQ;AACnC,SAAO,KAAK,GAAG,cAAc;OACvB,QAAO,KAAK,KAAK;AACxB,QAAO"}
|
|
1
|
+
{"version":3,"file":"route.js","names":[],"sources":["../../../../../../fragno/dist/api/route.js"],"sourcesContent":["//#region src/api/route.ts\n/**\n* Helper to resolve route factories into routes\n* @internal\n*/\nfunction resolveRouteFactories(context, routesOrFactories) {\n\tconst routes = [];\n\tfor (const item of routesOrFactories) if (typeof item === \"function\") {\n\t\tconst factoryRoutes = item(context);\n\t\troutes.push(...factoryRoutes);\n\t} else routes.push(item);\n\treturn routes;\n}\nfunction defineRoute(config) {\n\treturn config;\n}\nfunction defineRoutes(_definition) {\n\treturn { create: (fn) => {\n\t\treturn (ctx) => {\n\t\t\treturn fn({\n\t\t\t\t...ctx,\n\t\t\t\tdefineRoute\n\t\t\t});\n\t\t};\n\t} };\n}\n\n//#endregion\nexport { defineRoute, defineRoutes, resolveRouteFactories };\n//# sourceMappingURL=route.js.map"],"mappings":";;;;;AAKA,SAAS,sBAAsB,SAAS,mBAAmB;CAC1D,MAAM,SAAS,EAAE;AACjB,MAAK,MAAM,QAAQ,kBAAmB,KAAI,OAAO,SAAS,YAAY;EACrE,MAAM,gBAAgB,KAAK,QAAQ;AACnC,SAAO,KAAK,GAAG,cAAc;OACvB,QAAO,KAAK,KAAK;AACxB,QAAO;;AAER,SAAS,YAAY,QAAQ;AAC5B,QAAO;;AAER,SAAS,aAAa,aAAa;AAClC,QAAO,EAAE,SAAS,OAAO;AACxB,UAAQ,QAAQ;AACf,UAAO,GAAG;IACT,GAAG;IACH;IACA,CAAC;;IAED"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
|
|
3
|
+
//#region ../fragno/dist/internal/trace-context.js
|
|
4
|
+
const traceStorage = new AsyncLocalStorage();
|
|
5
|
+
const recordTraceEvent = (event) => {
|
|
6
|
+
const recorder = traceStorage.getStore();
|
|
7
|
+
if (recorder) recorder(event);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
export { recordTraceEvent };
|
|
12
|
+
//# sourceMappingURL=trace-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-context.js","names":[],"sources":["../../../../../../fragno/dist/internal/trace-context.js"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\n\n//#region src/internal/trace-context.ts\nconst traceStorage = new AsyncLocalStorage();\nconst runWithTraceRecorder = (recorder, callback) => traceStorage.run(recorder, callback);\nconst getTraceRecorder = () => traceStorage.getStore();\nconst recordTraceEvent = (event) => {\n\tconst recorder = traceStorage.getStore();\n\tif (recorder) recorder(event);\n};\n\n//#endregion\nexport { getTraceRecorder, recordTraceEvent, runWithTraceRecorder };\n//# sourceMappingURL=trace-context.js.map"],"mappings":";;;AAGA,MAAM,eAAe,IAAI,mBAAmB;AAG5C,MAAM,oBAAoB,UAAU;CACnC,MAAM,WAAW,aAAa,UAAU;AACxC,KAAI,SAAU,UAAS,MAAM"}
|
|
@@ -12,16 +12,32 @@ import { createId } from "../id.js";
|
|
|
12
12
|
*
|
|
13
13
|
* @internal
|
|
14
14
|
*/
|
|
15
|
-
function generateRuntimeDefault(column) {
|
|
15
|
+
function generateRuntimeDefault(column, context = {}) {
|
|
16
16
|
if (!column.default) return;
|
|
17
17
|
if ("value" in column.default) return;
|
|
18
18
|
if ("dbSpecial" in column.default) return;
|
|
19
19
|
const runtime = column.default.runtime;
|
|
20
|
-
if (runtime === "cuid") return createId();
|
|
21
|
-
if (runtime === "now") return /* @__PURE__ */ new Date();
|
|
20
|
+
if (runtime === "cuid") return (context.createId ?? createId)();
|
|
21
|
+
if (runtime === "now") return (context.now ?? (() => /* @__PURE__ */ new Date()))();
|
|
22
22
|
if (typeof runtime === "function") return runtime();
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Generate a fallback value for database-level defaults.
|
|
26
|
+
*
|
|
27
|
+
* This is used by adapters that cannot rely on database DEFAULT constraints,
|
|
28
|
+
* such as the in-memory adapter.
|
|
29
|
+
*
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
function generateDatabaseDefault(column, context = {}) {
|
|
33
|
+
if (!column.default) return;
|
|
34
|
+
if ("value" in column.default) return column.default.value;
|
|
35
|
+
if ("dbSpecial" in column.default) {
|
|
36
|
+
if (column.default.dbSpecial === "now") return (context.now ?? (() => /* @__PURE__ */ new Date()))();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
24
40
|
|
|
25
41
|
//#endregion
|
|
26
|
-
export { generateRuntimeDefault };
|
|
42
|
+
export { generateDatabaseDefault, generateRuntimeDefault };
|
|
27
43
|
//# sourceMappingURL=column-defaults.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"column-defaults.js","names":[],"sources":["../../src/query/column-defaults.ts"],"sourcesContent":["import type { AnyColumn } from \"../schema/create\";\nimport { createId } from \"../id\";\n\n/**\n * Generate a runtime default value for a column that has defaultTo$()\n *\n * Only generates values for runtime defaults (defaultTo$), NOT static defaults (defaultTo).\n * Static defaults should be handled by the database via DEFAULT constraints.\n *\n * @param column - The column with a default value configuration\n * @returns The generated default value, or undefined if the column has no runtime default\n *\n * @internal\n */\nexport function generateRuntimeDefault(column: AnyColumn): unknown {\n // Check if column has a default value configuration\n if (!column.default) {\n return undefined;\n }\n\n // If it's a static default value (defaultTo), return undefined\n // as the database should handle this via DEFAULT constraint\n if (\"value\" in column.default) {\n return undefined;\n }\n\n // If it's a database-level special function (defaultTo(b => b.now())), return undefined\n // as the database should handle this via DEFAULT NOW() or equivalent\n if (\"dbSpecial\" in column.default) {\n return undefined;\n }\n\n // Handle runtime defaults (defaultTo$)\n const runtime = column.default.runtime;\n\n if (runtime === \"cuid\") {\n return createId();\n }\n\n if (runtime === \"now\") {\n return new Date();\n }\n\n if (typeof runtime === \"function\") {\n return runtime();\n }\n\n return undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"column-defaults.js","names":[],"sources":["../../src/query/column-defaults.ts"],"sourcesContent":["import type { AnyColumn } from \"../schema/create\";\nimport { createId } from \"../id\";\n\nexport type RuntimeDefaultContext = {\n now?: () => Date;\n createId?: () => string;\n};\n\n/**\n * Generate a runtime default value for a column that has defaultTo$()\n *\n * Only generates values for runtime defaults (defaultTo$), NOT static defaults (defaultTo).\n * Static defaults should be handled by the database via DEFAULT constraints.\n *\n * @param column - The column with a default value configuration\n * @returns The generated default value, or undefined if the column has no runtime default\n *\n * @internal\n */\nexport function generateRuntimeDefault(\n column: AnyColumn,\n context: RuntimeDefaultContext = {},\n): unknown {\n // Check if column has a default value configuration\n if (!column.default) {\n return undefined;\n }\n\n // If it's a static default value (defaultTo), return undefined\n // as the database should handle this via DEFAULT constraint\n if (\"value\" in column.default) {\n return undefined;\n }\n\n // If it's a database-level special function (defaultTo(b => b.now())), return undefined\n // as the database should handle this via DEFAULT NOW() or equivalent\n if (\"dbSpecial\" in column.default) {\n return undefined;\n }\n\n // Handle runtime defaults (defaultTo$)\n const runtime = column.default.runtime;\n\n if (runtime === \"cuid\") {\n return (context.createId ?? createId)();\n }\n\n if (runtime === \"now\") {\n return (context.now ?? (() => new Date()))();\n }\n\n if (typeof runtime === \"function\") {\n return runtime();\n }\n\n return undefined;\n}\n\n/**\n * Generate a fallback value for database-level defaults.\n *\n * This is used by adapters that cannot rely on database DEFAULT constraints,\n * such as the in-memory adapter.\n *\n * @internal\n */\nexport function generateDatabaseDefault(\n column: AnyColumn,\n context: RuntimeDefaultContext = {},\n): unknown {\n if (!column.default) {\n return undefined;\n }\n\n if (\"value\" in column.default) {\n return column.default.value;\n }\n\n if (\"dbSpecial\" in column.default) {\n if (column.default.dbSpecial === \"now\") {\n return (context.now ?? (() => new Date()))();\n }\n return undefined;\n }\n\n return undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;AAmBA,SAAgB,uBACd,QACA,UAAiC,EAAE,EAC1B;AAET,KAAI,CAAC,OAAO,QACV;AAKF,KAAI,WAAW,OAAO,QACpB;AAKF,KAAI,eAAe,OAAO,QACxB;CAIF,MAAM,UAAU,OAAO,QAAQ;AAE/B,KAAI,YAAY,OACd,SAAQ,QAAQ,YAAY,WAAW;AAGzC,KAAI,YAAY,MACd,SAAQ,QAAQ,8BAAc,IAAI,MAAM,IAAI;AAG9C,KAAI,OAAO,YAAY,WACrB,QAAO,SAAS;;;;;;;;;;AAcpB,SAAgB,wBACd,QACA,UAAiC,EAAE,EAC1B;AACT,KAAI,CAAC,OAAO,QACV;AAGF,KAAI,WAAW,OAAO,QACpB,QAAO,OAAO,QAAQ;AAGxB,KAAI,eAAe,OAAO,SAAS;AACjC,MAAI,OAAO,QAAQ,cAAc,MAC/B,SAAQ,QAAQ,8BAAc,IAAI,MAAM,IAAI;AAE9C"}
|
package/dist/query/cursor.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AnyColumn } from "../schema/create.js";
|
|
2
2
|
import { DriverConfig } from "../adapters/generic-sql/driver-config.js";
|
|
3
|
+
import { SQLiteStorageMode } from "../adapters/generic-sql/sqlite-storage.js";
|
|
3
4
|
|
|
4
5
|
//#region src/query/cursor.d.ts
|
|
5
6
|
|
|
@@ -114,6 +115,7 @@ declare function createCursorFromRecord(record: Record<string, unknown>, indexCo
|
|
|
114
115
|
* @param cursor - The cursor object
|
|
115
116
|
* @param indexColumns - The columns that make up the index
|
|
116
117
|
* @param driverConfig - The driver configuration
|
|
118
|
+
* @param sqliteStorageMode - Optional SQLite storage mode override
|
|
117
119
|
* @returns Serialized values ready for database queries
|
|
118
120
|
*
|
|
119
121
|
* @example
|
|
@@ -125,7 +127,7 @@ declare function createCursorFromRecord(record: Record<string, unknown>, indexCo
|
|
|
125
127
|
* );
|
|
126
128
|
* ```
|
|
127
129
|
*/
|
|
128
|
-
declare function serializeCursorValues(cursor: Cursor, indexColumns: AnyColumn[], driverConfig: DriverConfig): Record<string, unknown>;
|
|
130
|
+
declare function serializeCursorValues(cursor: Cursor, indexColumns: AnyColumn[], driverConfig: DriverConfig, sqliteStorageMode?: SQLiteStorageMode): Record<string, unknown>;
|
|
129
131
|
//#endregion
|
|
130
132
|
export { Cursor, CursorData, CursorResult, createCursorFromRecord, decodeCursor, serializeCursorValues };
|
|
131
133
|
//# sourceMappingURL=cursor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor.d.ts","names":[],"sources":["../../src/query/cursor.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cursor.d.ts","names":[],"sources":["../../src/query/cursor.ts"],"sourcesContent":[],"mappings":";;;;;;;;AASA;AAiEiB,cAjEJ,MAAA,CAiEgB;EAkBZ,CAAA,OAAA;EAqCD,WAAA,CAAA,IAAY,EAAA;IAoEZ,SAAA,EAAA,MAAA;IACN,cAAA,EAAA,KAAA,GAAA,MAAA;IACM,QAAA,EAAA,MAAA;IAMb,WAAA,EA1Lc,MA0Ld,CAAA,MAAA,EAAA,OAAA,CAAA;EAAM,CAAA;EA4CO;;;EAGA,IAAA,SAAA,CAAA,CAAA,EAAA,MAAA;EACM;;;;;;;;;;;qBA1MD;;;;;;;;;UAuBJ;;;;SAIR;;;;WAIE;;;;;;;;;UAUM,UAAA;;;;;eAKF;;;;;;;;;;;;;;iBAgCC,YAAA,kBAA8B;;;;;;;;;;;;;;;;;;;;;;iBAoE9B,sBAAA,SACN,uCACM;;;;IAMb;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4Ca,qBAAA,SACN,sBACM,2BACA,kCACM,oBACnB"}
|
package/dist/query/cursor.js
CHANGED
|
@@ -44,6 +44,7 @@ var Cursor = class {
|
|
|
44
44
|
* Encode cursor to an opaque base64 string (safe to send to client)
|
|
45
45
|
*/
|
|
46
46
|
encode() {
|
|
47
|
+
assertSerializableIndexValues(this.#indexValues);
|
|
47
48
|
return encodeCursorData({
|
|
48
49
|
v: 1,
|
|
49
50
|
indexName: this.#indexName,
|
|
@@ -57,7 +58,12 @@ var Cursor = class {
|
|
|
57
58
|
* Encode cursor data to a base64 string (internal)
|
|
58
59
|
*/
|
|
59
60
|
function encodeCursorData(data) {
|
|
60
|
-
|
|
61
|
+
let json;
|
|
62
|
+
try {
|
|
63
|
+
json = JSON.stringify(data);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
throw new Error(`Invalid cursor: ${error instanceof Error ? error.message : "malformed data"}`);
|
|
66
|
+
}
|
|
61
67
|
if (typeof Buffer !== "undefined") return Buffer.from(json, "utf-8").toString("base64");
|
|
62
68
|
return btoa(json);
|
|
63
69
|
}
|
|
@@ -79,14 +85,16 @@ function decodeCursor(cursor) {
|
|
|
79
85
|
if (typeof Buffer !== "undefined") json = Buffer.from(cursor, "base64").toString("utf-8");
|
|
80
86
|
else json = atob(cursor);
|
|
81
87
|
const data = JSON.parse(json);
|
|
82
|
-
|
|
83
|
-
|
|
88
|
+
const record = data;
|
|
89
|
+
if (!isPlainObject(data) || !isPlainObject(record["indexValues"]) || typeof record["indexName"] !== "string" || record["indexName"].length === 0 || typeof record["orderDirection"] !== "string" || record["orderDirection"] !== "asc" && record["orderDirection"] !== "desc" || typeof record["pageSize"] !== "number" || !Number.isFinite(record["pageSize"]) || !Number.isInteger(record["pageSize"]) || record["pageSize"] <= 0) throw new Error("Invalid cursor structure");
|
|
90
|
+
if (typeof record["v"] !== "number") throw new Error("Unsupported cursor version: missing. Only v1 is supported.");
|
|
91
|
+
const version = record["v"];
|
|
84
92
|
if (version !== 1) throw new Error(`Unsupported cursor version: ${version}. Only v1 is supported.`);
|
|
85
93
|
return new Cursor({
|
|
86
|
-
indexName:
|
|
87
|
-
orderDirection:
|
|
88
|
-
pageSize:
|
|
89
|
-
indexValues:
|
|
94
|
+
indexName: record["indexName"],
|
|
95
|
+
orderDirection: record["orderDirection"],
|
|
96
|
+
pageSize: record["pageSize"],
|
|
97
|
+
indexValues: record["indexValues"]
|
|
90
98
|
});
|
|
91
99
|
} catch (error) {
|
|
92
100
|
throw new Error(`Invalid cursor: ${error instanceof Error ? error.message : "malformed data"}`);
|
|
@@ -115,7 +123,11 @@ function decodeCursor(cursor) {
|
|
|
115
123
|
*/
|
|
116
124
|
function createCursorFromRecord(record, indexColumns, metadata) {
|
|
117
125
|
const indexValues = {};
|
|
118
|
-
for (const col of indexColumns)
|
|
126
|
+
for (const col of indexColumns) {
|
|
127
|
+
const value = record[col.name];
|
|
128
|
+
if (value === void 0) throw new Error(`Record is missing value for index column "${col.name}".`);
|
|
129
|
+
indexValues[col.name] = value;
|
|
130
|
+
}
|
|
119
131
|
return new Cursor({
|
|
120
132
|
indexName: metadata.indexName,
|
|
121
133
|
orderDirection: metadata.orderDirection,
|
|
@@ -136,6 +148,7 @@ function createCursorFromRecord(record, indexColumns, metadata) {
|
|
|
136
148
|
* @param cursor - The cursor object
|
|
137
149
|
* @param indexColumns - The columns that make up the index
|
|
138
150
|
* @param driverConfig - The driver configuration
|
|
151
|
+
* @param sqliteStorageMode - Optional SQLite storage mode override
|
|
139
152
|
* @returns Serialized values ready for database queries
|
|
140
153
|
*
|
|
141
154
|
* @example
|
|
@@ -147,18 +160,36 @@ function createCursorFromRecord(record, indexColumns, metadata) {
|
|
|
147
160
|
* );
|
|
148
161
|
* ```
|
|
149
162
|
*/
|
|
150
|
-
function serializeCursorValues(cursor, indexColumns, driverConfig) {
|
|
151
|
-
const serializer = createSQLSerializer(driverConfig);
|
|
163
|
+
function serializeCursorValues(cursor, indexColumns, driverConfig, sqliteStorageMode) {
|
|
164
|
+
const serializer = createSQLSerializer(driverConfig, sqliteStorageMode);
|
|
152
165
|
const serialized = {};
|
|
166
|
+
const missingColumns = [];
|
|
153
167
|
for (const col of indexColumns) {
|
|
154
|
-
const value = cursor.indexValues[col.
|
|
155
|
-
if (value
|
|
156
|
-
|
|
157
|
-
|
|
168
|
+
const value = cursor.indexValues[col.name];
|
|
169
|
+
if (value === void 0) {
|
|
170
|
+
missingColumns.push(col.name);
|
|
171
|
+
continue;
|
|
158
172
|
}
|
|
173
|
+
const resolved = resolveFragnoIdValue(serializer.deserialize(value, col), col);
|
|
174
|
+
serialized[col.name] = serializer.serialize(resolved, col);
|
|
175
|
+
}
|
|
176
|
+
if (missingColumns.length > 0) {
|
|
177
|
+
const suffix = cursor.indexName ? ` for index "${cursor.indexName}"` : "";
|
|
178
|
+
const columns = missingColumns.map((name) => `"${name}"`).join(", ");
|
|
179
|
+
const plural = missingColumns.length === 1 ? "" : "s";
|
|
180
|
+
throw new Error(`Cursor is missing values for index column${plural} ${columns}${suffix}.`);
|
|
159
181
|
}
|
|
160
182
|
return serialized;
|
|
161
183
|
}
|
|
184
|
+
const isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
185
|
+
const assertSerializableIndexValues = (values) => {
|
|
186
|
+
for (const [key, value] of Object.entries(values)) {
|
|
187
|
+
if (value === void 0) throw new Error(`Cursor index value "${key}" is undefined.`);
|
|
188
|
+
if (typeof value === "number" && !Number.isFinite(value)) throw new Error(`Cursor index value "${key}" must be a finite number.`);
|
|
189
|
+
if (typeof value === "bigint") throw new Error(`Cursor index value "${key}" must not be a BigInt.`);
|
|
190
|
+
if (typeof value === "function" || typeof value === "symbol") throw new Error(`Cursor index value "${key}" is not JSON-serializable.`);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
162
193
|
|
|
163
194
|
//#endregion
|
|
164
195
|
export { Cursor, createCursorFromRecord, decodeCursor, serializeCursorValues };
|
package/dist/query/cursor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor.js","names":["#indexName","#orderDirection","#pageSize","#indexValues","json: string","indexValues: Record<string, unknown>","serialized: Record<string, unknown>"],"sources":["../../src/query/cursor.ts"],"sourcesContent":["import type { AnyColumn } from \"../schema/create\";\nimport { createSQLSerializer } from \"./serialize/create-sql-serializer\";\nimport { resolveFragnoIdValue } from \"./value-encoding\";\nimport type { DriverConfig } from \"../adapters/generic-sql/driver-config\";\n\n/**\n * Cursor object containing all information needed for pagination\n */\nexport class Cursor {\n readonly #indexName: string;\n readonly #orderDirection: \"asc\" | \"desc\";\n readonly #pageSize: number;\n readonly #indexValues: Record<string, unknown>;\n\n constructor(data: {\n indexName: string;\n orderDirection: \"asc\" | \"desc\";\n pageSize: number;\n indexValues: Record<string, unknown>;\n }) {\n this.#indexName = data.indexName;\n this.#orderDirection = data.orderDirection;\n this.#pageSize = data.pageSize;\n this.#indexValues = data.indexValues;\n }\n\n /**\n * Get the index name being used for pagination\n */\n get indexName(): string {\n return this.#indexName;\n }\n\n /**\n * Get the ordering direction\n */\n get orderDirection(): \"asc\" | \"desc\" {\n return this.#orderDirection;\n }\n\n /**\n * Get the page size\n */\n get pageSize(): number {\n return this.#pageSize;\n }\n\n /**\n * Get the cursor position values\n */\n get indexValues(): Record<string, unknown> {\n return this.#indexValues;\n }\n\n /**\n * Encode cursor to an opaque base64 string (safe to send to client)\n */\n encode(): string {\n const data: CursorData = {\n v: 1,\n indexName: this.#indexName,\n orderDirection: this.#orderDirection,\n pageSize: this.#pageSize,\n indexValues: this.#indexValues,\n };\n return encodeCursorData(data);\n }\n}\n\n/**\n * Result of a cursor-based query containing items and pagination cursor\n */\nexport interface CursorResult<T> {\n /**\n * The query results\n */\n items: T[];\n /**\n * Cursor to fetch the next page (undefined if no more results)\n */\n cursor?: Cursor;\n /**\n * Whether there are more results available after this page\n */\n hasNextPage: boolean;\n}\n\n/**\n * Cursor data structure for serialization\n */\nexport interface CursorData {\n v: number; // version\n indexName: string;\n orderDirection: \"asc\" | \"desc\";\n pageSize: number;\n indexValues: Record<string, unknown>;\n}\n\n/**\n * Encode cursor data to a base64 string (internal)\n */\nfunction encodeCursorData(data: CursorData): string {\n const json = JSON.stringify(data);\n // Use Buffer in Node.js or btoa in browsers\n if (typeof Buffer !== \"undefined\") {\n return Buffer.from(json, \"utf-8\").toString(\"base64\");\n }\n return btoa(json);\n}\n\n/**\n * Decode a base64 cursor string back to a Cursor object\n *\n * @param cursor - The base64-encoded cursor string\n * @returns Decoded Cursor object\n * @throws Error if cursor is invalid or malformed\n *\n * @example\n * ```ts\n * const cursor = decodeCursor(\"eyJpbmRleFZhbHVlcyI6e30sImRpcmVjdGlvbiI6ImZvcndhcmQifQ==\");\n * ```\n */\nexport function decodeCursor(cursor: string): Cursor {\n try {\n let json: string;\n if (typeof Buffer !== \"undefined\") {\n json = Buffer.from(cursor, \"base64\").toString(\"utf-8\");\n } else {\n json = atob(cursor);\n }\n const data = JSON.parse(json);\n\n // Validate structure\n if (\n !data ||\n typeof data !== \"object\" ||\n !data.indexValues ||\n typeof data.indexValues !== \"object\" ||\n typeof data.pageSize !== \"number\" ||\n !data.indexName ||\n !data.orderDirection ||\n (data.orderDirection !== \"asc\" && data.orderDirection !== \"desc\")\n ) {\n throw new Error(\"Invalid cursor structure\");\n }\n\n // Only support v1\n const version = typeof data.v === \"number\" ? data.v : 0;\n if (version !== 1) {\n throw new Error(`Unsupported cursor version: ${version}. Only v1 is supported.`);\n }\n\n return new Cursor({\n indexName: data.indexName,\n orderDirection: data.orderDirection,\n pageSize: data.pageSize,\n indexValues: data.indexValues,\n });\n } catch (error) {\n throw new Error(`Invalid cursor: ${error instanceof Error ? error.message : \"malformed data\"}`);\n }\n}\n\n/**\n * Create a cursor from a record and pagination metadata\n *\n * @param record - The database record\n * @param indexColumns - The columns that make up the index\n * @param metadata - Pagination metadata (index name, order direction, page size)\n * @returns Cursor object\n *\n * @example\n * ```ts\n * const cursor = createCursorFromRecord(\n * { id: \"abc\", name: \"Alice\", createdAt: 123 },\n * [table.columns.createdAt, table.columns.id],\n * {\n * indexName: \"idx_created\",\n * orderDirection: \"asc\",\n * pageSize: 10\n * }\n * );\n * ```\n */\nexport function createCursorFromRecord(\n record: Record<string, unknown>,\n indexColumns: AnyColumn[],\n metadata: {\n indexName: string;\n orderDirection: \"asc\" | \"desc\";\n pageSize: number;\n },\n): Cursor {\n const indexValues: Record<string, unknown> = {};\n\n for (const col of indexColumns) {\n indexValues[col.ormName] = record[col.ormName];\n }\n\n return new Cursor({\n indexName: metadata.indexName,\n orderDirection: metadata.orderDirection,\n pageSize: metadata.pageSize,\n indexValues,\n });\n}\n\n/**\n * Serialize cursor values for database queries\n *\n * Converts cursor values (which are in JSON-compatible format after decode)\n * to database format using the column serialization rules.\n *\n * This function performs a two-step process:\n * 1. Deserialize from JSON format to application format (e.g., ISO string → Date)\n * 2. Serialize from application format to database format (e.g., Date → driver format)\n *\n * @param cursor - The cursor object\n * @param indexColumns - The columns that make up the index\n * @param driverConfig - The driver configuration\n * @returns Serialized values ready for database queries\n *\n * @example\n * ```ts\n * const serialized = serializeCursorValues(\n * cursor,\n * [table.columns.createdAt],\n * driverConfig\n * );\n * ```\n */\nexport function serializeCursorValues(\n cursor: Cursor,\n indexColumns: AnyColumn[],\n driverConfig: DriverConfig,\n): Record<string, unknown> {\n const serializer = createSQLSerializer(driverConfig);\n const serialized: Record<string, unknown> = {};\n\n for (const col of indexColumns) {\n const value = cursor.indexValues[col.ormName];\n if (value !== undefined) {\n // First deserialize from JSON format to application format\n // (e.g., \"2025-11-07T09:36:57.959Z\" string → Date object)\n const deserialized = serializer.deserialize(value, col);\n // Resolve FragnoId/FragnoReference to primitive values (if present)\n const resolved = resolveFragnoIdValue(deserialized, col);\n // Then serialize to database format\n // (e.g., Date → database driver format)\n serialized[col.ormName] = serializer.serialize(resolved, col);\n }\n }\n\n return serialized;\n}\n"],"mappings":";;;;;;;AAQA,IAAa,SAAb,MAAoB;CAClB,CAASA;CACT,CAASC;CACT,CAASC;CACT,CAASC;CAET,YAAY,MAKT;AACD,QAAKH,YAAa,KAAK;AACvB,QAAKC,iBAAkB,KAAK;AAC5B,QAAKC,WAAY,KAAK;AACtB,QAAKC,cAAe,KAAK;;;;;CAM3B,IAAI,YAAoB;AACtB,SAAO,MAAKH;;;;;CAMd,IAAI,iBAAiC;AACnC,SAAO,MAAKC;;;;;CAMd,IAAI,WAAmB;AACrB,SAAO,MAAKC;;;;;CAMd,IAAI,cAAuC;AACzC,SAAO,MAAKC;;;;;CAMd,SAAiB;AAQf,SAAO,iBAPkB;GACvB,GAAG;GACH,WAAW,MAAKH;GAChB,gBAAgB,MAAKC;GACrB,UAAU,MAAKC;GACf,aAAa,MAAKC;GACnB,CAC4B;;;;;;AAoCjC,SAAS,iBAAiB,MAA0B;CAClD,MAAM,OAAO,KAAK,UAAU,KAAK;AAEjC,KAAI,OAAO,WAAW,YACpB,QAAO,OAAO,KAAK,MAAM,QAAQ,CAAC,SAAS,SAAS;AAEtD,QAAO,KAAK,KAAK;;;;;;;;;;;;;;AAenB,SAAgB,aAAa,QAAwB;AACnD,KAAI;EACF,IAAIC;AACJ,MAAI,OAAO,WAAW,YACpB,QAAO,OAAO,KAAK,QAAQ,SAAS,CAAC,SAAS,QAAQ;MAEtD,QAAO,KAAK,OAAO;EAErB,MAAM,OAAO,KAAK,MAAM,KAAK;AAG7B,MACE,CAAC,QACD,OAAO,SAAS,YAChB,CAAC,KAAK,eACN,OAAO,KAAK,gBAAgB,YAC5B,OAAO,KAAK,aAAa,YACzB,CAAC,KAAK,aACN,CAAC,KAAK,kBACL,KAAK,mBAAmB,SAAS,KAAK,mBAAmB,OAE1D,OAAM,IAAI,MAAM,2BAA2B;EAI7C,MAAM,UAAU,OAAO,KAAK,MAAM,WAAW,KAAK,IAAI;AACtD,MAAI,YAAY,EACd,OAAM,IAAI,MAAM,+BAA+B,QAAQ,yBAAyB;AAGlF,SAAO,IAAI,OAAO;GAChB,WAAW,KAAK;GAChB,gBAAgB,KAAK;GACrB,UAAU,KAAK;GACf,aAAa,KAAK;GACnB,CAAC;UACK,OAAO;AACd,QAAM,IAAI,MAAM,mBAAmB,iBAAiB,QAAQ,MAAM,UAAU,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;AAyBnG,SAAgB,uBACd,QACA,cACA,UAKQ;CACR,MAAMC,cAAuC,EAAE;AAE/C,MAAK,MAAM,OAAO,aAChB,aAAY,IAAI,WAAW,OAAO,IAAI;AAGxC,QAAO,IAAI,OAAO;EAChB,WAAW,SAAS;EACpB,gBAAgB,SAAS;EACzB,UAAU,SAAS;EACnB;EACD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BJ,SAAgB,sBACd,QACA,cACA,cACyB;CACzB,MAAM,aAAa,oBAAoB,aAAa;CACpD,MAAMC,aAAsC,EAAE;AAE9C,MAAK,MAAM,OAAO,cAAc;EAC9B,MAAM,QAAQ,OAAO,YAAY,IAAI;AACrC,MAAI,UAAU,QAAW;GAKvB,MAAM,WAAW,qBAFI,WAAW,YAAY,OAAO,IAAI,EAEH,IAAI;AAGxD,cAAW,IAAI,WAAW,WAAW,UAAU,UAAU,IAAI;;;AAIjE,QAAO"}
|
|
1
|
+
{"version":3,"file":"cursor.js","names":["#indexName","#orderDirection","#pageSize","#indexValues","json: string","indexValues: Record<string, unknown>","serialized: Record<string, unknown>","missingColumns: string[]"],"sources":["../../src/query/cursor.ts"],"sourcesContent":["import type { AnyColumn } from \"../schema/create\";\nimport { createSQLSerializer } from \"./serialize/create-sql-serializer\";\nimport { resolveFragnoIdValue } from \"./value-encoding\";\nimport type { DriverConfig } from \"../adapters/generic-sql/driver-config\";\nimport type { SQLiteStorageMode } from \"../adapters/generic-sql/sqlite-storage\";\n\n/**\n * Cursor object containing all information needed for pagination\n */\nexport class Cursor {\n readonly #indexName: string;\n readonly #orderDirection: \"asc\" | \"desc\";\n readonly #pageSize: number;\n readonly #indexValues: Record<string, unknown>;\n\n constructor(data: {\n indexName: string;\n orderDirection: \"asc\" | \"desc\";\n pageSize: number;\n indexValues: Record<string, unknown>;\n }) {\n this.#indexName = data.indexName;\n this.#orderDirection = data.orderDirection;\n this.#pageSize = data.pageSize;\n this.#indexValues = data.indexValues;\n }\n\n /**\n * Get the index name being used for pagination\n */\n get indexName(): string {\n return this.#indexName;\n }\n\n /**\n * Get the ordering direction\n */\n get orderDirection(): \"asc\" | \"desc\" {\n return this.#orderDirection;\n }\n\n /**\n * Get the page size\n */\n get pageSize(): number {\n return this.#pageSize;\n }\n\n /**\n * Get the cursor position values\n */\n get indexValues(): Record<string, unknown> {\n return this.#indexValues;\n }\n\n /**\n * Encode cursor to an opaque base64 string (safe to send to client)\n */\n encode(): string {\n assertSerializableIndexValues(this.#indexValues);\n const data: CursorData = {\n v: 1,\n indexName: this.#indexName,\n orderDirection: this.#orderDirection,\n pageSize: this.#pageSize,\n indexValues: this.#indexValues,\n };\n return encodeCursorData(data);\n }\n}\n\n/**\n * Result of a cursor-based query containing items and pagination cursor\n */\nexport interface CursorResult<T> {\n /**\n * The query results\n */\n items: T[];\n /**\n * Cursor to fetch the next page (undefined if no more results)\n */\n cursor?: Cursor;\n /**\n * Whether there are more results available after this page\n */\n hasNextPage: boolean;\n}\n\n/**\n * Cursor data structure for serialization\n */\nexport interface CursorData {\n v: number; // version\n indexName: string;\n orderDirection: \"asc\" | \"desc\";\n pageSize: number;\n indexValues: Record<string, unknown>;\n}\n\n/**\n * Encode cursor data to a base64 string (internal)\n */\nfunction encodeCursorData(data: CursorData): string {\n let json: string;\n try {\n json = JSON.stringify(data);\n } catch (error) {\n throw new Error(`Invalid cursor: ${error instanceof Error ? error.message : \"malformed data\"}`);\n }\n // Use Buffer in Node.js or btoa in browsers\n if (typeof Buffer !== \"undefined\") {\n return Buffer.from(json, \"utf-8\").toString(\"base64\");\n }\n return btoa(json);\n}\n\n/**\n * Decode a base64 cursor string back to a Cursor object\n *\n * @param cursor - The base64-encoded cursor string\n * @returns Decoded Cursor object\n * @throws Error if cursor is invalid or malformed\n *\n * @example\n * ```ts\n * const cursor = decodeCursor(\"eyJpbmRleFZhbHVlcyI6e30sImRpcmVjdGlvbiI6ImZvcndhcmQifQ==\");\n * ```\n */\nexport function decodeCursor(cursor: string): Cursor {\n try {\n let json: string;\n if (typeof Buffer !== \"undefined\") {\n json = Buffer.from(cursor, \"base64\").toString(\"utf-8\");\n } else {\n json = atob(cursor);\n }\n const data = JSON.parse(json);\n const record = data as Record<string, unknown>;\n\n // Validate structure\n if (\n !isPlainObject(data) ||\n !isPlainObject(record[\"indexValues\"]) ||\n typeof record[\"indexName\"] !== \"string\" ||\n record[\"indexName\"].length === 0 ||\n typeof record[\"orderDirection\"] !== \"string\" ||\n (record[\"orderDirection\"] !== \"asc\" && record[\"orderDirection\"] !== \"desc\") ||\n typeof record[\"pageSize\"] !== \"number\" ||\n !Number.isFinite(record[\"pageSize\"]) ||\n !Number.isInteger(record[\"pageSize\"]) ||\n record[\"pageSize\"] <= 0\n ) {\n throw new Error(\"Invalid cursor structure\");\n }\n\n // Only support v1\n if (typeof record[\"v\"] !== \"number\") {\n throw new Error(\"Unsupported cursor version: missing. Only v1 is supported.\");\n }\n const version = record[\"v\"];\n if (version !== 1) {\n throw new Error(`Unsupported cursor version: ${version}. Only v1 is supported.`);\n }\n\n return new Cursor({\n indexName: record[\"indexName\"],\n orderDirection: record[\"orderDirection\"],\n pageSize: record[\"pageSize\"],\n indexValues: record[\"indexValues\"],\n });\n } catch (error) {\n throw new Error(`Invalid cursor: ${error instanceof Error ? error.message : \"malformed data\"}`);\n }\n}\n\n/**\n * Create a cursor from a record and pagination metadata\n *\n * @param record - The database record\n * @param indexColumns - The columns that make up the index\n * @param metadata - Pagination metadata (index name, order direction, page size)\n * @returns Cursor object\n *\n * @example\n * ```ts\n * const cursor = createCursorFromRecord(\n * { id: \"abc\", name: \"Alice\", createdAt: 123 },\n * [table.columns.createdAt, table.columns.id],\n * {\n * indexName: \"idx_created\",\n * orderDirection: \"asc\",\n * pageSize: 10\n * }\n * );\n * ```\n */\nexport function createCursorFromRecord(\n record: Record<string, unknown>,\n indexColumns: AnyColumn[],\n metadata: {\n indexName: string;\n orderDirection: \"asc\" | \"desc\";\n pageSize: number;\n },\n): Cursor {\n const indexValues: Record<string, unknown> = {};\n\n for (const col of indexColumns) {\n const value = record[col.name];\n if (value === undefined) {\n throw new Error(`Record is missing value for index column \"${col.name}\".`);\n }\n indexValues[col.name] = value;\n }\n\n return new Cursor({\n indexName: metadata.indexName,\n orderDirection: metadata.orderDirection,\n pageSize: metadata.pageSize,\n indexValues,\n });\n}\n\n/**\n * Serialize cursor values for database queries\n *\n * Converts cursor values (which are in JSON-compatible format after decode)\n * to database format using the column serialization rules.\n *\n * This function performs a two-step process:\n * 1. Deserialize from JSON format to application format (e.g., ISO string → Date)\n * 2. Serialize from application format to database format (e.g., Date → driver format)\n *\n * @param cursor - The cursor object\n * @param indexColumns - The columns that make up the index\n * @param driverConfig - The driver configuration\n * @param sqliteStorageMode - Optional SQLite storage mode override\n * @returns Serialized values ready for database queries\n *\n * @example\n * ```ts\n * const serialized = serializeCursorValues(\n * cursor,\n * [table.columns.createdAt],\n * driverConfig\n * );\n * ```\n */\nexport function serializeCursorValues(\n cursor: Cursor,\n indexColumns: AnyColumn[],\n driverConfig: DriverConfig,\n sqliteStorageMode?: SQLiteStorageMode,\n): Record<string, unknown> {\n const serializer = createSQLSerializer(driverConfig, sqliteStorageMode);\n const serialized: Record<string, unknown> = {};\n const missingColumns: string[] = [];\n\n for (const col of indexColumns) {\n const value = cursor.indexValues[col.name];\n if (value === undefined) {\n missingColumns.push(col.name);\n continue;\n }\n // First deserialize from JSON format to application format\n // (e.g., \"2025-11-07T09:36:57.959Z\" string → Date object)\n const deserialized = serializer.deserialize(value, col);\n // Resolve FragnoId/FragnoReference to primitive values (if present)\n const resolved = resolveFragnoIdValue(deserialized, col);\n // Then serialize to database format\n // (e.g., Date → database driver format)\n serialized[col.name] = serializer.serialize(resolved, col);\n }\n\n if (missingColumns.length > 0) {\n const suffix = cursor.indexName ? ` for index \"${cursor.indexName}\"` : \"\";\n const columns = missingColumns.map((name) => `\"${name}\"`).join(\", \");\n const plural = missingColumns.length === 1 ? \"\" : \"s\";\n throw new Error(`Cursor is missing values for index column${plural} ${columns}${suffix}.`);\n }\n\n return serialized;\n}\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst assertSerializableIndexValues = (values: Record<string, unknown>): void => {\n for (const [key, value] of Object.entries(values)) {\n if (value === undefined) {\n throw new Error(`Cursor index value \"${key}\" is undefined.`);\n }\n if (typeof value === \"number\" && !Number.isFinite(value)) {\n throw new Error(`Cursor index value \"${key}\" must be a finite number.`);\n }\n if (typeof value === \"bigint\") {\n throw new Error(`Cursor index value \"${key}\" must not be a BigInt.`);\n }\n if (typeof value === \"function\" || typeof value === \"symbol\") {\n throw new Error(`Cursor index value \"${key}\" is not JSON-serializable.`);\n }\n }\n};\n"],"mappings":";;;;;;;AASA,IAAa,SAAb,MAAoB;CAClB,CAASA;CACT,CAASC;CACT,CAASC;CACT,CAASC;CAET,YAAY,MAKT;AACD,QAAKH,YAAa,KAAK;AACvB,QAAKC,iBAAkB,KAAK;AAC5B,QAAKC,WAAY,KAAK;AACtB,QAAKC,cAAe,KAAK;;;;;CAM3B,IAAI,YAAoB;AACtB,SAAO,MAAKH;;;;;CAMd,IAAI,iBAAiC;AACnC,SAAO,MAAKC;;;;;CAMd,IAAI,WAAmB;AACrB,SAAO,MAAKC;;;;;CAMd,IAAI,cAAuC;AACzC,SAAO,MAAKC;;;;;CAMd,SAAiB;AACf,gCAA8B,MAAKA,YAAa;AAQhD,SAAO,iBAPkB;GACvB,GAAG;GACH,WAAW,MAAKH;GAChB,gBAAgB,MAAKC;GACrB,UAAU,MAAKC;GACf,aAAa,MAAKC;GACnB,CAC4B;;;;;;AAoCjC,SAAS,iBAAiB,MAA0B;CAClD,IAAIC;AACJ,KAAI;AACF,SAAO,KAAK,UAAU,KAAK;UACpB,OAAO;AACd,QAAM,IAAI,MAAM,mBAAmB,iBAAiB,QAAQ,MAAM,UAAU,mBAAmB;;AAGjG,KAAI,OAAO,WAAW,YACpB,QAAO,OAAO,KAAK,MAAM,QAAQ,CAAC,SAAS,SAAS;AAEtD,QAAO,KAAK,KAAK;;;;;;;;;;;;;;AAenB,SAAgB,aAAa,QAAwB;AACnD,KAAI;EACF,IAAIA;AACJ,MAAI,OAAO,WAAW,YACpB,QAAO,OAAO,KAAK,QAAQ,SAAS,CAAC,SAAS,QAAQ;MAEtD,QAAO,KAAK,OAAO;EAErB,MAAM,OAAO,KAAK,MAAM,KAAK;EAC7B,MAAM,SAAS;AAGf,MACE,CAAC,cAAc,KAAK,IACpB,CAAC,cAAc,OAAO,eAAe,IACrC,OAAO,OAAO,iBAAiB,YAC/B,OAAO,aAAa,WAAW,KAC/B,OAAO,OAAO,sBAAsB,YACnC,OAAO,sBAAsB,SAAS,OAAO,sBAAsB,UACpE,OAAO,OAAO,gBAAgB,YAC9B,CAAC,OAAO,SAAS,OAAO,YAAY,IACpC,CAAC,OAAO,UAAU,OAAO,YAAY,IACrC,OAAO,eAAe,EAEtB,OAAM,IAAI,MAAM,2BAA2B;AAI7C,MAAI,OAAO,OAAO,SAAS,SACzB,OAAM,IAAI,MAAM,6DAA6D;EAE/E,MAAM,UAAU,OAAO;AACvB,MAAI,YAAY,EACd,OAAM,IAAI,MAAM,+BAA+B,QAAQ,yBAAyB;AAGlF,SAAO,IAAI,OAAO;GAChB,WAAW,OAAO;GAClB,gBAAgB,OAAO;GACvB,UAAU,OAAO;GACjB,aAAa,OAAO;GACrB,CAAC;UACK,OAAO;AACd,QAAM,IAAI,MAAM,mBAAmB,iBAAiB,QAAQ,MAAM,UAAU,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;AAyBnG,SAAgB,uBACd,QACA,cACA,UAKQ;CACR,MAAMC,cAAuC,EAAE;AAE/C,MAAK,MAAM,OAAO,cAAc;EAC9B,MAAM,QAAQ,OAAO,IAAI;AACzB,MAAI,UAAU,OACZ,OAAM,IAAI,MAAM,6CAA6C,IAAI,KAAK,IAAI;AAE5E,cAAY,IAAI,QAAQ;;AAG1B,QAAO,IAAI,OAAO;EAChB,WAAW,SAAS;EACpB,gBAAgB,SAAS;EACzB,UAAU,SAAS;EACnB;EACD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BJ,SAAgB,sBACd,QACA,cACA,cACA,mBACyB;CACzB,MAAM,aAAa,oBAAoB,cAAc,kBAAkB;CACvE,MAAMC,aAAsC,EAAE;CAC9C,MAAMC,iBAA2B,EAAE;AAEnC,MAAK,MAAM,OAAO,cAAc;EAC9B,MAAM,QAAQ,OAAO,YAAY,IAAI;AACrC,MAAI,UAAU,QAAW;AACvB,kBAAe,KAAK,IAAI,KAAK;AAC7B;;EAMF,MAAM,WAAW,qBAFI,WAAW,YAAY,OAAO,IAAI,EAEH,IAAI;AAGxD,aAAW,IAAI,QAAQ,WAAW,UAAU,UAAU,IAAI;;AAG5D,KAAI,eAAe,SAAS,GAAG;EAC7B,MAAM,SAAS,OAAO,YAAY,eAAe,OAAO,UAAU,KAAK;EACvE,MAAM,UAAU,eAAe,KAAK,SAAS,IAAI,KAAK,GAAG,CAAC,KAAK,KAAK;EACpE,MAAM,SAAS,eAAe,WAAW,IAAI,KAAK;AAClD,QAAM,IAAI,MAAM,4CAA4C,OAAO,GAAG,UAAU,OAAO,GAAG;;AAG5F,QAAO;;AAGT,MAAM,iBAAiB,UACrB,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;AAEtE,MAAM,iCAAiC,WAA0C;AAC/E,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,EAAE;AACjD,MAAI,UAAU,OACZ,OAAM,IAAI,MAAM,uBAAuB,IAAI,iBAAiB;AAE9D,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,MAAM,CACtD,OAAM,IAAI,MAAM,uBAAuB,IAAI,4BAA4B;AAEzE,MAAI,OAAO,UAAU,SACnB,OAAM,IAAI,MAAM,uBAAuB,IAAI,yBAAyB;AAEtE,MAAI,OAAO,UAAU,cAAc,OAAO,UAAU,SAClD,OAAM,IAAI,MAAM,uBAAuB,IAAI,6BAA6B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-now.d.ts","names":[],"sources":["../../src/query/db-now.ts"],"sourcesContent":[],"mappings":";KAAY,KAAA;EAAA,GAAA,EAAA,QAAK;AAEjB,CAAA;cAAa,aAAY"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-now.js","names":[],"sources":["../../src/query/db-now.ts"],"sourcesContent":["export type DbNow = { tag: \"db-now\" };\n\nexport const dbNow = (): DbNow => ({ tag: \"db-now\" });\n\nexport const isDbNow = (value: unknown): value is DbNow =>\n typeof value === \"object\" && value !== null && (value as { tag?: string }).tag === \"db-now\";\n"],"mappings":";AAEA,MAAa,eAAsB,EAAE,KAAK,UAAU;AAEpD,MAAa,WAAW,UACtB,OAAO,UAAU,YAAY,UAAU,QAAS,MAA2B,QAAQ"}
|
|
@@ -11,13 +11,14 @@ import { MySQLSerializer } from "./dialect/mysql-serializer.js";
|
|
|
11
11
|
* (PostgreSQL, MySQL, or SQLite).
|
|
12
12
|
*
|
|
13
13
|
* @param driverConfig - The driver configuration
|
|
14
|
+
* @param sqliteStorageMode - Optional SQLite storage mode override
|
|
14
15
|
* @returns Dialect-specific SQLSerializer instance
|
|
15
16
|
*/
|
|
16
|
-
function createSQLSerializer(driverConfig) {
|
|
17
|
+
function createSQLSerializer(driverConfig, sqliteStorageMode) {
|
|
17
18
|
switch (driverConfig.databaseType) {
|
|
18
19
|
case "postgresql": return new PostgreSQLSerializer(driverConfig);
|
|
19
20
|
case "mysql": return new MySQLSerializer(driverConfig);
|
|
20
|
-
case "sqlite": return new SQLiteSerializer(driverConfig);
|
|
21
|
+
case "sqlite": return new SQLiteSerializer(driverConfig, sqliteStorageMode);
|
|
21
22
|
default: {
|
|
22
23
|
const exhaustiveCheck = driverConfig.databaseType;
|
|
23
24
|
throw new Error(`Unsupported database type: ${exhaustiveCheck}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-sql-serializer.js","names":["exhaustiveCheck: never"],"sources":["../../../src/query/serialize/create-sql-serializer.ts"],"sourcesContent":["import type { DriverConfig } from \"../../adapters/generic-sql/driver-config\";\nimport { SQLSerializer } from \"./sql-serializer\";\nimport { SQLiteSerializer } from \"./dialect/sqlite-serializer\";\nimport { PostgreSQLSerializer } from \"./dialect/postgres-serializer\";\nimport { MySQLSerializer } from \"./dialect/mysql-serializer\";\n\n// Re-export SQLSerializer for convenience\nexport { SQLSerializer } from \"./sql-serializer\";\n\n/**\n * Factory function to create a dialect-specific SQL serializer from a DriverConfig.\n *\n * Based on the database type, returns the appropriate serializer implementation\n * (PostgreSQL, MySQL, or SQLite).\n *\n * @param driverConfig - The driver configuration\n * @returns Dialect-specific SQLSerializer instance\n */\nexport function createSQLSerializer(driverConfig: DriverConfig): SQLSerializer {\n // TODO: The serializers are pretty lenient in what they accept (lost of typeof checks), it may\n // be beneficial to implement serializers per DriverConfig, and be less lenient.\n switch (driverConfig.databaseType) {\n case \"postgresql\":\n return new PostgreSQLSerializer(driverConfig);\n case \"mysql\":\n return new MySQLSerializer(driverConfig);\n case \"sqlite\":\n return new SQLiteSerializer(driverConfig);\n default: {\n const exhaustiveCheck: never = driverConfig.databaseType;\n throw new Error(`Unsupported database type: ${exhaustiveCheck}`);\n }\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"create-sql-serializer.js","names":["exhaustiveCheck: never"],"sources":["../../../src/query/serialize/create-sql-serializer.ts"],"sourcesContent":["import type { DriverConfig } from \"../../adapters/generic-sql/driver-config\";\nimport type { SQLiteStorageMode } from \"../../adapters/generic-sql/sqlite-storage\";\nimport { SQLSerializer } from \"./sql-serializer\";\nimport { SQLiteSerializer } from \"./dialect/sqlite-serializer\";\nimport { PostgreSQLSerializer } from \"./dialect/postgres-serializer\";\nimport { MySQLSerializer } from \"./dialect/mysql-serializer\";\n\n// Re-export SQLSerializer for convenience\nexport { SQLSerializer } from \"./sql-serializer\";\n\n/**\n * Factory function to create a dialect-specific SQL serializer from a DriverConfig.\n *\n * Based on the database type, returns the appropriate serializer implementation\n * (PostgreSQL, MySQL, or SQLite).\n *\n * @param driverConfig - The driver configuration\n * @param sqliteStorageMode - Optional SQLite storage mode override\n * @returns Dialect-specific SQLSerializer instance\n */\nexport function createSQLSerializer(\n driverConfig: DriverConfig,\n sqliteStorageMode?: SQLiteStorageMode,\n): SQLSerializer {\n // TODO: The serializers are pretty lenient in what they accept (lost of typeof checks), it may\n // be beneficial to implement serializers per DriverConfig, and be less lenient.\n switch (driverConfig.databaseType) {\n case \"postgresql\":\n return new PostgreSQLSerializer(driverConfig);\n case \"mysql\":\n return new MySQLSerializer(driverConfig);\n case \"sqlite\":\n return new SQLiteSerializer(driverConfig, sqliteStorageMode);\n default: {\n const exhaustiveCheck: never = driverConfig.databaseType;\n throw new Error(`Unsupported database type: ${exhaustiveCheck}`);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAoBA,SAAgB,oBACd,cACA,mBACe;AAGf,SAAQ,aAAa,cAArB;EACE,KAAK,aACH,QAAO,IAAI,qBAAqB,aAAa;EAC/C,KAAK,QACH,QAAO,IAAI,gBAAgB,aAAa;EAC1C,KAAK,SACH,QAAO,IAAI,iBAAiB,cAAc,kBAAkB;EAC9D,SAAS;GACP,MAAMA,kBAAyB,aAAa;AAC5C,SAAM,IAAI,MAAM,8BAA8B,kBAAkB"}
|
|
@@ -17,7 +17,7 @@ var MySQLSerializer = class extends SQLSerializer {
|
|
|
17
17
|
constructor(driverConfig) {
|
|
18
18
|
super(driverConfig);
|
|
19
19
|
}
|
|
20
|
-
serializeDate(value) {
|
|
20
|
+
serializeDate(value, _col) {
|
|
21
21
|
return value;
|
|
22
22
|
}
|
|
23
23
|
serializeBoolean(value) {
|
|
@@ -26,7 +26,7 @@ var MySQLSerializer = class extends SQLSerializer {
|
|
|
26
26
|
serializeBigInt(value, _col) {
|
|
27
27
|
return value;
|
|
28
28
|
}
|
|
29
|
-
deserializeDate(value) {
|
|
29
|
+
deserializeDate(value, _col) {
|
|
30
30
|
if (value instanceof Date) return value;
|
|
31
31
|
if (typeof value === "string") return new Date(value);
|
|
32
32
|
throw new Error(`Cannot deserialize date from value: ${value}`);
|
|
@@ -55,10 +55,13 @@ var MySQLSerializer = class extends SQLSerializer {
|
|
|
55
55
|
throw new Error(`Cannot deserialize binary from value: ${typeof value}`);
|
|
56
56
|
}
|
|
57
57
|
deserializeInteger(value) {
|
|
58
|
-
if (typeof value === "number")
|
|
58
|
+
if (typeof value === "number") {
|
|
59
|
+
if (Number.isNaN(value) || !Number.isFinite(value)) throw new Error(`Cannot deserialize integer from invalid number: ${value}`);
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
59
62
|
if (typeof value === "string") {
|
|
60
63
|
const num = Number(value);
|
|
61
|
-
if (isNaN(num)) throw new Error(`Cannot deserialize integer from invalid string: ${value}`);
|
|
64
|
+
if (Number.isNaN(num) || !Number.isFinite(num)) throw new Error(`Cannot deserialize integer from invalid string: ${value}`);
|
|
62
65
|
return num;
|
|
63
66
|
}
|
|
64
67
|
if (typeof value === "bigint") {
|
|
@@ -68,10 +71,13 @@ var MySQLSerializer = class extends SQLSerializer {
|
|
|
68
71
|
throw new Error(`Cannot deserialize integer from value: ${typeof value}`);
|
|
69
72
|
}
|
|
70
73
|
deserializeDecimal(value) {
|
|
71
|
-
if (typeof value === "number")
|
|
74
|
+
if (typeof value === "number") {
|
|
75
|
+
if (Number.isNaN(value) || !Number.isFinite(value)) throw new Error(`Cannot deserialize decimal from invalid number: ${value}`);
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
72
78
|
if (typeof value === "string") {
|
|
73
79
|
const num = parseFloat(value);
|
|
74
|
-
if (isNaN(num)) throw new Error(`Cannot deserialize decimal from invalid string: ${value}`);
|
|
80
|
+
if (Number.isNaN(num) || !Number.isFinite(num)) throw new Error(`Cannot deserialize decimal from invalid string: ${value}`);
|
|
75
81
|
return num;
|
|
76
82
|
}
|
|
77
83
|
throw new Error(`Cannot deserialize decimal from value: ${typeof value}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mysql-serializer.js","names":[],"sources":["../../../../src/query/serialize/dialect/mysql-serializer.ts"],"sourcesContent":["import type { AnyColumn } from \"../../../schema/create\";\nimport { SQLSerializer } from \"../sql-serializer\";\nimport type { DriverConfig } from \"../../../adapters/generic-sql/driver-config\";\n\n/**\n * MySQL-specific serializer.\n *\n * MySQL has good native type support:\n * - Native JSON support (MySQL 5.7+)\n * - Native boolean type (TINYINT(1))\n * - Native timestamp/datetime/date types\n * - Native bigint support\n *\n * Similar to PostgreSQL, most values pass through without conversion.\n * Timestamps/dates are returned as strings and need to be parsed.\n */\nexport class MySQLSerializer extends SQLSerializer {\n constructor(driverConfig: DriverConfig) {\n super(driverConfig);\n }\n\n protected serializeDate(value: Date): Date {\n // MySQL handles Date objects natively\n return value;\n }\n\n protected serializeBoolean(value: boolean): boolean {\n // MySQL handles boolean natively (as TINYINT(1))\n return value;\n }\n\n protected serializeBigInt(value: bigint, _col: AnyColumn): bigint {\n // MySQL handles bigint natively\n return value;\n }\n\n protected deserializeDate(value: unknown): Date {\n if (value instanceof Date) {\n return value;\n }\n // MySQL returns timestamps/dates as strings\n if (typeof value === \"string\") {\n return new Date(value);\n }\n throw new Error(`Cannot deserialize date from value: ${value}`);\n }\n\n protected deserializeBoolean(value: unknown): boolean {\n if (typeof value === \"boolean\") {\n return value;\n }\n // MySQL may return booleans as numbers (0/1)\n if (typeof value === \"number\") {\n return value === 1;\n }\n throw new Error(`Cannot deserialize boolean from value: ${value}`);\n }\n\n protected deserializeBigInt(value: unknown): bigint {\n if (typeof value === \"bigint\") {\n return value;\n }\n // MySQL may return bigints as strings\n if (typeof value === \"string\") {\n return BigInt(value);\n }\n if (typeof value === \"number\") {\n return BigInt(value);\n }\n throw new Error(`Cannot deserialize bigint from value: ${value}`);\n }\n\n protected serializeJson(value: unknown): unknown {\n // MySQL supports native JSON, pass through as-is\n return value;\n }\n\n protected deserializeJson(value: unknown): unknown {\n // MySQL returns parsed JSON objects, pass through as-is\n return value;\n }\n\n protected deserializeBinary(value: unknown): Uint8Array {\n // MySQL can return Buffer or Uint8Array for BLOB columns\n if (value instanceof Buffer) {\n return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n }\n if (value instanceof Uint8Array) {\n return value;\n }\n if (value instanceof ArrayBuffer) {\n return new Uint8Array(value);\n }\n throw new Error(`Cannot deserialize binary from value: ${typeof value}`);\n }\n\n protected deserializeInteger(value: unknown): number {\n if (typeof value === \"number\") {\n return value;\n }\n // MySQL may return integers as strings\n if (typeof value === \"string\") {\n const num = Number(value);\n if (isNaN(num)) {\n throw new Error(`Cannot deserialize integer from invalid string: ${value}`);\n }\n return num;\n }\n // MySQL may return bigint for large integers\n if (typeof value === \"bigint\") {\n if (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER) {\n throw new RangeError(\n `Cannot deserialize integer value ${value}: exceeds safe integer range`,\n );\n }\n return Number(value);\n }\n throw new Error(`Cannot deserialize integer from value: ${typeof value}`);\n }\n\n protected deserializeDecimal(value: unknown): number {\n // MySQL can return decimals as numbers or strings\n if (typeof value === \"number\") {\n return value;\n }\n if (typeof value === \"string\") {\n const num = parseFloat(value);\n if (isNaN(num)) {\n throw new Error(`Cannot deserialize decimal from invalid string: ${value}`);\n }\n return num;\n }\n throw new Error(`Cannot deserialize decimal from value: ${typeof value}`);\n }\n\n protected deserializeString(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n throw new Error(`Cannot deserialize string from value: ${typeof value}`);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAgBA,IAAa,kBAAb,cAAqC,cAAc;CACjD,YAAY,cAA4B;AACtC,QAAM,aAAa;;CAGrB,AAAU,cAAc,
|
|
1
|
+
{"version":3,"file":"mysql-serializer.js","names":[],"sources":["../../../../src/query/serialize/dialect/mysql-serializer.ts"],"sourcesContent":["import type { AnyColumn } from \"../../../schema/create\";\nimport { SQLSerializer } from \"../sql-serializer\";\nimport type { DriverConfig } from \"../../../adapters/generic-sql/driver-config\";\n\n/**\n * MySQL-specific serializer.\n *\n * MySQL has good native type support:\n * - Native JSON support (MySQL 5.7+)\n * - Native boolean type (TINYINT(1))\n * - Native timestamp/datetime/date types\n * - Native bigint support\n *\n * Similar to PostgreSQL, most values pass through without conversion.\n * Timestamps/dates are returned as strings and need to be parsed.\n */\nexport class MySQLSerializer extends SQLSerializer {\n constructor(driverConfig: DriverConfig) {\n super(driverConfig);\n }\n\n protected serializeDate(value: Date, _col: AnyColumn): Date {\n void _col;\n // MySQL handles Date objects natively\n return value;\n }\n\n protected serializeBoolean(value: boolean): boolean {\n // MySQL handles boolean natively (as TINYINT(1))\n return value;\n }\n\n protected serializeBigInt(value: bigint, _col: AnyColumn): bigint {\n // MySQL handles bigint natively\n return value;\n }\n\n protected deserializeDate(value: unknown, _col: AnyColumn): Date {\n void _col;\n if (value instanceof Date) {\n return value;\n }\n // MySQL returns timestamps/dates as strings\n if (typeof value === \"string\") {\n return new Date(value);\n }\n throw new Error(`Cannot deserialize date from value: ${value}`);\n }\n\n protected deserializeBoolean(value: unknown): boolean {\n if (typeof value === \"boolean\") {\n return value;\n }\n // MySQL may return booleans as numbers (0/1)\n if (typeof value === \"number\") {\n return value === 1;\n }\n throw new Error(`Cannot deserialize boolean from value: ${value}`);\n }\n\n protected deserializeBigInt(value: unknown): bigint {\n if (typeof value === \"bigint\") {\n return value;\n }\n // MySQL may return bigints as strings\n if (typeof value === \"string\") {\n return BigInt(value);\n }\n if (typeof value === \"number\") {\n return BigInt(value);\n }\n throw new Error(`Cannot deserialize bigint from value: ${value}`);\n }\n\n protected serializeJson(value: unknown): unknown {\n // MySQL supports native JSON, pass through as-is\n return value;\n }\n\n protected deserializeJson(value: unknown): unknown {\n // MySQL returns parsed JSON objects, pass through as-is\n return value;\n }\n\n protected deserializeBinary(value: unknown): Uint8Array {\n // MySQL can return Buffer or Uint8Array for BLOB columns\n if (value instanceof Buffer) {\n return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n }\n if (value instanceof Uint8Array) {\n return value;\n }\n if (value instanceof ArrayBuffer) {\n return new Uint8Array(value);\n }\n throw new Error(`Cannot deserialize binary from value: ${typeof value}`);\n }\n\n protected deserializeInteger(value: unknown): number {\n if (typeof value === \"number\") {\n if (Number.isNaN(value) || !Number.isFinite(value)) {\n throw new Error(`Cannot deserialize integer from invalid number: ${value}`);\n }\n return value;\n }\n // MySQL may return integers as strings\n if (typeof value === \"string\") {\n const num = Number(value);\n if (Number.isNaN(num) || !Number.isFinite(num)) {\n throw new Error(`Cannot deserialize integer from invalid string: ${value}`);\n }\n return num;\n }\n // MySQL may return bigint for large integers\n if (typeof value === \"bigint\") {\n if (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER) {\n throw new RangeError(\n `Cannot deserialize integer value ${value}: exceeds safe integer range`,\n );\n }\n return Number(value);\n }\n throw new Error(`Cannot deserialize integer from value: ${typeof value}`);\n }\n\n protected deserializeDecimal(value: unknown): number {\n // MySQL can return decimals as numbers or strings\n if (typeof value === \"number\") {\n if (Number.isNaN(value) || !Number.isFinite(value)) {\n throw new Error(`Cannot deserialize decimal from invalid number: ${value}`);\n }\n return value;\n }\n if (typeof value === \"string\") {\n const num = parseFloat(value);\n if (Number.isNaN(num) || !Number.isFinite(num)) {\n throw new Error(`Cannot deserialize decimal from invalid string: ${value}`);\n }\n return num;\n }\n throw new Error(`Cannot deserialize decimal from value: ${typeof value}`);\n }\n\n protected deserializeString(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n throw new Error(`Cannot deserialize string from value: ${typeof value}`);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAgBA,IAAa,kBAAb,cAAqC,cAAc;CACjD,YAAY,cAA4B;AACtC,QAAM,aAAa;;CAGrB,AAAU,cAAc,OAAa,MAAuB;AAG1D,SAAO;;CAGT,AAAU,iBAAiB,OAAyB;AAElD,SAAO;;CAGT,AAAU,gBAAgB,OAAe,MAAyB;AAEhE,SAAO;;CAGT,AAAU,gBAAgB,OAAgB,MAAuB;AAE/D,MAAI,iBAAiB,KACnB,QAAO;AAGT,MAAI,OAAO,UAAU,SACnB,QAAO,IAAI,KAAK,MAAM;AAExB,QAAM,IAAI,MAAM,uCAAuC,QAAQ;;CAGjE,AAAU,mBAAmB,OAAyB;AACpD,MAAI,OAAO,UAAU,UACnB,QAAO;AAGT,MAAI,OAAO,UAAU,SACnB,QAAO,UAAU;AAEnB,QAAM,IAAI,MAAM,0CAA0C,QAAQ;;CAGpE,AAAU,kBAAkB,OAAwB;AAClD,MAAI,OAAO,UAAU,SACnB,QAAO;AAGT,MAAI,OAAO,UAAU,SACnB,QAAO,OAAO,MAAM;AAEtB,MAAI,OAAO,UAAU,SACnB,QAAO,OAAO,MAAM;AAEtB,QAAM,IAAI,MAAM,yCAAyC,QAAQ;;CAGnE,AAAU,cAAc,OAAyB;AAE/C,SAAO;;CAGT,AAAU,gBAAgB,OAAyB;AAEjD,SAAO;;CAGT,AAAU,kBAAkB,OAA4B;AAEtD,MAAI,iBAAiB,OACnB,QAAO,IAAI,WAAW,MAAM,QAAQ,MAAM,YAAY,MAAM,WAAW;AAEzE,MAAI,iBAAiB,WACnB,QAAO;AAET,MAAI,iBAAiB,YACnB,QAAO,IAAI,WAAW,MAAM;AAE9B,QAAM,IAAI,MAAM,yCAAyC,OAAO,QAAQ;;CAG1E,AAAU,mBAAmB,OAAwB;AACnD,MAAI,OAAO,UAAU,UAAU;AAC7B,OAAI,OAAO,MAAM,MAAM,IAAI,CAAC,OAAO,SAAS,MAAM,CAChD,OAAM,IAAI,MAAM,mDAAmD,QAAQ;AAE7E,UAAO;;AAGT,MAAI,OAAO,UAAU,UAAU;GAC7B,MAAM,MAAM,OAAO,MAAM;AACzB,OAAI,OAAO,MAAM,IAAI,IAAI,CAAC,OAAO,SAAS,IAAI,CAC5C,OAAM,IAAI,MAAM,mDAAmD,QAAQ;AAE7E,UAAO;;AAGT,MAAI,OAAO,UAAU,UAAU;AAC7B,OAAI,QAAQ,OAAO,oBAAoB,QAAQ,OAAO,iBACpD,OAAM,IAAI,WACR,oCAAoC,MAAM,8BAC3C;AAEH,UAAO,OAAO,MAAM;;AAEtB,QAAM,IAAI,MAAM,0CAA0C,OAAO,QAAQ;;CAG3E,AAAU,mBAAmB,OAAwB;AAEnD,MAAI,OAAO,UAAU,UAAU;AAC7B,OAAI,OAAO,MAAM,MAAM,IAAI,CAAC,OAAO,SAAS,MAAM,CAChD,OAAM,IAAI,MAAM,mDAAmD,QAAQ;AAE7E,UAAO;;AAET,MAAI,OAAO,UAAU,UAAU;GAC7B,MAAM,MAAM,WAAW,MAAM;AAC7B,OAAI,OAAO,MAAM,IAAI,IAAI,CAAC,OAAO,SAAS,IAAI,CAC5C,OAAM,IAAI,MAAM,mDAAmD,QAAQ;AAE7E,UAAO;;AAET,QAAM,IAAI,MAAM,0CAA0C,OAAO,QAAQ;;CAG3E,AAAU,kBAAkB,OAAwB;AAClD,MAAI,OAAO,UAAU,SACnB,QAAO;AAET,QAAM,IAAI,MAAM,yCAAyC,OAAO,QAAQ"}
|
|
@@ -16,7 +16,7 @@ var PostgreSQLSerializer = class extends SQLSerializer {
|
|
|
16
16
|
constructor(driverConfig) {
|
|
17
17
|
super(driverConfig);
|
|
18
18
|
}
|
|
19
|
-
serializeDate(value) {
|
|
19
|
+
serializeDate(value, _col) {
|
|
20
20
|
return value;
|
|
21
21
|
}
|
|
22
22
|
serializeBoolean(value) {
|
|
@@ -25,9 +25,12 @@ var PostgreSQLSerializer = class extends SQLSerializer {
|
|
|
25
25
|
serializeBigInt(value, _col) {
|
|
26
26
|
return value;
|
|
27
27
|
}
|
|
28
|
-
deserializeDate(value) {
|
|
29
|
-
if (value instanceof Date)
|
|
30
|
-
|
|
28
|
+
deserializeDate(value, _col) {
|
|
29
|
+
if (value instanceof Date) {
|
|
30
|
+
if (this.driverConfig.driverType === "pglite") return /* @__PURE__ */ new Date(value.getTime() - value.getTimezoneOffset() * 6e4);
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
if (typeof value === "string") return new Date(normalizeTimestampString(value));
|
|
31
34
|
throw new Error(`Cannot deserialize date from value: ${value}`);
|
|
32
35
|
}
|
|
33
36
|
deserializeBoolean(value) {
|
|
@@ -53,7 +56,10 @@ var PostgreSQLSerializer = class extends SQLSerializer {
|
|
|
53
56
|
throw new Error(`Cannot deserialize binary from value: ${typeof value}`);
|
|
54
57
|
}
|
|
55
58
|
deserializeInteger(value) {
|
|
56
|
-
if (typeof value === "number")
|
|
59
|
+
if (typeof value === "number") {
|
|
60
|
+
if (Number.isNaN(value) || !Number.isFinite(value)) throw new Error(`Cannot deserialize integer from invalid number: ${value}`);
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
57
63
|
if (typeof value === "bigint") {
|
|
58
64
|
if (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER) throw new RangeError(`Cannot deserialize integer value ${value}: exceeds safe integer range`);
|
|
59
65
|
return Number(value);
|
|
@@ -61,10 +67,13 @@ var PostgreSQLSerializer = class extends SQLSerializer {
|
|
|
61
67
|
throw new Error(`Cannot deserialize integer from value: ${typeof value}`);
|
|
62
68
|
}
|
|
63
69
|
deserializeDecimal(value) {
|
|
64
|
-
if (typeof value === "number")
|
|
70
|
+
if (typeof value === "number") {
|
|
71
|
+
if (Number.isNaN(value) || !Number.isFinite(value)) throw new Error(`Cannot deserialize decimal from invalid number: ${value}`);
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
65
74
|
if (typeof value === "string") {
|
|
66
75
|
const num = parseFloat(value);
|
|
67
|
-
if (isNaN(num)) throw new Error(`Cannot deserialize decimal from invalid string: ${value}`);
|
|
76
|
+
if (Number.isNaN(num) || !Number.isFinite(num)) throw new Error(`Cannot deserialize decimal from invalid string: ${value}`);
|
|
68
77
|
return num;
|
|
69
78
|
}
|
|
70
79
|
throw new Error(`Cannot deserialize decimal from value: ${typeof value}`);
|
|
@@ -74,6 +83,15 @@ var PostgreSQLSerializer = class extends SQLSerializer {
|
|
|
74
83
|
throw new Error(`Cannot deserialize string from value: ${typeof value}`);
|
|
75
84
|
}
|
|
76
85
|
};
|
|
86
|
+
const normalizeTimestampString = (value) => {
|
|
87
|
+
if (!hasTimeComponent(value) || !isTimestampWithoutTimezone(value)) return value;
|
|
88
|
+
return `${value.includes(" ") ? value.replace(" ", "T") : value}Z`;
|
|
89
|
+
};
|
|
90
|
+
const hasTimeComponent = (value) => /\d{2}:\d{2}:\d{2}/.test(value);
|
|
91
|
+
const isTimestampWithoutTimezone = (value) => {
|
|
92
|
+
if (value.endsWith("Z")) return false;
|
|
93
|
+
return !/[+-]\d{2}(:?\d{2})?$/.test(value);
|
|
94
|
+
};
|
|
77
95
|
|
|
78
96
|
//#endregion
|
|
79
97
|
export { PostgreSQLSerializer };
|