@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
|
@@ -19,7 +19,8 @@ export class MySQLSerializer extends SQLSerializer {
|
|
|
19
19
|
super(driverConfig);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
protected serializeDate(value: Date): Date {
|
|
22
|
+
protected serializeDate(value: Date, _col: AnyColumn): Date {
|
|
23
|
+
void _col;
|
|
23
24
|
// MySQL handles Date objects natively
|
|
24
25
|
return value;
|
|
25
26
|
}
|
|
@@ -34,7 +35,8 @@ export class MySQLSerializer extends SQLSerializer {
|
|
|
34
35
|
return value;
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
protected deserializeDate(value: unknown): Date {
|
|
38
|
+
protected deserializeDate(value: unknown, _col: AnyColumn): Date {
|
|
39
|
+
void _col;
|
|
38
40
|
if (value instanceof Date) {
|
|
39
41
|
return value;
|
|
40
42
|
}
|
|
@@ -96,12 +98,15 @@ export class MySQLSerializer extends SQLSerializer {
|
|
|
96
98
|
|
|
97
99
|
protected deserializeInteger(value: unknown): number {
|
|
98
100
|
if (typeof value === "number") {
|
|
101
|
+
if (Number.isNaN(value) || !Number.isFinite(value)) {
|
|
102
|
+
throw new Error(`Cannot deserialize integer from invalid number: ${value}`);
|
|
103
|
+
}
|
|
99
104
|
return value;
|
|
100
105
|
}
|
|
101
106
|
// MySQL may return integers as strings
|
|
102
107
|
if (typeof value === "string") {
|
|
103
108
|
const num = Number(value);
|
|
104
|
-
if (isNaN(num)) {
|
|
109
|
+
if (Number.isNaN(num) || !Number.isFinite(num)) {
|
|
105
110
|
throw new Error(`Cannot deserialize integer from invalid string: ${value}`);
|
|
106
111
|
}
|
|
107
112
|
return num;
|
|
@@ -121,11 +126,14 @@ export class MySQLSerializer extends SQLSerializer {
|
|
|
121
126
|
protected deserializeDecimal(value: unknown): number {
|
|
122
127
|
// MySQL can return decimals as numbers or strings
|
|
123
128
|
if (typeof value === "number") {
|
|
129
|
+
if (Number.isNaN(value) || !Number.isFinite(value)) {
|
|
130
|
+
throw new Error(`Cannot deserialize decimal from invalid number: ${value}`);
|
|
131
|
+
}
|
|
124
132
|
return value;
|
|
125
133
|
}
|
|
126
134
|
if (typeof value === "string") {
|
|
127
135
|
const num = parseFloat(value);
|
|
128
|
-
if (isNaN(num)) {
|
|
136
|
+
if (Number.isNaN(num) || !Number.isFinite(num)) {
|
|
129
137
|
throw new Error(`Cannot deserialize decimal from invalid string: ${value}`);
|
|
130
138
|
}
|
|
131
139
|
return num;
|
|
@@ -18,7 +18,8 @@ export class PostgreSQLSerializer extends SQLSerializer {
|
|
|
18
18
|
super(driverConfig);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
protected serializeDate(value: Date): Date {
|
|
21
|
+
protected serializeDate(value: Date, _col: AnyColumn): Date {
|
|
22
|
+
void _col;
|
|
22
23
|
// PostgreSQL handles Date objects natively
|
|
23
24
|
return value;
|
|
24
25
|
}
|
|
@@ -33,13 +34,18 @@ export class PostgreSQLSerializer extends SQLSerializer {
|
|
|
33
34
|
return value;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
protected deserializeDate(value: unknown): Date {
|
|
37
|
+
protected deserializeDate(value: unknown, _col: AnyColumn): Date {
|
|
38
|
+
void _col;
|
|
37
39
|
if (value instanceof Date) {
|
|
40
|
+
if (this.driverConfig.driverType === "pglite") {
|
|
41
|
+
return new Date(value.getTime() - value.getTimezoneOffset() * 60_000);
|
|
42
|
+
}
|
|
38
43
|
return value;
|
|
39
44
|
}
|
|
40
45
|
// PostgreSQL returns timestamps/dates as strings
|
|
41
46
|
if (typeof value === "string") {
|
|
42
|
-
|
|
47
|
+
// Normalize timezone-less timestamps to UTC to avoid local offset drift.
|
|
48
|
+
return new Date(normalizeTimestampString(value));
|
|
43
49
|
}
|
|
44
50
|
throw new Error(`Cannot deserialize date from value: ${value}`);
|
|
45
51
|
}
|
|
@@ -91,6 +97,9 @@ export class PostgreSQLSerializer extends SQLSerializer {
|
|
|
91
97
|
|
|
92
98
|
protected deserializeInteger(value: unknown): number {
|
|
93
99
|
if (typeof value === "number") {
|
|
100
|
+
if (Number.isNaN(value) || !Number.isFinite(value)) {
|
|
101
|
+
throw new Error(`Cannot deserialize integer from invalid number: ${value}`);
|
|
102
|
+
}
|
|
94
103
|
return value;
|
|
95
104
|
}
|
|
96
105
|
// PostgreSQL may return bigint for large integers
|
|
@@ -108,11 +117,14 @@ export class PostgreSQLSerializer extends SQLSerializer {
|
|
|
108
117
|
protected deserializeDecimal(value: unknown): number {
|
|
109
118
|
// PostgreSQL can return decimals as numbers or strings depending on precision
|
|
110
119
|
if (typeof value === "number") {
|
|
120
|
+
if (Number.isNaN(value) || !Number.isFinite(value)) {
|
|
121
|
+
throw new Error(`Cannot deserialize decimal from invalid number: ${value}`);
|
|
122
|
+
}
|
|
111
123
|
return value;
|
|
112
124
|
}
|
|
113
125
|
if (typeof value === "string") {
|
|
114
126
|
const num = parseFloat(value);
|
|
115
|
-
if (isNaN(num)) {
|
|
127
|
+
if (Number.isNaN(num) || !Number.isFinite(num)) {
|
|
116
128
|
throw new Error(`Cannot deserialize decimal from invalid string: ${value}`);
|
|
117
129
|
}
|
|
118
130
|
return num;
|
|
@@ -127,3 +139,21 @@ export class PostgreSQLSerializer extends SQLSerializer {
|
|
|
127
139
|
throw new Error(`Cannot deserialize string from value: ${typeof value}`);
|
|
128
140
|
}
|
|
129
141
|
}
|
|
142
|
+
|
|
143
|
+
const normalizeTimestampString = (value: string) => {
|
|
144
|
+
if (!hasTimeComponent(value) || !isTimestampWithoutTimezone(value)) {
|
|
145
|
+
return value;
|
|
146
|
+
}
|
|
147
|
+
const withTimeSeparator = value.includes(" ") ? value.replace(" ", "T") : value;
|
|
148
|
+
return `${withTimeSeparator}Z`;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const hasTimeComponent = (value: string) => /\d{2}:\d{2}:\d{2}/.test(value);
|
|
152
|
+
|
|
153
|
+
const isTimestampWithoutTimezone = (value: string) => {
|
|
154
|
+
// Detect RFC3339-like timezone indicators: Z or +/-HH(:MM)?
|
|
155
|
+
if (value.endsWith("Z")) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
return !/[+-]\d{2}(:?\d{2})?$/.test(value);
|
|
159
|
+
};
|
|
@@ -2,10 +2,18 @@ import { describe, it, expect } from "vitest";
|
|
|
2
2
|
import { SQLiteSerializer } from "./sqlite-serializer";
|
|
3
3
|
import type { AnyColumn } from "../../../schema/create";
|
|
4
4
|
import { BetterSQLite3DriverConfig } from "../../../adapters/generic-sql/driver-config";
|
|
5
|
+
import { sqliteStoragePrisma } from "../../../adapters/generic-sql/sqlite-storage";
|
|
5
6
|
|
|
6
7
|
describe("SQLiteSerializer", () => {
|
|
7
8
|
const mockDriverConfig = new BetterSQLite3DriverConfig();
|
|
8
9
|
const serializer = new SQLiteSerializer(mockDriverConfig);
|
|
10
|
+
const prismaSerializer = new SQLiteSerializer(mockDriverConfig, sqliteStoragePrisma);
|
|
11
|
+
const timestampColumn: AnyColumn = {
|
|
12
|
+
name: "createdAt",
|
|
13
|
+
type: "timestamp",
|
|
14
|
+
role: "regular",
|
|
15
|
+
isNullable: false,
|
|
16
|
+
} as AnyColumn;
|
|
9
17
|
|
|
10
18
|
describe("serializeBigInt", () => {
|
|
11
19
|
describe("for internal-id and reference columns", () => {
|
|
@@ -110,6 +118,19 @@ describe("SQLiteSerializer", () => {
|
|
|
110
118
|
expect((result as Buffer).length).toBe(8);
|
|
111
119
|
});
|
|
112
120
|
|
|
121
|
+
it("should keep bigint for regular column in prisma storage", () => {
|
|
122
|
+
const col: AnyColumn = {
|
|
123
|
+
name: "largeNumber",
|
|
124
|
+
type: "bigint",
|
|
125
|
+
role: "regular",
|
|
126
|
+
isNullable: false,
|
|
127
|
+
} as AnyColumn;
|
|
128
|
+
|
|
129
|
+
const result = prismaSerializer["serializeBigInt"](BigInt(789), col);
|
|
130
|
+
expect(result).toBe(BigInt(789));
|
|
131
|
+
expect(typeof result).toBe("bigint");
|
|
132
|
+
});
|
|
133
|
+
|
|
113
134
|
it("should handle large values outside safe integer range as Buffer", () => {
|
|
114
135
|
const col: AnyColumn = {
|
|
115
136
|
name: "largeNumber",
|
|
@@ -132,11 +153,18 @@ describe("SQLiteSerializer", () => {
|
|
|
132
153
|
describe("other serialization methods", () => {
|
|
133
154
|
it("should serialize Date to timestamp number", () => {
|
|
134
155
|
const date = new Date("2024-01-01T00:00:00Z");
|
|
135
|
-
const result = serializer["serializeDate"](date);
|
|
156
|
+
const result = serializer["serializeDate"](date, timestampColumn);
|
|
136
157
|
expect(result).toBe(date.getTime());
|
|
137
158
|
expect(typeof result).toBe("number");
|
|
138
159
|
});
|
|
139
160
|
|
|
161
|
+
it("should serialize Date to ISO string for prisma storage", () => {
|
|
162
|
+
const date = new Date("2024-01-01T00:00:00Z");
|
|
163
|
+
const result = prismaSerializer["serializeDate"](date, timestampColumn);
|
|
164
|
+
expect(result).toBe(date.toISOString());
|
|
165
|
+
expect(typeof result).toBe("string");
|
|
166
|
+
});
|
|
167
|
+
|
|
140
168
|
it("should serialize boolean to 0/1", () => {
|
|
141
169
|
expect(serializer["serializeBoolean"](true)).toBe(1);
|
|
142
170
|
expect(serializer["serializeBoolean"](false)).toBe(0);
|
|
@@ -181,6 +209,18 @@ describe("SQLiteSerializer", () => {
|
|
|
181
209
|
});
|
|
182
210
|
});
|
|
183
211
|
|
|
212
|
+
describe("deserializeDate", () => {
|
|
213
|
+
it("should parse CURRENT_TIMESTAMP format as UTC", () => {
|
|
214
|
+
const date = prismaSerializer["deserializeDate"]("2024-03-10 12:34:56", timestampColumn);
|
|
215
|
+
expect(date.toISOString()).toBe("2024-03-10T12:34:56.000Z");
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("should parse CURRENT_TIMESTAMP format with milliseconds as UTC", () => {
|
|
219
|
+
const date = prismaSerializer["deserializeDate"]("2024-03-10 12:34:56.789", timestampColumn);
|
|
220
|
+
expect(date.toISOString()).toBe("2024-03-10T12:34:56.789Z");
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
184
224
|
describe("deserializeInteger", () => {
|
|
185
225
|
it("should deserialize number directly", () => {
|
|
186
226
|
expect(serializer["deserializeInteger"](42)).toBe(42);
|
|
@@ -248,4 +288,14 @@ describe("SQLiteSerializer", () => {
|
|
|
248
288
|
);
|
|
249
289
|
});
|
|
250
290
|
});
|
|
291
|
+
|
|
292
|
+
describe("deserializeBigInt", () => {
|
|
293
|
+
it("should throw when prisma storage receives unsafe bigint number", () => {
|
|
294
|
+
const unsafeNumber = Number.MAX_SAFE_INTEGER + 10;
|
|
295
|
+
expect(() => prismaSerializer["deserializeBigInt"](unsafeNumber)).toThrow(RangeError);
|
|
296
|
+
expect(() => prismaSerializer["deserializeBigInt"](unsafeNumber)).toThrow(
|
|
297
|
+
/exceeds Number\.MAX_SAFE_INTEGER/,
|
|
298
|
+
);
|
|
299
|
+
});
|
|
300
|
+
});
|
|
251
301
|
});
|
|
@@ -1,23 +1,59 @@
|
|
|
1
1
|
import type { AnyColumn } from "../../../schema/create";
|
|
2
2
|
import { SQLSerializer } from "../sql-serializer";
|
|
3
3
|
import type { DriverConfig } from "../../../adapters/generic-sql/driver-config";
|
|
4
|
+
import type { SQLiteStorageMode } from "../../../adapters/generic-sql/sqlite-storage";
|
|
5
|
+
import { sqliteStorageDefault } from "../../../adapters/generic-sql/sqlite-storage";
|
|
6
|
+
|
|
7
|
+
const SQLITE_UTC_TIMESTAMP_REGEX =
|
|
8
|
+
/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?$/;
|
|
9
|
+
|
|
10
|
+
function parseSQLiteUtcTimestamp(value: string): Date | null {
|
|
11
|
+
const match = SQLITE_UTC_TIMESTAMP_REGEX.exec(value);
|
|
12
|
+
if (!match) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const [, year, month, day, hour, minute, second, millis] = match;
|
|
17
|
+
const milliseconds = millis ? Number(millis.padEnd(3, "0")) : 0;
|
|
18
|
+
return new Date(
|
|
19
|
+
Date.UTC(
|
|
20
|
+
Number(year),
|
|
21
|
+
Number(month) - 1,
|
|
22
|
+
Number(day),
|
|
23
|
+
Number(hour),
|
|
24
|
+
Number(minute),
|
|
25
|
+
Number(second),
|
|
26
|
+
milliseconds,
|
|
27
|
+
),
|
|
28
|
+
);
|
|
29
|
+
}
|
|
4
30
|
|
|
5
31
|
/**
|
|
6
32
|
* SQLite-specific serializer.
|
|
7
33
|
*
|
|
8
34
|
* SQLite has limited native type support and requires conversions:
|
|
9
35
|
* - JSON → strings (no native JSON support)
|
|
10
|
-
* - Dates → numbers (
|
|
36
|
+
* - Dates → numbers or ISO strings (storage-mode dependent)
|
|
11
37
|
* - Booleans → 0/1
|
|
12
|
-
* - BigInts → Buffer (
|
|
38
|
+
* - BigInts → Buffer or integer (storage-mode dependent; internal-id/reference stay integer)
|
|
13
39
|
* - Numbers/strings → Date for timestamps/dates
|
|
14
40
|
*/
|
|
15
41
|
export class SQLiteSerializer extends SQLSerializer {
|
|
16
|
-
|
|
42
|
+
private readonly sqliteStorageMode: SQLiteStorageMode;
|
|
43
|
+
|
|
44
|
+
constructor(driverConfig: DriverConfig, sqliteStorageMode?: SQLiteStorageMode) {
|
|
17
45
|
super(driverConfig);
|
|
46
|
+
this.sqliteStorageMode = sqliteStorageMode ?? sqliteStorageDefault;
|
|
18
47
|
}
|
|
19
48
|
|
|
20
|
-
protected serializeDate(value: Date): number {
|
|
49
|
+
protected serializeDate(value: Date, col: AnyColumn): number | string {
|
|
50
|
+
const storage =
|
|
51
|
+
col.type === "date"
|
|
52
|
+
? this.sqliteStorageMode.dateStorage
|
|
53
|
+
: this.sqliteStorageMode.timestampStorage;
|
|
54
|
+
if (storage === "iso-text") {
|
|
55
|
+
return value.toISOString();
|
|
56
|
+
}
|
|
21
57
|
return value.getTime();
|
|
22
58
|
}
|
|
23
59
|
|
|
@@ -25,7 +61,7 @@ export class SQLiteSerializer extends SQLSerializer {
|
|
|
25
61
|
return value ? 1 : 0;
|
|
26
62
|
}
|
|
27
63
|
|
|
28
|
-
protected serializeBigInt(value: bigint, col: AnyColumn): number | Buffer {
|
|
64
|
+
protected serializeBigInt(value: bigint, col: AnyColumn): bigint | number | Buffer {
|
|
29
65
|
// SQLite special case: internal-id and reference columns use integer, not blob
|
|
30
66
|
// These should be converted to numbers for SQLite
|
|
31
67
|
if (col.role === "reference" || col.role === "internal-id") {
|
|
@@ -40,18 +76,52 @@ export class SQLiteSerializer extends SQLSerializer {
|
|
|
40
76
|
}
|
|
41
77
|
return Number(value);
|
|
42
78
|
}
|
|
79
|
+
if (this.sqliteStorageMode.bigintStorage === "integer") {
|
|
80
|
+
return value;
|
|
81
|
+
}
|
|
43
82
|
const buf = Buffer.alloc(8);
|
|
44
83
|
buf.writeBigInt64BE(value);
|
|
45
84
|
return buf;
|
|
46
85
|
}
|
|
47
86
|
|
|
48
|
-
protected deserializeDate(value: unknown): Date {
|
|
87
|
+
protected deserializeDate(value: unknown, col: AnyColumn): Date {
|
|
49
88
|
if (value instanceof Date) {
|
|
50
89
|
return value;
|
|
51
90
|
}
|
|
52
|
-
if (typeof value === "
|
|
91
|
+
if (typeof value === "string") {
|
|
92
|
+
if (/^\d+$/.test(value)) {
|
|
93
|
+
const numericDate = new Date(Number(value));
|
|
94
|
+
if (Number.isNaN(numericDate.getTime())) {
|
|
95
|
+
throw new Error(`Cannot deserialize date from value: ${value}`);
|
|
96
|
+
}
|
|
97
|
+
return numericDate;
|
|
98
|
+
}
|
|
99
|
+
const parsed = parseSQLiteUtcTimestamp(value);
|
|
100
|
+
const date = parsed ?? new Date(value);
|
|
101
|
+
if (Number.isNaN(date.getTime())) {
|
|
102
|
+
throw new Error(`Cannot deserialize date from value: ${value}`);
|
|
103
|
+
}
|
|
104
|
+
return date;
|
|
105
|
+
}
|
|
106
|
+
if (typeof value === "number") {
|
|
107
|
+
if (Number.isNaN(value)) {
|
|
108
|
+
throw new Error(`Cannot deserialize date from value: ${value}`);
|
|
109
|
+
}
|
|
53
110
|
return new Date(value);
|
|
54
111
|
}
|
|
112
|
+
if (typeof value === "bigint") {
|
|
113
|
+
const storage =
|
|
114
|
+
col.type === "date"
|
|
115
|
+
? this.sqliteStorageMode.dateStorage
|
|
116
|
+
: this.sqliteStorageMode.timestampStorage;
|
|
117
|
+
if (storage === "epoch-ms") {
|
|
118
|
+
const date = new Date(Number(value));
|
|
119
|
+
if (Number.isNaN(date.getTime())) {
|
|
120
|
+
throw new Error(`Cannot deserialize date from value: ${value}`);
|
|
121
|
+
}
|
|
122
|
+
return date;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
55
125
|
throw new Error(`Cannot deserialize date from value: ${value}`);
|
|
56
126
|
}
|
|
57
127
|
|
|
@@ -76,6 +146,13 @@ export class SQLiteSerializer extends SQLSerializer {
|
|
|
76
146
|
return BigInt(value);
|
|
77
147
|
}
|
|
78
148
|
if (typeof value === "number") {
|
|
149
|
+
if (this.sqliteStorageMode.bigintStorage === "integer") {
|
|
150
|
+
if (Math.abs(value) > Number.MAX_SAFE_INTEGER) {
|
|
151
|
+
throw new RangeError(
|
|
152
|
+
`Cannot deserialize bigint value ${value}: exceeds Number.MAX_SAFE_INTEGER`,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
79
156
|
return BigInt(value);
|
|
80
157
|
}
|
|
81
158
|
throw new Error(`Cannot deserialize bigint from value: ${value}`);
|
|
@@ -110,12 +187,15 @@ export class SQLiteSerializer extends SQLSerializer {
|
|
|
110
187
|
|
|
111
188
|
protected deserializeInteger(value: unknown): number {
|
|
112
189
|
if (typeof value === "number") {
|
|
190
|
+
if (Number.isNaN(value) || !Number.isFinite(value)) {
|
|
191
|
+
throw new Error(`Cannot deserialize integer from invalid number: ${value}`);
|
|
192
|
+
}
|
|
113
193
|
return value;
|
|
114
194
|
}
|
|
115
195
|
// SQLite may return integers as strings for large values
|
|
116
196
|
if (typeof value === "string") {
|
|
117
197
|
const num = Number(value);
|
|
118
|
-
if (isNaN(num)) {
|
|
198
|
+
if (Number.isNaN(num) || !Number.isFinite(num)) {
|
|
119
199
|
throw new Error(`Cannot deserialize integer from invalid string: ${value}`);
|
|
120
200
|
}
|
|
121
201
|
return num;
|
|
@@ -135,11 +215,14 @@ export class SQLiteSerializer extends SQLSerializer {
|
|
|
135
215
|
protected deserializeDecimal(value: unknown): number {
|
|
136
216
|
// SQLite stores decimals as REAL (floating point) or TEXT
|
|
137
217
|
if (typeof value === "number") {
|
|
218
|
+
if (Number.isNaN(value) || !Number.isFinite(value)) {
|
|
219
|
+
throw new Error(`Cannot deserialize decimal from invalid number: ${value}`);
|
|
220
|
+
}
|
|
138
221
|
return value;
|
|
139
222
|
}
|
|
140
223
|
if (typeof value === "string") {
|
|
141
224
|
const num = parseFloat(value);
|
|
142
|
-
if (isNaN(num)) {
|
|
225
|
+
if (Number.isNaN(num) || !Number.isFinite(num)) {
|
|
143
226
|
throw new Error(`Cannot deserialize decimal from invalid string: ${value}`);
|
|
144
227
|
}
|
|
145
228
|
return num;
|
|
@@ -40,7 +40,7 @@ export abstract class SQLSerializer {
|
|
|
40
40
|
|
|
41
41
|
// Handle date/timestamp deserialization
|
|
42
42
|
if (col.type === "timestamp" || col.type === "date") {
|
|
43
|
-
return this.deserializeDate(value);
|
|
43
|
+
return this.deserializeDate(value, col);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
// Handle boolean deserialization
|
|
@@ -103,7 +103,7 @@ export abstract class SQLSerializer {
|
|
|
103
103
|
if (!skipDriverConversions) {
|
|
104
104
|
// Handle date/timestamp serialization
|
|
105
105
|
if (value instanceof Date) {
|
|
106
|
-
return this.serializeDate(value);
|
|
106
|
+
return this.serializeDate(value, col);
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
// Handle boolean serialization
|
|
@@ -126,13 +126,13 @@ export abstract class SQLSerializer {
|
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
// Abstract methods for dialect-specific serialization
|
|
129
|
-
protected abstract serializeDate(value: Date): Date | number;
|
|
129
|
+
protected abstract serializeDate(value: Date, col: AnyColumn): Date | number | string;
|
|
130
130
|
protected abstract serializeBoolean(value: boolean): boolean | number;
|
|
131
131
|
protected abstract serializeBigInt(value: bigint, col: AnyColumn): bigint | number | Buffer;
|
|
132
132
|
protected abstract serializeJson(value: unknown): unknown;
|
|
133
133
|
|
|
134
134
|
// Abstract methods for dialect-specific deserialization
|
|
135
|
-
protected abstract deserializeDate(value: unknown): Date;
|
|
135
|
+
protected abstract deserializeDate(value: unknown, col: AnyColumn): Date;
|
|
136
136
|
protected abstract deserializeBoolean(value: unknown): boolean;
|
|
137
137
|
protected abstract deserializeBigInt(value: unknown): bigint;
|
|
138
138
|
protected abstract deserializeJson(value: unknown): unknown;
|
|
@@ -133,6 +133,11 @@ export type FindManyOptions<
|
|
|
133
133
|
: {});
|
|
134
134
|
|
|
135
135
|
export interface SimpleQueryInterface<TSchema extends AnySchema, TUOWConfig = void> {
|
|
136
|
+
/**
|
|
137
|
+
* Fetch the current database timestamp.
|
|
138
|
+
* Optional for adapters that cannot provide DB time.
|
|
139
|
+
*/
|
|
140
|
+
now?: () => Promise<Date>;
|
|
136
141
|
/**
|
|
137
142
|
* Find multiple records using a builder pattern
|
|
138
143
|
*/
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
} from "./retry-policy";
|
|
21
21
|
import type { AwaitedPromisesInObject, TxResult } from "./execute-unit-of-work";
|
|
22
22
|
|
|
23
|
-
const testSchema = schema((s) =>
|
|
23
|
+
const testSchema = schema("test", (s) =>
|
|
24
24
|
s.addTable("users", (t) =>
|
|
25
25
|
t
|
|
26
26
|
.addColumn("id", idColumn())
|
|
@@ -414,6 +414,26 @@ describe("Unified Tx API", () => {
|
|
|
414
414
|
expect(result.userId).toBeInstanceOf(FragnoId);
|
|
415
415
|
});
|
|
416
416
|
|
|
417
|
+
it("should throw when retry policy is provided without retrieve operations", async () => {
|
|
418
|
+
const compiler = createMockCompiler();
|
|
419
|
+
const executor: UOWExecutor<unknown, unknown> = {
|
|
420
|
+
executeRetrievalPhase: async () => [],
|
|
421
|
+
executeMutationPhase: async () => ({ success: false }),
|
|
422
|
+
};
|
|
423
|
+
const decoder = createMockDecoder();
|
|
424
|
+
|
|
425
|
+
await expect(
|
|
426
|
+
createHandlerTxBuilder({
|
|
427
|
+
createUnitOfWork: () => createUnitOfWork(compiler, executor, decoder),
|
|
428
|
+
retryPolicy: new NoRetryPolicy(),
|
|
429
|
+
})
|
|
430
|
+
.mutate(() => ({ done: true }))
|
|
431
|
+
.execute(),
|
|
432
|
+
).rejects.toThrow(
|
|
433
|
+
"Retry policy is only supported when the transaction includes retrieve operations.",
|
|
434
|
+
);
|
|
435
|
+
});
|
|
436
|
+
|
|
417
437
|
it("should execute a transaction with serviceCalls as retrieve source", async () => {
|
|
418
438
|
const compiler = createMockCompiler();
|
|
419
439
|
const mockUser = {
|
|
@@ -772,6 +792,7 @@ describe("Unified Tx API", () => {
|
|
|
772
792
|
createUnitOfWork: () => createUnitOfWork(compiler, executor, decoder),
|
|
773
793
|
retryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 5, initialDelayMs: 1 }),
|
|
774
794
|
})
|
|
795
|
+
.retrieve(({ forSchema }) => forSchema(testSchema).find("users"))
|
|
775
796
|
.mutate(({ forSchema }) => {
|
|
776
797
|
forSchema(testSchema).create("users", {
|
|
777
798
|
email: "test@example.com",
|
|
@@ -801,6 +822,7 @@ describe("Unified Tx API", () => {
|
|
|
801
822
|
createUnitOfWork: () => createUnitOfWork(compiler, executor, decoder),
|
|
802
823
|
retryPolicy: new NoRetryPolicy(),
|
|
803
824
|
})
|
|
825
|
+
.retrieve(({ forSchema }) => forSchema(testSchema).find("users"))
|
|
804
826
|
.mutate(() => ({ done: true }))
|
|
805
827
|
.execute(),
|
|
806
828
|
).rejects.toThrow(ConcurrencyConflictError);
|
|
@@ -850,6 +872,7 @@ describe("Unified Tx API", () => {
|
|
|
850
872
|
},
|
|
851
873
|
retryPolicy: new LinearBackoffRetryPolicy({ maxRetries: 3, delayMs: 1 }),
|
|
852
874
|
})
|
|
875
|
+
.retrieve(({ forSchema }) => forSchema(testSchema).find("users"))
|
|
853
876
|
.mutate(({ forSchema }) => {
|
|
854
877
|
forSchema(testSchema).create("users", {
|
|
855
878
|
email: "test@example.com",
|
|
@@ -882,6 +905,7 @@ describe("Unified Tx API", () => {
|
|
|
882
905
|
retryPolicy: new LinearBackoffRetryPolicy({ maxRetries: 5, delayMs: 100 }),
|
|
883
906
|
signal: controller.signal,
|
|
884
907
|
})
|
|
908
|
+
.retrieve(({ forSchema }) => forSchema(testSchema).find("users"))
|
|
885
909
|
.mutate(() => ({ done: true }))
|
|
886
910
|
.execute(),
|
|
887
911
|
).rejects.toThrow("Transaction execution aborted");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AnySchema } from "../../schema/create";
|
|
2
2
|
import type { TypedUnitOfWork, IUnitOfWork } from "./unit-of-work";
|
|
3
3
|
import type { HooksMap } from "../../hooks/hooks";
|
|
4
|
-
import { ExponentialBackoffRetryPolicy, type RetryPolicy } from "./retry-policy";
|
|
4
|
+
import { ExponentialBackoffRetryPolicy, NoRetryPolicy, type RetryPolicy } from "./retry-policy";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Symbol to identify TxResult objects
|
|
@@ -724,13 +724,6 @@ async function executeTx(
|
|
|
724
724
|
type TServiceCalls = readonly (TxResult<any, any> | undefined)[];
|
|
725
725
|
type TMutateResult = unknown;
|
|
726
726
|
type THooks = HooksMap;
|
|
727
|
-
const retryPolicy =
|
|
728
|
-
options.retryPolicy ??
|
|
729
|
-
new ExponentialBackoffRetryPolicy({
|
|
730
|
-
maxRetries: 5,
|
|
731
|
-
initialDelayMs: 10,
|
|
732
|
-
maxDelayMs: 100,
|
|
733
|
-
});
|
|
734
727
|
const signal = options.signal;
|
|
735
728
|
let attempt = 0;
|
|
736
729
|
|
|
@@ -740,6 +733,8 @@ async function executeTx(
|
|
|
740
733
|
throw new Error("Transaction execution aborted");
|
|
741
734
|
}
|
|
742
735
|
|
|
736
|
+
let retryPolicy: RetryPolicy | undefined;
|
|
737
|
+
|
|
743
738
|
try {
|
|
744
739
|
// Create a fresh UOW for this attempt
|
|
745
740
|
const baseUow = options.createUnitOfWork();
|
|
@@ -764,6 +759,24 @@ async function executeTx(
|
|
|
764
759
|
|
|
765
760
|
const allServiceCallTxResults = serviceCalls ? collectAllTxResults([...serviceCalls]) : [];
|
|
766
761
|
|
|
762
|
+
const hasRetrieveOps = baseUow.getRetrievalOperations().length > 0;
|
|
763
|
+
if (!hasRetrieveOps) {
|
|
764
|
+
if (options.retryPolicy) {
|
|
765
|
+
throw new Error(
|
|
766
|
+
"Retry policy is only supported when the transaction includes retrieve operations.",
|
|
767
|
+
);
|
|
768
|
+
}
|
|
769
|
+
retryPolicy = new NoRetryPolicy();
|
|
770
|
+
} else {
|
|
771
|
+
retryPolicy =
|
|
772
|
+
options.retryPolicy ??
|
|
773
|
+
new ExponentialBackoffRetryPolicy({
|
|
774
|
+
maxRetries: 5,
|
|
775
|
+
initialDelayMs: 10,
|
|
776
|
+
maxDelayMs: 100,
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
|
|
767
780
|
await baseUow.executeRetrieve();
|
|
768
781
|
|
|
769
782
|
// Get retrieve results from TypedUnitOfWork's retrievalPhase or default to empty array
|
|
@@ -885,6 +898,10 @@ async function executeTx(
|
|
|
885
898
|
throw error;
|
|
886
899
|
}
|
|
887
900
|
|
|
901
|
+
if (!retryPolicy) {
|
|
902
|
+
throw error;
|
|
903
|
+
}
|
|
904
|
+
|
|
888
905
|
if (!retryPolicy.shouldRetry(attempt, error, signal)) {
|
|
889
906
|
if (signal?.aborted) {
|
|
890
907
|
throw new Error("Transaction execution aborted");
|
|
@@ -59,7 +59,7 @@ function createMockDecoder(): UOWDecoder {
|
|
|
59
59
|
|
|
60
60
|
describe("UOW Coordinator - Parent-Child Execution", () => {
|
|
61
61
|
it("should allow child UOWs to add operations and parent to execute them", async () => {
|
|
62
|
-
const testSchema = schema((s) =>
|
|
62
|
+
const testSchema = schema("test", (s) =>
|
|
63
63
|
s.addTable("users", (t) =>
|
|
64
64
|
t.addColumn("id", idColumn()).addColumn("name", "string").addColumn("email", "string"),
|
|
65
65
|
),
|
|
@@ -102,7 +102,7 @@ describe("UOW Coordinator - Parent-Child Execution", () => {
|
|
|
102
102
|
});
|
|
103
103
|
|
|
104
104
|
it("should handle nested service calls that await phase promises without deadlock", async () => {
|
|
105
|
-
const testSchema = schema((s) =>
|
|
105
|
+
const testSchema = schema("test", (s) =>
|
|
106
106
|
s
|
|
107
107
|
.addTable("users", (t) =>
|
|
108
108
|
t.addColumn("id", idColumn()).addColumn("name", "string").addColumn("email", "string"),
|
|
@@ -176,7 +176,7 @@ describe("UOW Coordinator - Parent-Child Execution", () => {
|
|
|
176
176
|
});
|
|
177
177
|
|
|
178
178
|
it("should handle retrieval-to-mutation flow with service composition", async () => {
|
|
179
|
-
const testSchema = schema((s) =>
|
|
179
|
+
const testSchema = schema("test", (s) =>
|
|
180
180
|
s
|
|
181
181
|
.addTable("users", (t) =>
|
|
182
182
|
t
|
|
@@ -303,7 +303,7 @@ describe("UOW Coordinator - Parent-Child Execution", () => {
|
|
|
303
303
|
});
|
|
304
304
|
|
|
305
305
|
it("should handle deeply nested child UOWs (3+ levels)", async () => {
|
|
306
|
-
const testSchema = schema((s) =>
|
|
306
|
+
const testSchema = schema("test", (s) =>
|
|
307
307
|
s
|
|
308
308
|
.addTable("users", (t) =>
|
|
309
309
|
t.addColumn("id", idColumn()).addColumn("name", "string").addColumn("email", "string"),
|
|
@@ -416,7 +416,7 @@ describe("UOW Coordinator - Parent-Child Execution", () => {
|
|
|
416
416
|
});
|
|
417
417
|
|
|
418
418
|
it("should handle sibling child UOWs at same nesting level", async () => {
|
|
419
|
-
const testSchema = schema((s) =>
|
|
419
|
+
const testSchema = schema("test", (s) =>
|
|
420
420
|
s
|
|
421
421
|
.addTable("users", (t) =>
|
|
422
422
|
t
|
|
@@ -526,7 +526,7 @@ describe("UOW Coordinator - Parent-Child Execution", () => {
|
|
|
526
526
|
});
|
|
527
527
|
|
|
528
528
|
it("should support transaction rollback pattern", async () => {
|
|
529
|
-
const testSchema = schema((s) =>
|
|
529
|
+
const testSchema = schema("test", (s) =>
|
|
530
530
|
s
|
|
531
531
|
.addTable("accounts", (t) =>
|
|
532
532
|
t
|
|
@@ -633,7 +633,7 @@ describe("UOW Coordinator - Parent-Child Execution", () => {
|
|
|
633
633
|
});
|
|
634
634
|
|
|
635
635
|
it("should handle errors thrown by service methods without unhandled rejections", async () => {
|
|
636
|
-
const testSchema = schema((s) =>
|
|
636
|
+
const testSchema = schema("test", (s) =>
|
|
637
637
|
s
|
|
638
638
|
.addTable("users", (t) =>
|
|
639
639
|
t
|
|
@@ -770,7 +770,7 @@ describe("UOW Coordinator - Parent-Child Execution", () => {
|
|
|
770
770
|
});
|
|
771
771
|
|
|
772
772
|
it("should not cause unhandled rejection when service method awaits retrievalPhase and executeRetrieve fails", async () => {
|
|
773
|
-
const testSchema = schema((s) =>
|
|
773
|
+
const testSchema = schema("test", (s) =>
|
|
774
774
|
s.addTable("settings", (t) =>
|
|
775
775
|
t
|
|
776
776
|
.addColumn("id", idColumn())
|
|
@@ -830,7 +830,7 @@ describe("UOW Coordinator - Parent-Child Execution", () => {
|
|
|
830
830
|
});
|
|
831
831
|
|
|
832
832
|
it("should allow child UOW to call getCreatedIds() after parent executes mutations", async () => {
|
|
833
|
-
const testSchema = schema((s) =>
|
|
833
|
+
const testSchema = schema("test", (s) =>
|
|
834
834
|
s.addTable("products", (t) =>
|
|
835
835
|
t.addColumn("id", idColumn()).addColumn("name", "string").addColumn("price", "integer"),
|
|
836
836
|
),
|
|
@@ -862,7 +862,7 @@ describe("UOW Coordinator - Parent-Child Execution", () => {
|
|
|
862
862
|
});
|
|
863
863
|
|
|
864
864
|
it("should preserve internal IDs in child UOW when using two-phase pattern with mutationPhase await", async () => {
|
|
865
|
-
const testSchema = schema((s) =>
|
|
865
|
+
const testSchema = schema("test", (s) =>
|
|
866
866
|
s.addTable("orders", (t) =>
|
|
867
867
|
t
|
|
868
868
|
.addColumn("id", idColumn())
|
|
@@ -916,7 +916,7 @@ describe("UOW Coordinator - Parent-Child Execution", () => {
|
|
|
916
916
|
});
|
|
917
917
|
|
|
918
918
|
it("should fail when handler executes mutations before service finishes scheduling them (anti-pattern)", async () => {
|
|
919
|
-
const testSchema = schema((s) =>
|
|
919
|
+
const testSchema = schema("test", (s) =>
|
|
920
920
|
s.addTable("totp_secret", (t) =>
|
|
921
921
|
t
|
|
922
922
|
.addColumn("id", idColumn())
|
|
@@ -997,7 +997,7 @@ describe("UOW Coordinator - Parent-Child Execution", () => {
|
|
|
997
997
|
});
|
|
998
998
|
|
|
999
999
|
it("should succeed when handler awaits service promise between phases (correct pattern)", async () => {
|
|
1000
|
-
const testSchema = schema((s) =>
|
|
1000
|
+
const testSchema = schema("test", (s) =>
|
|
1001
1001
|
s.addTable("totp_secret", (t) =>
|
|
1002
1002
|
t
|
|
1003
1003
|
.addColumn("id", idColumn())
|