@fragno-dev/db 0.1.14 → 0.2.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 +242 -139
- package/CHANGELOG.md +47 -0
- package/README.md +123 -8
- package/dist/adapters/adapters.d.ts +19 -5
- package/dist/adapters/adapters.d.ts.map +1 -1
- package/dist/adapters/adapters.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-adapter.d.ts +6 -19
- package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-adapter.js +7 -47
- package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -1
- package/dist/adapters/drizzle/generate.d.ts +7 -1
- package/dist/adapters/drizzle/generate.d.ts.map +1 -1
- package/dist/adapters/drizzle/generate.js +46 -45
- package/dist/adapters/drizzle/generate.js.map +1 -1
- package/dist/adapters/generic-sql/driver-config.d.ts +74 -0
- package/dist/adapters/generic-sql/driver-config.d.ts.map +1 -0
- package/dist/adapters/generic-sql/driver-config.js +94 -0
- package/dist/adapters/generic-sql/driver-config.js.map +1 -0
- package/dist/adapters/generic-sql/generic-sql-adapter.d.ts +43 -0
- package/dist/adapters/generic-sql/generic-sql-adapter.d.ts.map +1 -0
- package/dist/adapters/generic-sql/generic-sql-adapter.js +87 -0
- package/dist/adapters/generic-sql/generic-sql-adapter.js.map +1 -0
- package/dist/adapters/generic-sql/generic-sql-uow-executor.js +67 -0
- package/dist/adapters/generic-sql/generic-sql-uow-executor.js.map +1 -0
- package/dist/adapters/generic-sql/migration/cold-kysely.js +33 -0
- package/dist/adapters/generic-sql/migration/cold-kysely.js.map +1 -0
- package/dist/adapters/generic-sql/migration/dialect/mysql.js +60 -0
- package/dist/adapters/generic-sql/migration/dialect/mysql.js.map +1 -0
- package/dist/adapters/generic-sql/migration/dialect/postgres.js +59 -0
- package/dist/adapters/generic-sql/migration/dialect/postgres.js.map +1 -0
- package/dist/adapters/generic-sql/migration/dialect/sqlite.js +96 -0
- package/dist/adapters/generic-sql/migration/dialect/sqlite.js.map +1 -0
- package/dist/adapters/generic-sql/migration/executor.d.ts +15 -0
- package/dist/adapters/generic-sql/migration/executor.d.ts.map +1 -0
- package/dist/adapters/generic-sql/migration/executor.js +18 -0
- package/dist/adapters/generic-sql/migration/executor.js.map +1 -0
- package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts +66 -0
- package/dist/adapters/generic-sql/migration/prepared-migrations.d.ts.map +1 -0
- package/dist/adapters/generic-sql/migration/prepared-migrations.js +68 -0
- package/dist/adapters/generic-sql/migration/prepared-migrations.js.map +1 -0
- package/dist/adapters/generic-sql/migration/sql-generator.js +212 -0
- package/dist/adapters/generic-sql/migration/sql-generator.js.map +1 -0
- package/dist/adapters/generic-sql/query/create-sql-query-compiler.js +32 -0
- package/dist/adapters/generic-sql/query/create-sql-query-compiler.js.map +1 -0
- package/dist/adapters/generic-sql/query/cursor-utils.js +37 -0
- package/dist/adapters/generic-sql/query/cursor-utils.js.map +1 -0
- package/dist/adapters/generic-sql/query/dialect/mysql.js +33 -0
- package/dist/adapters/generic-sql/query/dialect/mysql.js.map +1 -0
- package/dist/adapters/generic-sql/query/dialect/postgres.js +32 -0
- package/dist/adapters/generic-sql/query/dialect/postgres.js.map +1 -0
- package/dist/adapters/generic-sql/query/dialect/sqlite.js +32 -0
- package/dist/adapters/generic-sql/query/dialect/sqlite.js.map +1 -0
- package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js +152 -0
- package/dist/adapters/generic-sql/query/generic-sql-uow-operation-compiler.js.map +1 -0
- package/dist/adapters/generic-sql/query/select-builder.js +69 -0
- package/dist/adapters/generic-sql/query/select-builder.js.map +1 -0
- package/dist/adapters/generic-sql/query/sql-query-compiler.js +145 -0
- package/dist/adapters/generic-sql/query/sql-query-compiler.js.map +1 -0
- package/dist/adapters/generic-sql/query/where-builder.js +129 -0
- package/dist/adapters/generic-sql/query/where-builder.js.map +1 -0
- package/dist/adapters/generic-sql/result-interpreter.js +74 -0
- package/dist/adapters/generic-sql/result-interpreter.js.map +1 -0
- package/dist/adapters/generic-sql/uow-decoder.js +105 -0
- package/dist/adapters/generic-sql/uow-decoder.js.map +1 -0
- package/dist/adapters/generic-sql/uow-encoder.js +93 -0
- package/dist/adapters/generic-sql/uow-encoder.js.map +1 -0
- package/dist/adapters/kysely/kysely-adapter.d.ts +5 -16
- package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
- package/dist/adapters/kysely/kysely-adapter.js +6 -159
- package/dist/adapters/kysely/kysely-adapter.js.map +1 -1
- package/dist/adapters/{drizzle/drizzle-query.js → shared/from-unit-of-work-compiler.js} +48 -62
- package/dist/adapters/shared/from-unit-of-work-compiler.js.map +1 -0
- package/dist/adapters/{kysely/kysely-shared.d.ts → shared/table-name-mapper.d.ts} +3 -2
- package/dist/adapters/shared/table-name-mapper.d.ts.map +1 -0
- package/dist/adapters/shared/table-name-mapper.js +43 -0
- package/dist/adapters/shared/table-name-mapper.js.map +1 -0
- package/dist/adapters/shared/uow-operation-compiler.js +105 -0
- package/dist/adapters/shared/uow-operation-compiler.js.map +1 -0
- package/dist/db-fragment-definition-builder.d.ts +186 -0
- package/dist/db-fragment-definition-builder.d.ts.map +1 -0
- package/dist/db-fragment-definition-builder.js +207 -0
- package/dist/db-fragment-definition-builder.js.map +1 -0
- package/dist/fragments/internal-fragment.d.ts +53 -0
- package/dist/fragments/internal-fragment.d.ts.map +1 -0
- package/dist/fragments/internal-fragment.js +111 -0
- package/dist/fragments/internal-fragment.js.map +1 -0
- package/dist/hooks/hooks.d.ts +51 -0
- package/dist/hooks/hooks.d.ts.map +1 -0
- package/dist/hooks/hooks.js +88 -0
- package/dist/hooks/hooks.js.map +1 -0
- package/dist/migration-engine/generation-engine.d.ts +0 -2
- package/dist/migration-engine/generation-engine.d.ts.map +1 -1
- package/dist/migration-engine/generation-engine.js +38 -56
- package/dist/migration-engine/generation-engine.js.map +1 -1
- package/dist/mod.d.ts +35 -23
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +48 -45
- package/dist/mod.js.map +1 -1
- package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js +165 -0
- package/dist/node_modules/.pnpm/rou3@0.7.10/node_modules/rou3/dist/index.js.map +1 -0
- package/dist/packages/fragno/dist/api/bind-services.js +20 -0
- package/dist/packages/fragno/dist/api/bind-services.js.map +1 -0
- package/dist/packages/fragno/dist/api/error.js +48 -0
- package/dist/packages/fragno/dist/api/error.js.map +1 -0
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js +320 -0
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +1 -0
- package/dist/packages/fragno/dist/api/fragment-instantiator.js +525 -0
- package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +1 -0
- package/dist/packages/fragno/dist/api/fragno-response.js +73 -0
- package/dist/packages/fragno/dist/api/fragno-response.js.map +1 -0
- package/dist/packages/fragno/dist/api/internal/response-stream.js +81 -0
- package/dist/packages/fragno/dist/api/internal/response-stream.js.map +1 -0
- package/dist/packages/fragno/dist/api/internal/route.js +10 -0
- package/dist/packages/fragno/dist/api/internal/route.js.map +1 -0
- package/dist/packages/fragno/dist/api/mutable-request-state.js +97 -0
- package/dist/packages/fragno/dist/api/mutable-request-state.js.map +1 -0
- package/dist/packages/fragno/dist/api/request-context-storage.js +43 -0
- package/dist/packages/fragno/dist/api/request-context-storage.js.map +1 -0
- package/dist/packages/fragno/dist/api/request-input-context.js +118 -0
- package/dist/packages/fragno/dist/api/request-input-context.js.map +1 -0
- package/dist/packages/fragno/dist/api/request-middleware.js +83 -0
- package/dist/packages/fragno/dist/api/request-middleware.js.map +1 -0
- package/dist/packages/fragno/dist/api/request-output-context.js +119 -0
- package/dist/packages/fragno/dist/api/request-output-context.js.map +1 -0
- package/dist/packages/fragno/dist/api/route.js +17 -0
- package/dist/packages/fragno/dist/api/route.js.map +1 -0
- package/dist/packages/fragno/dist/internal/symbols.js +10 -0
- package/dist/packages/fragno/dist/internal/symbols.js.map +1 -0
- package/dist/query/column-defaults.js +27 -0
- package/dist/query/column-defaults.js.map +1 -0
- package/dist/query/cursor.d.ts +14 -6
- package/dist/query/cursor.d.ts.map +1 -1
- package/dist/query/cursor.js +16 -7
- package/dist/query/cursor.js.map +1 -1
- package/dist/query/orm/orm.d.ts +1 -1
- package/dist/query/orm/orm.js.map +1 -1
- package/dist/query/serialize/create-sql-serializer.js +30 -0
- package/dist/query/serialize/create-sql-serializer.js.map +1 -0
- package/dist/query/serialize/dialect/mysql-serializer.js +87 -0
- package/dist/query/serialize/dialect/mysql-serializer.js.map +1 -0
- package/dist/query/serialize/dialect/postgres-serializer.js +80 -0
- package/dist/query/serialize/dialect/postgres-serializer.js.map +1 -0
- package/dist/query/serialize/dialect/sqlite-serializer.js +93 -0
- package/dist/query/serialize/dialect/sqlite-serializer.js.map +1 -0
- package/dist/query/serialize/sql-serializer.js +67 -0
- package/dist/query/serialize/sql-serializer.js.map +1 -0
- package/dist/query/{query.d.ts → simple-query-interface.d.ts} +6 -6
- package/dist/query/simple-query-interface.d.ts.map +1 -0
- package/dist/query/unit-of-work/execute-unit-of-work.d.ts +133 -0
- package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -0
- package/dist/query/unit-of-work/execute-unit-of-work.js +197 -0
- package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -0
- package/dist/query/unit-of-work/retry-policy.d.ts +88 -0
- package/dist/query/unit-of-work/retry-policy.d.ts.map +1 -0
- package/dist/query/unit-of-work/retry-policy.js +61 -0
- package/dist/query/unit-of-work/retry-policy.js.map +1 -0
- package/dist/query/{unit-of-work.d.ts → unit-of-work/unit-of-work.d.ts} +145 -58
- package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -0
- package/dist/query/{unit-of-work.js → unit-of-work/unit-of-work.js} +435 -198
- package/dist/query/unit-of-work/unit-of-work.js.map +1 -0
- package/dist/query/value-decoding.js +71 -0
- package/dist/query/value-decoding.js.map +1 -0
- package/dist/query/value-encoding.js +124 -0
- package/dist/query/value-encoding.js.map +1 -0
- package/dist/schema/create.d.ts +3 -0
- package/dist/schema/create.d.ts.map +1 -1
- package/dist/schema/create.js +4 -0
- package/dist/schema/create.js.map +1 -1
- package/dist/schema/type-conversion/create-sql-type-mapper.js +29 -0
- package/dist/schema/type-conversion/create-sql-type-mapper.js.map +1 -0
- package/dist/schema/type-conversion/dialect/mysql.js +57 -0
- package/dist/schema/type-conversion/dialect/mysql.js.map +1 -0
- package/dist/schema/type-conversion/dialect/postgres.js +56 -0
- package/dist/schema/type-conversion/dialect/postgres.js.map +1 -0
- package/dist/schema/type-conversion/dialect/sqlite.js +52 -0
- package/dist/schema/type-conversion/dialect/sqlite.js.map +1 -0
- package/dist/schema/type-conversion/type-mapping.js +63 -0
- package/dist/schema/type-conversion/type-mapping.js.map +1 -0
- package/dist/sql-driver/connection/connection-provider.d.ts +13 -0
- package/dist/sql-driver/connection/connection-provider.d.ts.map +1 -0
- package/dist/sql-driver/connection/connection-provider.js +19 -0
- package/dist/sql-driver/connection/connection-provider.js.map +1 -0
- package/dist/sql-driver/connection/single-connection-provider.js +23 -0
- package/dist/sql-driver/connection/single-connection-provider.js.map +1 -0
- package/dist/sql-driver/dialect-adapter/dialect-adapter.d.ts +7 -0
- package/dist/sql-driver/dialect-adapter/dialect-adapter.d.ts.map +1 -0
- package/dist/sql-driver/dialects/dialects.d.ts +2 -0
- package/dist/sql-driver/dialects/dialects.js +3 -0
- package/dist/sql-driver/dialects/durable-object-dialect.d.ts +72 -0
- package/dist/sql-driver/dialects/durable-object-dialect.d.ts.map +1 -0
- package/dist/sql-driver/dialects/durable-object-dialect.js +130 -0
- package/dist/sql-driver/dialects/durable-object-dialect.js.map +1 -0
- package/dist/sql-driver/driver/runtime-driver.d.ts +23 -0
- package/dist/sql-driver/driver/runtime-driver.d.ts.map +1 -0
- package/dist/sql-driver/driver/runtime-driver.js +56 -0
- package/dist/sql-driver/driver/runtime-driver.js.map +1 -0
- package/dist/sql-driver/query-executor/default-query-executor.js +26 -0
- package/dist/sql-driver/query-executor/default-query-executor.js.map +1 -0
- package/dist/sql-driver/query-executor/plugin.d.ts +17 -0
- package/dist/sql-driver/query-executor/plugin.d.ts.map +1 -0
- package/dist/sql-driver/query-executor/query-executor-base.js +25 -0
- package/dist/sql-driver/query-executor/query-executor-base.js.map +1 -0
- package/dist/sql-driver/query-executor/query-executor.d.ts +36 -0
- package/dist/sql-driver/query-executor/query-executor.d.ts.map +1 -0
- package/dist/sql-driver/sql-driver-adapter.d.ts +29 -0
- package/dist/sql-driver/sql-driver-adapter.d.ts.map +1 -0
- package/dist/sql-driver/sql-driver-adapter.js +68 -0
- package/dist/sql-driver/sql-driver-adapter.js.map +1 -0
- package/dist/sql-driver/sql-driver.d.ts +38 -0
- package/dist/sql-driver/sql-driver.d.ts.map +1 -0
- package/dist/sql-driver/sql-driver.js +1 -0
- package/dist/sql-driver/sql.js +50 -0
- package/dist/sql-driver/sql.js.map +1 -0
- package/dist/with-database.d.ts +32 -0
- package/dist/with-database.d.ts.map +1 -0
- package/dist/with-database.js +34 -0
- package/dist/with-database.js.map +1 -0
- package/package.json +43 -9
- package/src/adapters/adapters.ts +23 -4
- package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +140 -185
- package/src/adapters/drizzle/{drizzle-adapter-sqlite.test.ts → drizzle-adapter-sqlite3.test.ts} +187 -55
- package/src/adapters/drizzle/drizzle-adapter.ts +14 -93
- package/src/adapters/drizzle/generate.test.ts +102 -269
- package/src/adapters/drizzle/generate.ts +89 -63
- package/src/adapters/drizzle/migrate-drizzle.test.ts +19 -0
- package/src/adapters/drizzle/shared.ts +0 -34
- package/src/adapters/drizzle/test-utils.ts +36 -5
- package/src/adapters/generic-sql/README.md +14 -0
- package/src/adapters/generic-sql/driver-config.ts +144 -0
- package/src/adapters/generic-sql/generic-sql-adapter.test.ts +50 -0
- package/src/adapters/generic-sql/generic-sql-adapter.ts +146 -0
- package/src/adapters/generic-sql/generic-sql-uow-executor.ts +130 -0
- package/src/adapters/generic-sql/migration/cold-kysely.ts +55 -0
- package/src/adapters/{kysely/migration/execute-mysql.test.ts → generic-sql/migration/dialect/mysql.test.ts} +342 -484
- package/src/adapters/generic-sql/migration/dialect/mysql.ts +104 -0
- package/src/adapters/generic-sql/migration/dialect/postgres.test.ts +1008 -0
- package/src/adapters/generic-sql/migration/dialect/postgres.ts +113 -0
- package/src/adapters/{kysely/migration/execute-sqlite.test.ts → generic-sql/migration/dialect/sqlite.test.ts} +307 -510
- package/src/adapters/generic-sql/migration/dialect/sqlite.ts +189 -0
- package/src/adapters/generic-sql/migration/executor.ts +33 -0
- package/src/adapters/generic-sql/migration/prepared-migrations.test.ts +661 -0
- package/src/adapters/generic-sql/migration/prepared-migrations.ts +214 -0
- package/src/adapters/generic-sql/migration/sql-generator.ts +413 -0
- package/src/adapters/generic-sql/query/create-sql-query-compiler.ts +36 -0
- package/src/adapters/generic-sql/query/cursor-utils.ts +56 -0
- package/src/adapters/generic-sql/query/dialect/mysql.ts +34 -0
- package/src/adapters/generic-sql/query/dialect/postgres.ts +32 -0
- package/src/adapters/generic-sql/query/dialect/sqlite.ts +32 -0
- package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.test.ts +1568 -0
- package/src/adapters/generic-sql/query/generic-sql-uow-operation-compiler.ts +314 -0
- package/src/adapters/generic-sql/query/select-builder.test.ts +256 -0
- package/src/adapters/generic-sql/query/select-builder.ts +137 -0
- package/src/adapters/generic-sql/query/sql-query-compiler.test.ts +195 -0
- package/src/adapters/generic-sql/query/sql-query-compiler.ts +367 -0
- package/src/adapters/generic-sql/query/where-builder.test.ts +744 -0
- package/src/adapters/generic-sql/query/where-builder.ts +211 -0
- package/src/adapters/generic-sql/result-interpreter.ts +102 -0
- package/src/adapters/generic-sql/test/generic-drizzle-adapter-sqlite3.test.ts +899 -0
- package/src/adapters/generic-sql/uow-decoder.test.ts +399 -0
- package/src/adapters/generic-sql/uow-decoder.ts +152 -0
- package/src/adapters/generic-sql/uow-encoder.test.ts +183 -0
- package/src/adapters/generic-sql/uow-encoder.ts +131 -0
- package/src/adapters/kysely/kysely-adapter-pglite.test.ts +90 -96
- package/src/adapters/kysely/kysely-adapter-sqlocal.test.ts +215 -0
- package/src/adapters/kysely/kysely-adapter.ts +10 -242
- package/src/adapters/{drizzle/drizzle-query.ts → shared/from-unit-of-work-compiler.ts} +111 -106
- package/src/adapters/shared/table-name-mapper.ts +50 -0
- package/src/adapters/shared/uow-operation-compiler.ts +211 -0
- package/src/db-fragment-definition-builder.test.ts +887 -0
- package/src/db-fragment-definition-builder.ts +737 -0
- package/src/db-fragment-instantiator.test.ts +543 -0
- package/src/db-fragment-integration.test.ts +406 -0
- package/src/fragments/internal-fragment.test.ts +549 -0
- package/src/fragments/internal-fragment.ts +249 -0
- package/src/hooks/hooks.test.ts +575 -0
- package/src/hooks/hooks.ts +179 -0
- package/src/migration-engine/generation-engine.test.ts +60 -27
- package/src/migration-engine/generation-engine.ts +99 -92
- package/src/mod.ts +139 -78
- package/src/query/column-defaults.ts +49 -0
- package/src/query/cursor.test.ts +147 -3
- package/src/query/cursor.ts +25 -8
- package/src/query/orm/orm.ts +1 -1
- package/src/query/query-type.test.ts +9 -9
- package/src/query/serialize/create-sql-serializer.ts +34 -0
- package/src/query/serialize/dialect/mysql-serializer.ts +142 -0
- package/src/query/serialize/dialect/postgres-serializer.ts +129 -0
- package/src/query/serialize/dialect/sqlite-serializer.test.ts +251 -0
- package/src/query/serialize/dialect/sqlite-serializer.ts +156 -0
- package/src/query/serialize/sql-serializer.ts +143 -0
- package/src/query/{query.ts → simple-query-interface.ts} +4 -4
- package/src/query/unit-of-work/execute-unit-of-work.test.ts +1310 -0
- package/src/query/unit-of-work/execute-unit-of-work.ts +504 -0
- package/src/query/unit-of-work/retry-policy.test.ts +217 -0
- package/src/query/unit-of-work/retry-policy.ts +141 -0
- package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +831 -0
- package/src/query/{unit-of-work-types.test.ts → unit-of-work/unit-of-work-types.test.ts} +7 -5
- package/src/query/unit-of-work/unit-of-work.test.ts +1716 -0
- package/src/query/{unit-of-work.ts → unit-of-work/unit-of-work.ts} +716 -420
- package/src/query/{result-transform.test.ts → value-decoding.test.ts} +45 -298
- package/src/query/value-decoding.ts +113 -0
- package/src/query/value-encoding.test.ts +390 -0
- package/src/query/value-encoding.ts +168 -0
- package/src/schema/create.test.ts +5 -1
- package/src/schema/create.ts +5 -0
- package/src/schema/serialize.test.ts +165 -407
- package/src/schema/type-conversion/create-sql-type-mapper.ts +28 -0
- package/src/schema/type-conversion/dialect/mysql.ts +64 -0
- package/src/schema/type-conversion/dialect/postgres.ts +62 -0
- package/src/schema/type-conversion/dialect/sqlite.ts +63 -0
- package/src/schema/type-conversion/type-mapping.test.ts +137 -0
- package/src/schema/type-conversion/type-mapping.ts +153 -0
- package/src/shared/connection-pool.ts +5 -5
- package/src/sql-driver/better-sqlite3.test.ts +126 -0
- package/src/sql-driver/connection/connection-provider.ts +27 -0
- package/src/sql-driver/connection/single-connection-provider.ts +42 -0
- package/src/sql-driver/dialect-adapter/dialect-adapter.ts +9 -0
- package/src/sql-driver/dialect-adapter/sqlite-dialect-adapter.ts +7 -0
- package/src/sql-driver/dialects/dialects.ts +1 -0
- package/src/sql-driver/dialects/durable-object-dialect.ts +260 -0
- package/src/sql-driver/driver/runtime-driver.ts +91 -0
- package/src/sql-driver/query-executor/default-query-executor.ts +38 -0
- package/src/sql-driver/query-executor/plugin.ts +22 -0
- package/src/sql-driver/query-executor/query-executor-base.ts +53 -0
- package/src/sql-driver/query-executor/query-executor.ts +44 -0
- package/src/sql-driver/sql-driver-adapter.ts +96 -0
- package/src/sql-driver/sql-driver.ts +53 -0
- package/src/sql-driver/sql.ts +57 -0
- package/src/sql-driver/sqlocal.test.ts +117 -0
- package/src/with-database.ts +152 -0
- package/tsdown.config.ts +8 -2
- package/dist/adapters/drizzle/drizzle-connection-pool.js +0 -40
- package/dist/adapters/drizzle/drizzle-connection-pool.js.map +0 -1
- package/dist/adapters/drizzle/drizzle-query.d.ts +0 -23
- package/dist/adapters/drizzle/drizzle-query.d.ts.map +0 -1
- package/dist/adapters/drizzle/drizzle-query.js.map +0 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts +0 -10
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map +0 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.js +0 -315
- package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +0 -1
- package/dist/adapters/drizzle/drizzle-uow-decoder.js +0 -116
- package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +0 -1
- package/dist/adapters/drizzle/drizzle-uow-executor.js +0 -149
- package/dist/adapters/drizzle/drizzle-uow-executor.js.map +0 -1
- package/dist/adapters/drizzle/join-column-utils.js +0 -28
- package/dist/adapters/drizzle/join-column-utils.js.map +0 -1
- package/dist/adapters/drizzle/shared.d.ts +0 -14
- package/dist/adapters/drizzle/shared.d.ts.map +0 -1
- package/dist/adapters/drizzle/shared.js +0 -35
- package/dist/adapters/drizzle/shared.js.map +0 -1
- package/dist/adapters/kysely/kysely-connection-pool.js +0 -41
- package/dist/adapters/kysely/kysely-connection-pool.js.map +0 -1
- package/dist/adapters/kysely/kysely-query-builder.js +0 -321
- package/dist/adapters/kysely/kysely-query-builder.js.map +0 -1
- package/dist/adapters/kysely/kysely-query-compiler.js +0 -66
- package/dist/adapters/kysely/kysely-query-compiler.js.map +0 -1
- package/dist/adapters/kysely/kysely-query.d.ts +0 -22
- package/dist/adapters/kysely/kysely-query.d.ts.map +0 -1
- package/dist/adapters/kysely/kysely-query.js +0 -223
- package/dist/adapters/kysely/kysely-query.js.map +0 -1
- package/dist/adapters/kysely/kysely-shared.d.ts.map +0 -1
- package/dist/adapters/kysely/kysely-shared.js +0 -18
- package/dist/adapters/kysely/kysely-shared.js.map +0 -1
- package/dist/adapters/kysely/kysely-uow-compiler.js +0 -170
- package/dist/adapters/kysely/kysely-uow-compiler.js.map +0 -1
- package/dist/adapters/kysely/kysely-uow-executor.js +0 -89
- package/dist/adapters/kysely/kysely-uow-executor.js.map +0 -1
- package/dist/adapters/kysely/migration/execute-base.js +0 -128
- package/dist/adapters/kysely/migration/execute-base.js.map +0 -1
- package/dist/adapters/kysely/migration/execute-factory.js +0 -34
- package/dist/adapters/kysely/migration/execute-factory.js.map +0 -1
- package/dist/adapters/kysely/migration/execute-mssql.js +0 -112
- package/dist/adapters/kysely/migration/execute-mssql.js.map +0 -1
- package/dist/adapters/kysely/migration/execute-mysql.js +0 -93
- package/dist/adapters/kysely/migration/execute-mysql.js.map +0 -1
- package/dist/adapters/kysely/migration/execute-postgres.js +0 -104
- package/dist/adapters/kysely/migration/execute-postgres.js.map +0 -1
- package/dist/adapters/kysely/migration/execute-sqlite.js +0 -123
- package/dist/adapters/kysely/migration/execute-sqlite.js.map +0 -1
- package/dist/adapters/kysely/migration/execute.js +0 -34
- package/dist/adapters/kysely/migration/execute.js.map +0 -1
- package/dist/bind-services.d.ts +0 -7
- package/dist/bind-services.d.ts.map +0 -1
- package/dist/bind-services.js +0 -14
- package/dist/bind-services.js.map +0 -1
- package/dist/fragment.d.ts +0 -173
- package/dist/fragment.d.ts.map +0 -1
- package/dist/fragment.js +0 -191
- package/dist/fragment.js.map +0 -1
- package/dist/migration-engine/create.d.ts +0 -37
- package/dist/migration-engine/create.d.ts.map +0 -1
- package/dist/migration-engine/create.js +0 -58
- package/dist/migration-engine/create.js.map +0 -1
- package/dist/migration-engine/shared.d.ts +0 -112
- package/dist/migration-engine/shared.d.ts.map +0 -1
- package/dist/query/query.d.ts.map +0 -1
- package/dist/query/result-transform.js +0 -168
- package/dist/query/result-transform.js.map +0 -1
- package/dist/query/unit-of-work.d.ts.map +0 -1
- package/dist/query/unit-of-work.js.map +0 -1
- package/dist/schema/serialize.js +0 -106
- package/dist/schema/serialize.js.map +0 -1
- package/dist/shared/settings-schema.js +0 -36
- package/dist/shared/settings-schema.js.map +0 -1
- package/src/adapters/drizzle/drizzle-adapter.test.ts +0 -170
- package/src/adapters/drizzle/drizzle-connection-pool.ts +0 -66
- package/src/adapters/drizzle/drizzle-query.test.ts +0 -499
- package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +0 -1383
- package/src/adapters/drizzle/drizzle-uow-compiler.ts +0 -636
- package/src/adapters/drizzle/drizzle-uow-decoder.ts +0 -218
- package/src/adapters/drizzle/drizzle-uow-executor.ts +0 -276
- package/src/adapters/drizzle/join-column-utils.test.ts +0 -79
- package/src/adapters/drizzle/join-column-utils.ts +0 -39
- package/src/adapters/kysely/kysely-connection-pool.ts +0 -70
- package/src/adapters/kysely/kysely-query-builder.test.ts +0 -1344
- package/src/adapters/kysely/kysely-query-builder.ts +0 -666
- package/src/adapters/kysely/kysely-query-compiler.ts +0 -132
- package/src/adapters/kysely/kysely-query.test.ts +0 -498
- package/src/adapters/kysely/kysely-query.ts +0 -390
- package/src/adapters/kysely/kysely-shared.ts +0 -23
- package/src/adapters/kysely/kysely-uow-compiler.test.ts +0 -998
- package/src/adapters/kysely/kysely-uow-compiler.ts +0 -318
- package/src/adapters/kysely/kysely-uow-executor.ts +0 -145
- package/src/adapters/kysely/kysely-uow-joins.test.ts +0 -811
- package/src/adapters/kysely/migration/execute-base.ts +0 -256
- package/src/adapters/kysely/migration/execute-factory.ts +0 -53
- package/src/adapters/kysely/migration/execute-mssql.ts +0 -250
- package/src/adapters/kysely/migration/execute-mysql.ts +0 -211
- package/src/adapters/kysely/migration/execute-postgres.test.ts +0 -2657
- package/src/adapters/kysely/migration/execute-postgres.ts +0 -234
- package/src/adapters/kysely/migration/execute-sqlite.ts +0 -247
- package/src/adapters/kysely/migration/execute.ts +0 -50
- package/src/adapters/kysely/migration/kysely-migrator.test.ts +0 -261
- package/src/bind-services.test.ts +0 -214
- package/src/bind-services.ts +0 -37
- package/src/db-fragment.test.ts +0 -800
- package/src/fragment.ts +0 -727
- package/src/query/result-transform.ts +0 -271
- package/src/query/unit-of-work-multi-schema.test.ts +0 -64
- package/src/query/unit-of-work.test.ts +0 -943
- package/src/schema/serialize.ts +0 -396
- package/src/shared/settings-schema.ts +0 -61
- package/src/uow-context-integration.test.ts +0 -102
- package/src/uow-context.test.ts +0 -182
- /package/dist/query/{query.js → simple-query-interface.js} +0 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
//#region src/adapters/generic-sql/query/select-builder.ts
|
|
2
|
+
/**
|
|
3
|
+
* Maps a select clause to SQL column names with optional aliases.
|
|
4
|
+
*
|
|
5
|
+
* Converts application-level select clauses (either array of keys or "select all")
|
|
6
|
+
* into SQL-compatible column selections with proper aliasing for relations.
|
|
7
|
+
*
|
|
8
|
+
* @param select - The select clause (array of keys or true for all columns)
|
|
9
|
+
* @param table - The table schema containing column definitions
|
|
10
|
+
* @param options - Optional configuration
|
|
11
|
+
* @param options.relation - Relation name to prefix in aliases (for joined data)
|
|
12
|
+
* @param options.tableName - Override the table name in the SQL (defaults to table.name)
|
|
13
|
+
* @returns Array of SQL select strings in the format "tableName.columnName as alias"
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
function mapSelect(select, table, options = {}) {
|
|
17
|
+
const { relation, tableName = table.name } = options;
|
|
18
|
+
const out = [];
|
|
19
|
+
const keys = Array.isArray(select) ? select : Object.keys(table.columns);
|
|
20
|
+
for (const key of keys) {
|
|
21
|
+
const col = table.columns[key];
|
|
22
|
+
if (Array.isArray(select) && col.isHidden) continue;
|
|
23
|
+
const name = relation ? `${relation}:${key}` : key;
|
|
24
|
+
out.push(`${tableName}.${col.name} as ${name}`);
|
|
25
|
+
}
|
|
26
|
+
for (const key in table.columns) {
|
|
27
|
+
const col = table.columns[key];
|
|
28
|
+
if (col.isHidden && !keys.includes(key)) {
|
|
29
|
+
const name = relation ? `${relation}:${key}` : key;
|
|
30
|
+
out.push(`${tableName}.${col.name} as ${name}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Creates a builder that can extend a select clause with additional keys.
|
|
37
|
+
*
|
|
38
|
+
* This is useful when you need to temporarily include columns for join operations
|
|
39
|
+
* or other internal processing, but don't want them in the final result.
|
|
40
|
+
*
|
|
41
|
+
* @param original - The original select clause from the user
|
|
42
|
+
* @returns A select builder with extend() and compile() methods
|
|
43
|
+
* @internal
|
|
44
|
+
*/
|
|
45
|
+
function extendSelect(original) {
|
|
46
|
+
const select = Array.isArray(original) ? new Set(original) : true;
|
|
47
|
+
const extendedKeys = [];
|
|
48
|
+
return {
|
|
49
|
+
extend(key) {
|
|
50
|
+
if (select === true || select.has(key)) return;
|
|
51
|
+
select.add(key);
|
|
52
|
+
extendedKeys.push(key);
|
|
53
|
+
},
|
|
54
|
+
compile() {
|
|
55
|
+
return {
|
|
56
|
+
result: select instanceof Set ? Array.from(select) : true,
|
|
57
|
+
extendedKeys,
|
|
58
|
+
removeExtendedKeys(record) {
|
|
59
|
+
for (const key of extendedKeys) delete record[key];
|
|
60
|
+
return record;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
//#endregion
|
|
68
|
+
export { extendSelect, mapSelect };
|
|
69
|
+
//# sourceMappingURL=select-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-builder.js","names":["out: string[]","extendedKeys: string[]"],"sources":["../../../../src/adapters/generic-sql/query/select-builder.ts"],"sourcesContent":["import type { AnyTable } from \"../../../schema/create\";\nimport type { AnySelectClause } from \"../../../query/simple-query-interface\";\n\n/**\n * Maps a select clause to SQL column names with optional aliases.\n *\n * Converts application-level select clauses (either array of keys or \"select all\")\n * into SQL-compatible column selections with proper aliasing for relations.\n *\n * @param select - The select clause (array of keys or true for all columns)\n * @param table - The table schema containing column definitions\n * @param options - Optional configuration\n * @param options.relation - Relation name to prefix in aliases (for joined data)\n * @param options.tableName - Override the table name in the SQL (defaults to table.name)\n * @returns Array of SQL select strings in the format \"tableName.columnName as alias\"\n * @internal\n */\nexport function mapSelect(\n select: AnySelectClause,\n table: AnyTable,\n options: {\n relation?: string;\n tableName?: string;\n } = {},\n): string[] {\n const { relation, tableName = table.name } = options;\n const out: string[] = [];\n const keys = Array.isArray(select) ? select : Object.keys(table.columns);\n\n for (const key of keys) {\n const col = table.columns[key];\n\n // Skip hidden columns when explicitly selecting\n if (Array.isArray(select) && col.isHidden) {\n continue;\n }\n\n // Add the column to the select list\n const name = relation ? `${relation}:${key}` : key;\n out.push(`${tableName}.${col.name} as ${name}`);\n }\n\n // Always include hidden columns (for FragnoId construction with internal ID and version)\n for (const key in table.columns) {\n const col = table.columns[key];\n if (col.isHidden && !keys.includes(key)) {\n const name = relation ? `${relation}:${key}` : key;\n out.push(`${tableName}.${col.name} as ${name}`);\n }\n }\n\n return out;\n}\n\n/**\n * Result type from compiling a select clause with extensions.\n * @internal\n */\nexport interface CompiledSelect {\n /**\n * The final select clause to use in the query\n */\n result: AnySelectClause;\n\n /**\n * Keys that were added to the select clause (not originally requested)\n */\n extendedKeys: string[];\n\n /**\n * Removes the extended keys from a record (mutates the record).\n * Used to clean up keys that were only needed for join operations.\n *\n * @param record - The record to remove extended keys from\n * @returns The same record with extended keys removed\n */\n removeExtendedKeys: (record: Record<string, unknown>) => Record<string, unknown>;\n}\n\n/**\n * Builder for extending a select clause with additional keys.\n * @internal\n */\nexport interface SelectBuilder {\n /**\n * Adds a key to the select clause if not already present.\n * Tracks which keys were added for later removal.\n *\n * @param key - The key to add to the select clause\n */\n extend: (key: string) => void;\n\n /**\n * Compiles the select clause into its final form.\n *\n * @returns The compiled select information\n */\n compile: () => CompiledSelect;\n}\n\n/**\n * Creates a builder that can extend a select clause with additional keys.\n *\n * This is useful when you need to temporarily include columns for join operations\n * or other internal processing, but don't want them in the final result.\n *\n * @param original - The original select clause from the user\n * @returns A select builder with extend() and compile() methods\n * @internal\n */\nexport function extendSelect(original: AnySelectClause): SelectBuilder {\n const select = Array.isArray(original) ? new Set(original) : true;\n const extendedKeys: string[] = [];\n\n return {\n extend(key) {\n if (select === true || select.has(key)) {\n return;\n }\n\n select.add(key);\n extendedKeys.push(key);\n },\n compile() {\n return {\n result: select instanceof Set ? Array.from(select) : true,\n extendedKeys,\n removeExtendedKeys(record) {\n for (const key of extendedKeys) {\n delete record[key];\n }\n return record;\n },\n };\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;AAiBA,SAAgB,UACd,QACA,OACA,UAGI,EAAE,EACI;CACV,MAAM,EAAE,UAAU,YAAY,MAAM,SAAS;CAC7C,MAAMA,MAAgB,EAAE;CACxB,MAAM,OAAO,MAAM,QAAQ,OAAO,GAAG,SAAS,OAAO,KAAK,MAAM,QAAQ;AAExE,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,MAAM,MAAM,QAAQ;AAG1B,MAAI,MAAM,QAAQ,OAAO,IAAI,IAAI,SAC/B;EAIF,MAAM,OAAO,WAAW,GAAG,SAAS,GAAG,QAAQ;AAC/C,MAAI,KAAK,GAAG,UAAU,GAAG,IAAI,KAAK,MAAM,OAAO;;AAIjD,MAAK,MAAM,OAAO,MAAM,SAAS;EAC/B,MAAM,MAAM,MAAM,QAAQ;AAC1B,MAAI,IAAI,YAAY,CAAC,KAAK,SAAS,IAAI,EAAE;GACvC,MAAM,OAAO,WAAW,GAAG,SAAS,GAAG,QAAQ;AAC/C,OAAI,KAAK,GAAG,UAAU,GAAG,IAAI,KAAK,MAAM,OAAO;;;AAInD,QAAO;;;;;;;;;;;;AA2DT,SAAgB,aAAa,UAA0C;CACrE,MAAM,SAAS,MAAM,QAAQ,SAAS,GAAG,IAAI,IAAI,SAAS,GAAG;CAC7D,MAAMC,eAAyB,EAAE;AAEjC,QAAO;EACL,OAAO,KAAK;AACV,OAAI,WAAW,QAAQ,OAAO,IAAI,IAAI,CACpC;AAGF,UAAO,IAAI,IAAI;AACf,gBAAa,KAAK,IAAI;;EAExB,UAAU;AACR,UAAO;IACL,QAAQ,kBAAkB,MAAM,MAAM,KAAK,OAAO,GAAG;IACrD;IACA,mBAAmB,QAAQ;AACzB,UAAK,MAAM,OAAO,aAChB,QAAO,OAAO;AAEhB,YAAO;;IAEV;;EAEJ"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { buildWhere, fullSQLName } from "./where-builder.js";
|
|
2
|
+
import { extendSelect, mapSelect } from "./select-builder.js";
|
|
3
|
+
import { UnitOfWorkEncoder } from "../uow-encoder.js";
|
|
4
|
+
import { sql } from "kysely";
|
|
5
|
+
|
|
6
|
+
//#region src/adapters/generic-sql/query/sql-query-compiler.ts
|
|
7
|
+
/**
|
|
8
|
+
* Abstract base class for SQL query compilation.
|
|
9
|
+
*
|
|
10
|
+
* Similar to SQLGenerator for migrations, this class provides a framework
|
|
11
|
+
* for compiling runtime queries with dialect-specific behavior.
|
|
12
|
+
*
|
|
13
|
+
* Each database dialect extends this class and implements the abstract methods
|
|
14
|
+
* to handle database-specific SQL generation (like .limit() vs .top()).
|
|
15
|
+
*/
|
|
16
|
+
var SQLQueryCompiler = class {
|
|
17
|
+
db;
|
|
18
|
+
driverConfig;
|
|
19
|
+
database;
|
|
20
|
+
mapper;
|
|
21
|
+
encoder;
|
|
22
|
+
constructor(db, driverConfig, mapper) {
|
|
23
|
+
this.db = db;
|
|
24
|
+
this.driverConfig = driverConfig;
|
|
25
|
+
this.database = driverConfig.databaseType;
|
|
26
|
+
this.mapper = mapper;
|
|
27
|
+
this.encoder = new UnitOfWorkEncoder(driverConfig, db, mapper);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get the physical table name, applying namespace mapping if provided.
|
|
31
|
+
*/
|
|
32
|
+
getTableName(table) {
|
|
33
|
+
return this.mapper ? this.mapper.toPhysical(table.name) : table.name;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Build WHERE clause from a condition tree.
|
|
37
|
+
*/
|
|
38
|
+
buildWhereClause(condition, eb, table) {
|
|
39
|
+
return buildWhere(condition, eb, this.driverConfig, this.mapper, table);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Process joins recursively to support nested joins.
|
|
43
|
+
*/
|
|
44
|
+
processJoins(query, joins, parentTable, parentTableName, mappedSelect, parentPath = "") {
|
|
45
|
+
let result = query;
|
|
46
|
+
for (const join of joins) {
|
|
47
|
+
const { options: joinOptions, relation } = join;
|
|
48
|
+
if (joinOptions === false) continue;
|
|
49
|
+
const targetTable = relation.table;
|
|
50
|
+
const fullPath = parentPath ? `${parentPath}:${relation.name}` : relation.name;
|
|
51
|
+
const joinName = fullPath.replace(/:/g, "_");
|
|
52
|
+
mappedSelect.push(...mapSelect(joinOptions.select, targetTable, {
|
|
53
|
+
relation: fullPath,
|
|
54
|
+
tableName: joinName
|
|
55
|
+
}));
|
|
56
|
+
result = result.leftJoin(`${this.getTableName(targetTable)} as ${joinName}`, (b) => b.on((eb) => {
|
|
57
|
+
const conditions = [];
|
|
58
|
+
for (const [left, right] of relation.on) {
|
|
59
|
+
const actualRight = targetTable.columns[right]?.role === "external-id" ? "_internalId" : right;
|
|
60
|
+
conditions.push(eb(`${parentTableName}.${parentTable.columns[left].name}`, "=", eb.ref(`${joinName}.${targetTable.columns[actualRight].name}`)));
|
|
61
|
+
}
|
|
62
|
+
if (joinOptions.where) conditions.push(this.buildWhereClause(joinOptions.where, eb, targetTable));
|
|
63
|
+
return eb.and(conditions);
|
|
64
|
+
}));
|
|
65
|
+
if (joinOptions.join && joinOptions.join.length > 0) result = this.processJoins(result, joinOptions.join, targetTable, joinName, mappedSelect, fullPath);
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Compile a COUNT query.
|
|
71
|
+
*/
|
|
72
|
+
compileCount(table, options) {
|
|
73
|
+
let query = this.db.selectFrom(this.getTableName(table)).select(this.db.fn.countAll().as("count"));
|
|
74
|
+
if (options.where) query = query.where((b) => this.buildWhereClause(options.where, b, table));
|
|
75
|
+
return query.compile();
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Compile a FIND MANY query.
|
|
79
|
+
*/
|
|
80
|
+
compileFindMany(table, options) {
|
|
81
|
+
let query = this.db.selectFrom(this.getTableName(table));
|
|
82
|
+
const whereQuery = options.where;
|
|
83
|
+
if (whereQuery) query = query.where((eb) => this.buildWhereClause(whereQuery, eb, table));
|
|
84
|
+
if (options.offset !== void 0) query = this.applyOffset(query, options.offset);
|
|
85
|
+
if (options.limit !== void 0) query = this.applyLimit(query, options.limit);
|
|
86
|
+
if (options.orderBy) for (const [col, mode] of options.orderBy) query = query.orderBy(fullSQLName(col, this.mapper), mode);
|
|
87
|
+
const selectBuilder = extendSelect(options.select);
|
|
88
|
+
const mappedSelect = [];
|
|
89
|
+
if (options.join && options.join.length > 0) query = this.processJoins(query, options.join, table, this.getTableName(table), mappedSelect);
|
|
90
|
+
const compiledSelect = selectBuilder.compile();
|
|
91
|
+
mappedSelect.push(...mapSelect(compiledSelect.result, table, { tableName: this.getTableName(table) }));
|
|
92
|
+
return query.select(mappedSelect).compile();
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Compile a CREATE (INSERT) query.
|
|
96
|
+
*/
|
|
97
|
+
compileCreate(table, values) {
|
|
98
|
+
const encodedValues = this.encoder.encodeForDatabase({
|
|
99
|
+
values,
|
|
100
|
+
table,
|
|
101
|
+
generateDefaults: true
|
|
102
|
+
});
|
|
103
|
+
let insert = this.db.insertInto(this.getTableName(table)).values(encodedValues);
|
|
104
|
+
if (this.driverConfig.supportsReturning) {
|
|
105
|
+
const columns = mapSelect(true, table, { tableName: this.getTableName(table) });
|
|
106
|
+
insert = this.applyReturning(insert, columns);
|
|
107
|
+
}
|
|
108
|
+
return insert.compile();
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Compile an UPDATE query.
|
|
112
|
+
*/
|
|
113
|
+
compileUpdate(table, options) {
|
|
114
|
+
const encoded = this.encoder.encodeForDatabase({
|
|
115
|
+
values: options.set,
|
|
116
|
+
table,
|
|
117
|
+
generateDefaults: false
|
|
118
|
+
});
|
|
119
|
+
const versionCol = table.getVersionColumn();
|
|
120
|
+
encoded[versionCol.name] = sql.raw(`COALESCE(${versionCol.name}, 0) + 1`);
|
|
121
|
+
let query = this.db.updateTable(this.getTableName(table)).set(encoded);
|
|
122
|
+
if (options.where) query = query.where((eb) => this.buildWhereClause(options.where, eb, table));
|
|
123
|
+
if (options.returning && this.driverConfig.supportsReturning) return query.returning(sql`1`.as("_returned")).compile();
|
|
124
|
+
return query.compile();
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Compile a DELETE query.
|
|
128
|
+
*/
|
|
129
|
+
compileDelete(table, options) {
|
|
130
|
+
let query = this.db.deleteFrom(this.getTableName(table));
|
|
131
|
+
if (options.where) query = query.where((eb) => this.buildWhereClause(options.where, eb, table));
|
|
132
|
+
if (options.returning && this.driverConfig.supportsReturning) return query.returning(sql`1`.as("_returned")).compile();
|
|
133
|
+
return query.compile();
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Compile a CHECK query (SELECT 1 to verify a row exists).
|
|
137
|
+
*/
|
|
138
|
+
compileCheck(table, where) {
|
|
139
|
+
return this.db.selectFrom(this.getTableName(table)).select(sql`1`.as("exists")).where((eb) => this.buildWhereClause(where, eb, table)).limit(1).compile();
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
//#endregion
|
|
144
|
+
export { SQLQueryCompiler };
|
|
145
|
+
//# sourceMappingURL=sql-query-compiler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-query-compiler.js","names":["mappedSelect: string[]","insert: AnyInsertQueryBuilder"],"sources":["../../../../src/adapters/generic-sql/query/sql-query-compiler.ts"],"sourcesContent":["import type {\n CompiledQuery,\n Kysely,\n ExpressionBuilder,\n ExpressionWrapper,\n SelectQueryBuilder,\n InsertQueryBuilder,\n} from \"kysely\";\nimport { sql } from \"kysely\";\nimport type { SqlBool } from \"kysely\";\nimport type { AnyColumn, AnyTable } from \"../../../schema/create\";\nimport type { Condition } from \"../../../query/condition-builder\";\nimport type { DriverConfig, SupportedDatabase } from \"../driver-config\";\nimport type { TableNameMapper } from \"../../shared/table-name-mapper\";\nimport { buildWhere, fullSQLName } from \"./where-builder\";\nimport { mapSelect, extendSelect } from \"./select-builder\";\nimport type { CompiledJoin } from \"../../../query/orm/orm\";\nimport { UnitOfWorkEncoder } from \"../uow-encoder\";\n\n/**\n * Type helpers for Kysely query builders.\n *\n * These use `any` for database schema types because at this abstraction layer,\n * we cannot know the specific database schema - we work with generic query\n * compilation that needs to work across any schema.\n */\n\n// oxlint-disable-next-line no-explicit-any\nexport type AnyKysely = Kysely<any>;\n\n// oxlint-disable-next-line no-explicit-any\nexport type AnyExpressionBuilder = ExpressionBuilder<any, any>;\n\n// oxlint-disable-next-line no-explicit-any\nexport type AnyExpressionWrapper = ExpressionWrapper<any, any, SqlBool>;\n\n// oxlint-disable-next-line no-explicit-any\nexport type AnySelectQueryBuilder<O = any> = SelectQueryBuilder<any, any, O>;\n\n// oxlint-disable-next-line no-explicit-any\nexport type AnyInsertQueryBuilder<O = any> = InsertQueryBuilder<any, any, O>;\n\n/**\n * Options for compiling a find operation\n */\nexport interface FindManyCompilerOptions {\n select: true | string[];\n where?: Condition;\n orderBy?: [AnyColumn, \"asc\" | \"desc\"][];\n limit?: number;\n offset?: number;\n join?: CompiledJoin[];\n}\n\n/**\n * Options for compiling a count operation\n */\nexport interface CountCompilerOptions {\n where?: Condition;\n}\n\n/**\n * Options for compiling an update operation\n */\nexport interface UpdateCompilerOptions {\n where?: Condition;\n set: Record<string, unknown>;\n /**\n * Whether to add RETURNING clause to the UPDATE query.\n * Used for version conflict detection when driver supports RETURNING but not affected rows.\n */\n returning?: boolean;\n}\n\n/**\n * Options for compiling a delete operation\n */\nexport interface DeleteCompilerOptions {\n where?: Condition;\n /**\n * Whether to add RETURNING clause to the DELETE query.\n * Used for version conflict detection when driver supports RETURNING but not affected rows.\n */\n returning?: boolean;\n}\n\n/**\n * Abstract base class for SQL query compilation.\n *\n * Similar to SQLGenerator for migrations, this class provides a framework\n * for compiling runtime queries with dialect-specific behavior.\n *\n * Each database dialect extends this class and implements the abstract methods\n * to handle database-specific SQL generation (like .limit() vs .top()).\n */\nexport abstract class SQLQueryCompiler {\n protected readonly db: AnyKysely;\n protected readonly driverConfig: DriverConfig;\n protected readonly database: SupportedDatabase;\n protected readonly mapper?: TableNameMapper;\n protected readonly encoder: UnitOfWorkEncoder;\n\n constructor(db: AnyKysely, driverConfig: DriverConfig, mapper?: TableNameMapper) {\n this.db = db;\n this.driverConfig = driverConfig;\n this.database = driverConfig.databaseType;\n this.mapper = mapper;\n this.encoder = new UnitOfWorkEncoder(driverConfig, db, mapper);\n }\n\n /**\n * Apply LIMIT clause to a query.\n * Different databases use different syntax (.limit() vs .top()).\n */\n protected abstract applyLimit<T>(query: T & { limit(limit: number): T }, limit: number): T;\n\n /**\n * Apply OFFSET clause to a query.\n * Some databases may not support offset.\n */\n protected abstract applyOffset<T>(query: T & { offset(offset: number): T }, offset: number): T;\n\n /**\n * Apply RETURNING clause to an insert/update query.\n * Returns the query with RETURNING if supported, otherwise returns as-is.\n */\n protected abstract applyReturning<T>(\n query: T & { returning(columns: string[]): T },\n columns: string[],\n ): T;\n\n /**\n * Get the physical table name, applying namespace mapping if provided.\n */\n protected getTableName(table: AnyTable): string {\n return this.mapper ? this.mapper.toPhysical(table.name) : table.name;\n }\n\n /**\n * Build WHERE clause from a condition tree.\n */\n protected buildWhereClause(condition: Condition, eb: AnyExpressionBuilder, table: AnyTable) {\n return buildWhere(condition, eb, this.driverConfig, this.mapper, table);\n }\n\n /**\n * Process joins recursively to support nested joins.\n */\n protected processJoins<O>(\n query: AnySelectQueryBuilder<O>,\n joins: CompiledJoin[],\n parentTable: AnyTable,\n parentTableName: string,\n mappedSelect: string[],\n parentPath: string = \"\",\n ): AnySelectQueryBuilder<O> {\n let result = query;\n\n for (const join of joins) {\n const { options: joinOptions, relation } = join;\n\n if (joinOptions === false) {\n continue;\n }\n\n const targetTable = relation.table;\n // Build the full path for this join (e.g., \"author:inviter\")\n const fullPath = parentPath ? `${parentPath}:${relation.name}` : relation.name;\n // SQL table alias uses underscores (e.g., \"author_inviter\")\n const joinName = fullPath.replace(/:/g, \"_\");\n\n // Update select\n mappedSelect.push(\n ...mapSelect(joinOptions.select, targetTable, {\n relation: fullPath, // Use full path with colons for column aliases\n tableName: joinName, // Use underscore version for table name\n }),\n );\n\n result = result.leftJoin(`${this.getTableName(targetTable)} as ${joinName}`, (b) =>\n b.on((eb) => {\n const conditions = [];\n for (const [left, right] of relation.on) {\n // Foreign keys always use internal IDs\n // If the relation references an external ID column (any name), translate to \"_internalId\"\n const rightCol = targetTable.columns[right];\n const actualRight = rightCol?.role === \"external-id\" ? \"_internalId\" : right;\n\n conditions.push(\n eb(\n `${parentTableName}.${parentTable.columns[left].name}`,\n \"=\",\n eb.ref(`${joinName}.${targetTable.columns[actualRight].name}`),\n ),\n );\n }\n\n if (joinOptions.where) {\n conditions.push(this.buildWhereClause(joinOptions.where, eb, targetTable));\n }\n\n return eb.and(conditions);\n }),\n );\n\n // Recursively process nested joins with the full path\n if (joinOptions.join && joinOptions.join.length > 0) {\n result = this.processJoins(\n result,\n joinOptions.join,\n targetTable,\n joinName,\n mappedSelect,\n fullPath,\n );\n }\n }\n\n return result;\n }\n\n /**\n * Compile a COUNT query.\n */\n compileCount(table: AnyTable, options: CountCompilerOptions): CompiledQuery {\n let query = this.db\n .selectFrom(this.getTableName(table))\n .select(this.db.fn.countAll().as(\"count\"));\n\n if (options.where) {\n query = query.where((b) => this.buildWhereClause(options.where!, b, table));\n }\n\n return query.compile();\n }\n\n /**\n * Compile a FIND MANY query.\n */\n compileFindMany(table: AnyTable, options: FindManyCompilerOptions): CompiledQuery {\n let query = this.db.selectFrom(this.getTableName(table));\n\n // Apply WHERE clause\n const whereQuery = options.where;\n if (whereQuery) {\n query = query.where((eb) => this.buildWhereClause(whereQuery, eb, table));\n }\n\n // Apply OFFSET\n if (options.offset !== undefined) {\n query = this.applyOffset(query, options.offset);\n }\n\n // Apply LIMIT\n if (options.limit !== undefined) {\n query = this.applyLimit(query, options.limit);\n }\n\n // Apply ORDER BY\n if (options.orderBy) {\n for (const [col, mode] of options.orderBy) {\n query = query.orderBy(fullSQLName(col, this.mapper), mode);\n }\n }\n\n // Build SELECT with joins\n const selectBuilder = extendSelect(options.select);\n const mappedSelect: string[] = [];\n\n // Process joins if provided\n if (options.join && options.join.length > 0) {\n query = this.processJoins(query, options.join, table, this.getTableName(table), mappedSelect);\n }\n\n const compiledSelect = selectBuilder.compile();\n mappedSelect.push(\n ...mapSelect(compiledSelect.result, table, { tableName: this.getTableName(table) }),\n );\n\n return query.select(mappedSelect).compile();\n }\n\n /**\n * Compile a CREATE (INSERT) query.\n */\n compileCreate(table: AnyTable, values: Record<string, unknown>): CompiledQuery {\n // Encode application values to database format (resolves FragnoId, generates defaults, serializes)\n const encodedValues = this.encoder.encodeForDatabase({\n values,\n table,\n generateDefaults: true,\n });\n\n let insert: AnyInsertQueryBuilder = this.db\n .insertInto(this.getTableName(table))\n .values(encodedValues);\n\n // Apply RETURNING if supported\n if (this.driverConfig.supportsReturning) {\n const columns = mapSelect(true, table, { tableName: this.getTableName(table) });\n insert = this.applyReturning(insert, columns);\n }\n\n return insert.compile();\n }\n\n /**\n * Compile an UPDATE query.\n */\n compileUpdate(table: AnyTable, options: UpdateCompilerOptions): CompiledQuery {\n const encoded = this.encoder.encodeForDatabase({\n values: options.set,\n table,\n generateDefaults: false,\n });\n\n // Add version increment (must be added after encoding, as a raw SQL expression)\n const versionCol = table.getVersionColumn();\n encoded[versionCol.name] = sql.raw(`COALESCE(${versionCol.name}, 0) + 1`);\n\n let query = this.db.updateTable(this.getTableName(table)).set(encoded);\n\n if (options.where) {\n query = query.where((eb) => this.buildWhereClause(options.where!, eb, table));\n }\n\n // Apply RETURNING if requested and supported\n // Use sql template tag for literal value (not a column name)\n if (options.returning && this.driverConfig.supportsReturning) {\n return query.returning(sql<number>`1`.as(\"_returned\")).compile();\n }\n\n return query.compile();\n }\n\n /**\n * Compile a DELETE query.\n */\n compileDelete(table: AnyTable, options: DeleteCompilerOptions): CompiledQuery {\n let query = this.db.deleteFrom(this.getTableName(table));\n\n if (options.where) {\n query = query.where((eb) => this.buildWhereClause(options.where!, eb, table));\n }\n\n // Apply RETURNING if requested and supported\n // Use sql template tag for literal value (not a column name)\n if (options.returning && this.driverConfig.supportsReturning) {\n return query.returning(sql<number>`1`.as(\"_returned\")).compile();\n }\n\n return query.compile();\n }\n\n /**\n * Compile a CHECK query (SELECT 1 to verify a row exists).\n */\n compileCheck(table: AnyTable, where: Condition): CompiledQuery {\n const query = this.db\n .selectFrom(this.getTableName(table))\n .select(sql<number>`1`.as(\"exists\"))\n .where((eb) => this.buildWhereClause(where, eb, table))\n .limit(1);\n\n return query.compile();\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { Column, FragnoId, FragnoReference } from "../../../schema/create.js";
|
|
2
|
+
import { createSQLSerializer } from "../../../query/serialize/create-sql-serializer.js";
|
|
3
|
+
import { ReferenceSubquery, resolveFragnoIdValue } from "../../../query/value-encoding.js";
|
|
4
|
+
import { sql } from "kysely";
|
|
5
|
+
|
|
6
|
+
//#region src/adapters/generic-sql/query/where-builder.ts
|
|
7
|
+
/**
|
|
8
|
+
* Returns the fully qualified SQL name for a column (table.column).
|
|
9
|
+
*
|
|
10
|
+
* @param column - The column to get the full name for
|
|
11
|
+
* @param mapper - Optional table name mapper for namespace prefixing
|
|
12
|
+
* @returns The fully qualified SQL name in the format "tableName.columnName"
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
function fullSQLName(column, mapper) {
|
|
16
|
+
return `${mapper ? mapper.toPhysical(column.tableName) : column.tableName}.${column.name}`;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Builds a WHERE clause expression from a Condition tree.
|
|
20
|
+
*
|
|
21
|
+
* Recursively processes condition objects to build Kysely WHERE expressions.
|
|
22
|
+
* Handles comparison operators, logical AND/OR/NOT, and special string operators
|
|
23
|
+
* like "contains", "starts with", and "ends with".
|
|
24
|
+
*
|
|
25
|
+
* @param condition - The condition tree to build the WHERE clause from
|
|
26
|
+
* @param eb - Kysely expression builder for constructing SQL expressions
|
|
27
|
+
* @param database - The database type (affects SQL generation)
|
|
28
|
+
* @param mapper - Optional table name mapper for namespace prefixing
|
|
29
|
+
* @param table - The table being queried (used for resolving reference columns)
|
|
30
|
+
* @returns A Kysely expression wrapper representing the WHERE clause
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
function buildWhere(condition, eb, driverConfig, mapper, table) {
|
|
34
|
+
const serializer = createSQLSerializer(driverConfig);
|
|
35
|
+
if (condition.type === "compare") {
|
|
36
|
+
const left = condition.a;
|
|
37
|
+
const op = condition.operator;
|
|
38
|
+
let val = condition.b;
|
|
39
|
+
if (!(val instanceof Column)) if (left.role === "reference" && table) if (typeof val === "string") {
|
|
40
|
+
const relation = Object.values(table.relations).find((rel) => rel.on.some(([localCol]) => localCol === left.ormName));
|
|
41
|
+
if (relation) {
|
|
42
|
+
const refTable = relation.table;
|
|
43
|
+
const internalIdCol = refTable.getInternalIdColumn();
|
|
44
|
+
const idCol = refTable.getIdColumn();
|
|
45
|
+
const physicalTableName = mapper ? mapper.toPhysical(refTable.ormName) : refTable.ormName;
|
|
46
|
+
val = eb.selectFrom(physicalTableName).select(internalIdCol.name).where(idCol.name, "=", val).limit(1);
|
|
47
|
+
}
|
|
48
|
+
} else if (val instanceof FragnoId && val.internalId !== void 0) val = val.internalId;
|
|
49
|
+
else if (val instanceof FragnoId && val.internalId === void 0) {
|
|
50
|
+
const relation = Object.values(table.relations).find((rel) => rel.on.some(([localCol]) => localCol === left.ormName));
|
|
51
|
+
if (relation) {
|
|
52
|
+
const refTable = relation.table;
|
|
53
|
+
const internalIdCol = refTable.getInternalIdColumn();
|
|
54
|
+
const idCol = refTable.getIdColumn();
|
|
55
|
+
const physicalTableName = mapper ? mapper.toPhysical(refTable.ormName) : refTable.ormName;
|
|
56
|
+
val = eb.selectFrom(physicalTableName).select(internalIdCol.name).where(idCol.name, "=", val.externalId).limit(1);
|
|
57
|
+
}
|
|
58
|
+
} else if (val instanceof FragnoReference) val = val.internalId;
|
|
59
|
+
else {
|
|
60
|
+
const resolvedVal = resolveFragnoIdValue(val, left);
|
|
61
|
+
val = serializer.serialize(resolvedVal, left);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
const resolvedVal = resolveFragnoIdValue(val, left);
|
|
65
|
+
val = serializer.serialize(resolvedVal, left);
|
|
66
|
+
}
|
|
67
|
+
let v;
|
|
68
|
+
let rhs;
|
|
69
|
+
switch (op) {
|
|
70
|
+
case "contains":
|
|
71
|
+
v = "like";
|
|
72
|
+
rhs = val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))}, '%')` : `%${val}%`;
|
|
73
|
+
break;
|
|
74
|
+
case "not contains":
|
|
75
|
+
v = "not like";
|
|
76
|
+
rhs = val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))}, '%')` : `%${val}%`;
|
|
77
|
+
break;
|
|
78
|
+
case "starts with":
|
|
79
|
+
v = "like";
|
|
80
|
+
rhs = val instanceof Column ? sql`concat(${eb.ref(fullSQLName(val, mapper))}, '%')` : `${val}%`;
|
|
81
|
+
break;
|
|
82
|
+
case "not starts with":
|
|
83
|
+
v = "not like";
|
|
84
|
+
rhs = val instanceof Column ? sql`concat(${eb.ref(fullSQLName(val, mapper))}, '%')` : `${val}%`;
|
|
85
|
+
break;
|
|
86
|
+
case "ends with":
|
|
87
|
+
v = "like";
|
|
88
|
+
rhs = val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))})` : `%${val}`;
|
|
89
|
+
break;
|
|
90
|
+
case "not ends with":
|
|
91
|
+
v = "not like";
|
|
92
|
+
rhs = val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))})` : `%${val}`;
|
|
93
|
+
break;
|
|
94
|
+
default:
|
|
95
|
+
v = op;
|
|
96
|
+
rhs = val instanceof Column ? eb.ref(fullSQLName(val, mapper)) : val;
|
|
97
|
+
}
|
|
98
|
+
return eb(fullSQLName(left, mapper), v, rhs);
|
|
99
|
+
}
|
|
100
|
+
if (condition.type === "and") return eb.and(condition.items.map((v) => buildWhere(v, eb, driverConfig, mapper, table)));
|
|
101
|
+
if (condition.type === "not") return eb.not(buildWhere(condition.item, eb, driverConfig, mapper, table));
|
|
102
|
+
return eb.or(condition.items.map((v) => buildWhere(v, eb, driverConfig, mapper, table)));
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Process reference subqueries in encoded values, converting them to Kysely SQL subqueries
|
|
106
|
+
*
|
|
107
|
+
* @param values - The encoded values that may contain ReferenceSubquery objects
|
|
108
|
+
* @param kysely - The Kysely database instance for building subqueries
|
|
109
|
+
* @param mapper - Optional table name mapper for namespace prefixing
|
|
110
|
+
* @returns Processed values with subqueries in place of ReferenceSubquery markers
|
|
111
|
+
* @internal
|
|
112
|
+
*/
|
|
113
|
+
function processReferenceSubqueries(values, kysely, mapper) {
|
|
114
|
+
const processed = {};
|
|
115
|
+
const getTableName = (table) => mapper ? mapper.toPhysical(table.name) : table.name;
|
|
116
|
+
for (const [key, value] of Object.entries(values)) if (value instanceof ReferenceSubquery) {
|
|
117
|
+
const refTable = value.referencedTable;
|
|
118
|
+
const externalId = value.externalIdValue;
|
|
119
|
+
const tableName = getTableName(refTable);
|
|
120
|
+
const internalIdCol = refTable.getInternalIdColumn().name;
|
|
121
|
+
const idCol = refTable.getIdColumn().name;
|
|
122
|
+
processed[key] = kysely.selectFrom(tableName).select(internalIdCol).where(idCol, "=", externalId).limit(1);
|
|
123
|
+
} else processed[key] = value;
|
|
124
|
+
return processed;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
//#endregion
|
|
128
|
+
export { buildWhere, fullSQLName, processReferenceSubqueries };
|
|
129
|
+
//# sourceMappingURL=where-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"where-builder.js","names":["v: BinaryOperator","rhs: unknown","processed: Record<string, unknown>"],"sources":["../../../../src/adapters/generic-sql/query/where-builder.ts"],"sourcesContent":["import { sql, type BinaryOperator } from \"kysely\";\nimport {\n type AnyColumn,\n type AnyTable,\n Column,\n FragnoId,\n FragnoReference,\n} from \"../../../schema/create\";\nimport type { Condition } from \"../../../query/condition-builder\";\nimport { createSQLSerializer } from \"../../../query/serialize/create-sql-serializer\";\nimport type { TableNameMapper } from \"../../shared/table-name-mapper\";\nimport type { DriverConfig } from \"../driver-config\";\nimport { ReferenceSubquery, resolveFragnoIdValue } from \"../../../query/value-encoding\";\nimport type { AnyKysely, AnyExpressionBuilder, AnyExpressionWrapper } from \"./sql-query-compiler\";\n\n/**\n * Returns the fully qualified SQL name for a column (table.column).\n *\n * @param column - The column to get the full name for\n * @param mapper - Optional table name mapper for namespace prefixing\n * @returns The fully qualified SQL name in the format \"tableName.columnName\"\n * @internal\n */\nexport function fullSQLName(column: AnyColumn, mapper?: TableNameMapper): string {\n const tableName = mapper ? mapper.toPhysical(column.tableName) : column.tableName;\n return `${tableName}.${column.name}`;\n}\n\n/**\n * Builds a WHERE clause expression from a Condition tree.\n *\n * Recursively processes condition objects to build Kysely WHERE expressions.\n * Handles comparison operators, logical AND/OR/NOT, and special string operators\n * like \"contains\", \"starts with\", and \"ends with\".\n *\n * @param condition - The condition tree to build the WHERE clause from\n * @param eb - Kysely expression builder for constructing SQL expressions\n * @param database - The database type (affects SQL generation)\n * @param mapper - Optional table name mapper for namespace prefixing\n * @param table - The table being queried (used for resolving reference columns)\n * @returns A Kysely expression wrapper representing the WHERE clause\n * @internal\n */\nexport function buildWhere(\n condition: Condition,\n eb: AnyExpressionBuilder,\n driverConfig: DriverConfig,\n mapper?: TableNameMapper,\n table?: AnyTable,\n): AnyExpressionWrapper {\n const serializer = createSQLSerializer(driverConfig);\n\n if (condition.type === \"compare\") {\n const left = condition.a;\n const op = condition.operator;\n let val = condition.b;\n\n if (!(val instanceof Column)) {\n // Handle reference columns specially\n if (left.role === \"reference\" && table) {\n if (typeof val === \"string\") {\n // String external ID - create subquery to lookup internal ID\n const relation = Object.values(table.relations).find((rel) =>\n rel.on.some(([localCol]) => localCol === left.ormName),\n );\n if (relation) {\n const refTable = relation.table;\n const internalIdCol = refTable.getInternalIdColumn();\n const idCol = refTable.getIdColumn();\n const physicalTableName = mapper\n ? mapper.toPhysical(refTable.ormName)\n : refTable.ormName;\n\n val = eb\n .selectFrom(physicalTableName)\n .select(internalIdCol.name)\n .where(idCol.name, \"=\", val)\n .limit(1);\n }\n } else if (val instanceof FragnoId && val.internalId !== undefined) {\n // FragnoId with internal ID - use it directly (no serialization needed)\n val = val.internalId;\n } else if (val instanceof FragnoId && val.internalId === undefined) {\n // FragnoId without internal ID - create subquery using external ID\n const relation = Object.values(table.relations).find((rel) =>\n rel.on.some(([localCol]) => localCol === left.ormName),\n );\n if (relation) {\n const refTable = relation.table;\n const internalIdCol = refTable.getInternalIdColumn();\n const idCol = refTable.getIdColumn();\n const physicalTableName = mapper\n ? mapper.toPhysical(refTable.ormName)\n : refTable.ormName;\n\n val = eb\n .selectFrom(physicalTableName)\n .select(internalIdCol.name)\n .where(idCol.name, \"=\", val.externalId)\n .limit(1);\n }\n } else if (val instanceof FragnoReference) {\n // FragnoReference - use internal ID directly (no serialization needed)\n val = val.internalId;\n } else {\n // Other values - resolve and serialize\n const resolvedVal = resolveFragnoIdValue(val, left);\n val = serializer.serialize(resolvedVal, left);\n }\n } else {\n // Non-reference columns - resolve FragnoId/FragnoReference and serialize\n const resolvedVal = resolveFragnoIdValue(val, left);\n val = serializer.serialize(resolvedVal, left);\n }\n }\n\n let v: BinaryOperator;\n let rhs: unknown;\n\n switch (op) {\n case \"contains\":\n v = \"like\";\n rhs =\n val instanceof Column\n ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))}, '%')`\n : `%${val}%`;\n break;\n case \"not contains\":\n v = \"not like\";\n rhs =\n val instanceof Column\n ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))}, '%')`\n : `%${val}%`;\n break;\n case \"starts with\":\n v = \"like\";\n rhs =\n val instanceof Column ? sql`concat(${eb.ref(fullSQLName(val, mapper))}, '%')` : `${val}%`;\n break;\n case \"not starts with\":\n v = \"not like\";\n rhs =\n val instanceof Column ? sql`concat(${eb.ref(fullSQLName(val, mapper))}, '%')` : `${val}%`;\n break;\n case \"ends with\":\n v = \"like\";\n rhs =\n val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))})` : `%${val}`;\n break;\n case \"not ends with\":\n v = \"not like\";\n rhs =\n val instanceof Column ? sql`concat('%', ${eb.ref(fullSQLName(val, mapper))})` : `%${val}`;\n break;\n default:\n v = op;\n rhs = val instanceof Column ? eb.ref(fullSQLName(val, mapper)) : val;\n }\n\n return eb(fullSQLName(left, mapper), v, rhs);\n }\n\n // Nested conditions\n if (condition.type === \"and\") {\n return eb.and(condition.items.map((v) => buildWhere(v, eb, driverConfig, mapper, table)));\n }\n\n if (condition.type === \"not\") {\n return eb.not(buildWhere(condition.item, eb, driverConfig, mapper, table));\n }\n\n return eb.or(condition.items.map((v) => buildWhere(v, eb, driverConfig, mapper, table)));\n}\n\n/**\n * Process reference subqueries in encoded values, converting them to Kysely SQL subqueries\n *\n * @param values - The encoded values that may contain ReferenceSubquery objects\n * @param kysely - The Kysely database instance for building subqueries\n * @param mapper - Optional table name mapper for namespace prefixing\n * @returns Processed values with subqueries in place of ReferenceSubquery markers\n * @internal\n */\nexport function processReferenceSubqueries(\n values: Record<string, unknown>,\n kysely: AnyKysely,\n mapper?: TableNameMapper,\n): Record<string, unknown> {\n const processed: Record<string, unknown> = {};\n const getTableName = (table: AnyTable) => (mapper ? mapper.toPhysical(table.name) : table.name);\n\n for (const [key, value] of Object.entries(values)) {\n if (value instanceof ReferenceSubquery) {\n const refTable = value.referencedTable;\n const externalId = value.externalIdValue;\n const tableName = getTableName(refTable);\n const internalIdCol = refTable.getInternalIdColumn().name;\n const idCol = refTable.getIdColumn().name;\n\n processed[key] = kysely\n .selectFrom(tableName)\n .select(internalIdCol)\n .where(idCol, \"=\", externalId)\n .limit(1);\n } else {\n processed[key] = value;\n }\n }\n\n return processed;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
//#region src/adapters/generic-sql/result-interpreter.ts
|
|
2
|
+
/**
|
|
3
|
+
* Interprets query results from different SQL drivers.
|
|
4
|
+
*
|
|
5
|
+
* Different drivers return affected rows information in different formats.
|
|
6
|
+
* This class uses the driver-specific extraction logic defined in DriverConfig
|
|
7
|
+
* to normalize the affected rows count to a bigint value.
|
|
8
|
+
*/
|
|
9
|
+
var ResultInterpreter = class {
|
|
10
|
+
#driverConfig;
|
|
11
|
+
constructor(driverConfig) {
|
|
12
|
+
this.#driverConfig = driverConfig;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Extract the number of affected rows from a query result.
|
|
16
|
+
* Only works for drivers that support affected rows reporting.
|
|
17
|
+
*
|
|
18
|
+
* @param result - The query result from the SQL driver
|
|
19
|
+
* @returns The number of rows affected by the operation as bigint
|
|
20
|
+
* @throws Error if driver doesn't support affected rows or extraction fails
|
|
21
|
+
*/
|
|
22
|
+
getAffectedRows(result) {
|
|
23
|
+
if (!this.#driverConfig.extractAffectedRows) throw new Error(`Driver ${this.#driverConfig.driverType} does not support affected rows reporting.`);
|
|
24
|
+
return this.#driverConfig.extractAffectedRows(result);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Extract internal ID from INSERT result (RETURNING clause).
|
|
28
|
+
*
|
|
29
|
+
* @param result - The query result from the SQL driver
|
|
30
|
+
* @returns The internal ID as bigint
|
|
31
|
+
* @throws Error if driver doesn't support RETURNING, no rows returned, or column not found
|
|
32
|
+
*/
|
|
33
|
+
getCreatedInternalId(result) {
|
|
34
|
+
if (!this.#driverConfig.supportsReturning || !this.#driverConfig.internalIdColumn) throw new Error(`Driver ${this.#driverConfig.driverType} does not support RETURNING clause.`);
|
|
35
|
+
if (!Array.isArray(result.rows) || result.rows.length === 0) throw new Error(`No rows returned from INSERT with RETURNING clause.`);
|
|
36
|
+
const row = result.rows[0];
|
|
37
|
+
const columnName = this.#driverConfig.internalIdColumn;
|
|
38
|
+
if (!(columnName in row)) throw new Error(`Expected column "${columnName}" not found in RETURNING result.`);
|
|
39
|
+
const rawId = row[columnName];
|
|
40
|
+
return this.#normalizeIntegerId(rawId);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get count of returned rows as bigint.
|
|
44
|
+
*
|
|
45
|
+
* @param result - The query result from the SQL driver
|
|
46
|
+
* @returns The number of rows returned as bigint
|
|
47
|
+
*/
|
|
48
|
+
getReturnedRowCount(result) {
|
|
49
|
+
if (!Array.isArray(result.rows)) return BigInt(0);
|
|
50
|
+
return BigInt(result.rows.length);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Normalize integer values to bigint.
|
|
54
|
+
* Handles different driver return types (bigint, number, string).
|
|
55
|
+
*
|
|
56
|
+
* @param value - The value to normalize
|
|
57
|
+
* @returns The normalized bigint value
|
|
58
|
+
* @throws Error if value cannot be converted to bigint
|
|
59
|
+
*/
|
|
60
|
+
#normalizeIntegerId(value) {
|
|
61
|
+
if (value === null || value === void 0) throw new Error(`Cannot normalize null or undefined value to bigint`);
|
|
62
|
+
if (typeof value === "bigint") return value;
|
|
63
|
+
if (typeof value === "number") {
|
|
64
|
+
if (Number.isNaN(value) || !Number.isFinite(value)) throw new Error(`Cannot normalize NaN or non-finite number to bigint`);
|
|
65
|
+
return BigInt(value);
|
|
66
|
+
}
|
|
67
|
+
if (typeof value === "string") return BigInt(value);
|
|
68
|
+
throw new Error(`Cannot normalize value to bigint: ${typeof value}`);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
//#endregion
|
|
73
|
+
export { ResultInterpreter };
|
|
74
|
+
//# sourceMappingURL=result-interpreter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-interpreter.js","names":["#driverConfig","#normalizeIntegerId"],"sources":["../../../src/adapters/generic-sql/result-interpreter.ts"],"sourcesContent":["import type { QueryResult } from \"../../sql-driver/sql-driver\";\nimport type { DriverConfig } from \"./driver-config\";\n\n/**\n * Interprets query results from different SQL drivers.\n *\n * Different drivers return affected rows information in different formats.\n * This class uses the driver-specific extraction logic defined in DriverConfig\n * to normalize the affected rows count to a bigint value.\n */\nexport class ResultInterpreter {\n readonly #driverConfig: DriverConfig;\n constructor(driverConfig: DriverConfig) {\n this.#driverConfig = driverConfig;\n }\n\n /**\n * Extract the number of affected rows from a query result.\n * Only works for drivers that support affected rows reporting.\n *\n * @param result - The query result from the SQL driver\n * @returns The number of rows affected by the operation as bigint\n * @throws Error if driver doesn't support affected rows or extraction fails\n */\n getAffectedRows(result: QueryResult<unknown>): bigint {\n if (!this.#driverConfig.extractAffectedRows) {\n throw new Error(\n `Driver ${this.#driverConfig.driverType} does not support affected rows reporting.`,\n );\n }\n\n // QueryResult doesn't have an index signature, but drivers return objects with dynamic properties\n return this.#driverConfig.extractAffectedRows(result as unknown as Record<string, unknown>);\n }\n\n /**\n * Extract internal ID from INSERT result (RETURNING clause).\n *\n * @param result - The query result from the SQL driver\n * @returns The internal ID as bigint\n * @throws Error if driver doesn't support RETURNING, no rows returned, or column not found\n */\n getCreatedInternalId(result: QueryResult<unknown>): bigint {\n if (!this.#driverConfig.supportsReturning || !this.#driverConfig.internalIdColumn) {\n throw new Error(`Driver ${this.#driverConfig.driverType} does not support RETURNING clause.`);\n }\n\n if (!Array.isArray(result.rows) || result.rows.length === 0) {\n throw new Error(`No rows returned from INSERT with RETURNING clause.`);\n }\n\n const row = result.rows[0] as Record<string, unknown>;\n const columnName = this.#driverConfig.internalIdColumn;\n\n if (!(columnName in row)) {\n throw new Error(`Expected column \"${columnName}\" not found in RETURNING result.`);\n }\n\n const rawId = row[columnName];\n return this.#normalizeIntegerId(rawId);\n }\n\n /**\n * Get count of returned rows as bigint.\n *\n * @param result - The query result from the SQL driver\n * @returns The number of rows returned as bigint\n */\n getReturnedRowCount(result: QueryResult<unknown>): bigint {\n if (!Array.isArray(result.rows)) {\n return BigInt(0);\n }\n return BigInt(result.rows.length);\n }\n\n /**\n * Normalize integer values to bigint.\n * Handles different driver return types (bigint, number, string).\n *\n * @param value - The value to normalize\n * @returns The normalized bigint value\n * @throws Error if value cannot be converted to bigint\n */\n #normalizeIntegerId(value: unknown): bigint {\n if (value === null || value === undefined) {\n throw new Error(`Cannot normalize null or undefined value to bigint`);\n }\n if (typeof value === \"bigint\") {\n return value;\n }\n if (typeof value === \"number\") {\n if (Number.isNaN(value) || !Number.isFinite(value)) {\n throw new Error(`Cannot normalize NaN or non-finite number to bigint`);\n }\n return BigInt(value);\n }\n if (typeof value === \"string\") {\n return BigInt(value);\n }\n throw new Error(`Cannot normalize value to bigint: ${typeof value}`);\n }\n}\n"],"mappings":";;;;;;;;AAUA,IAAa,oBAAb,MAA+B;CAC7B,CAASA;CACT,YAAY,cAA4B;AACtC,QAAKA,eAAgB;;;;;;;;;;CAWvB,gBAAgB,QAAsC;AACpD,MAAI,CAAC,MAAKA,aAAc,oBACtB,OAAM,IAAI,MACR,UAAU,MAAKA,aAAc,WAAW,4CACzC;AAIH,SAAO,MAAKA,aAAc,oBAAoB,OAA6C;;;;;;;;;CAU7F,qBAAqB,QAAsC;AACzD,MAAI,CAAC,MAAKA,aAAc,qBAAqB,CAAC,MAAKA,aAAc,iBAC/D,OAAM,IAAI,MAAM,UAAU,MAAKA,aAAc,WAAW,qCAAqC;AAG/F,MAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,IAAI,OAAO,KAAK,WAAW,EACxD,OAAM,IAAI,MAAM,sDAAsD;EAGxE,MAAM,MAAM,OAAO,KAAK;EACxB,MAAM,aAAa,MAAKA,aAAc;AAEtC,MAAI,EAAE,cAAc,KAClB,OAAM,IAAI,MAAM,oBAAoB,WAAW,kCAAkC;EAGnF,MAAM,QAAQ,IAAI;AAClB,SAAO,MAAKC,mBAAoB,MAAM;;;;;;;;CASxC,oBAAoB,QAAsC;AACxD,MAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,CAC7B,QAAO,OAAO,EAAE;AAElB,SAAO,OAAO,OAAO,KAAK,OAAO;;;;;;;;;;CAWnC,oBAAoB,OAAwB;AAC1C,MAAI,UAAU,QAAQ,UAAU,OAC9B,OAAM,IAAI,MAAM,qDAAqD;AAEvE,MAAI,OAAO,UAAU,SACnB,QAAO;AAET,MAAI,OAAO,UAAU,UAAU;AAC7B,OAAI,OAAO,MAAM,MAAM,IAAI,CAAC,OAAO,SAAS,MAAM,CAChD,OAAM,IAAI,MAAM,sDAAsD;AAExE,UAAO,OAAO,MAAM;;AAEtB,MAAI,OAAO,UAAU,SACnB,QAAO,OAAO,MAAM;AAEtB,QAAM,IAAI,MAAM,qCAAqC,OAAO,QAAQ"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { createCursorFromRecord } from "../../query/cursor.js";
|
|
2
|
+
import { decodeResult } from "../../query/value-decoding.js";
|
|
3
|
+
|
|
4
|
+
//#region src/adapters/generic-sql/uow-decoder.ts
|
|
5
|
+
/**
|
|
6
|
+
* Decoder class for Unit of Work retrieval results.
|
|
7
|
+
*
|
|
8
|
+
* Transforms raw database results into application format (e.g., converting raw columns
|
|
9
|
+
* into FragnoId objects with external ID, internal ID, and version).
|
|
10
|
+
*/
|
|
11
|
+
var UnitOfWorkDecoder = class {
|
|
12
|
+
#driverConfig;
|
|
13
|
+
constructor(driverConfig) {
|
|
14
|
+
this.#driverConfig = driverConfig;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Decode raw database results from the retrieval phase
|
|
18
|
+
*
|
|
19
|
+
* @param rawResults - Array of raw result sets from database queries
|
|
20
|
+
* @param operations - Array of retrieval operations that produced these results
|
|
21
|
+
* @returns Decoded results in application format
|
|
22
|
+
*/
|
|
23
|
+
decode(rawResults, operations) {
|
|
24
|
+
if (rawResults.length !== operations.length) throw new Error("rawResults and ops must have the same length");
|
|
25
|
+
return rawResults.map((rows, index) => {
|
|
26
|
+
const op = operations[index];
|
|
27
|
+
if (!op) throw new Error("op must be defined");
|
|
28
|
+
const rowArray = rows;
|
|
29
|
+
return this.decodeResultSet(rowArray, op);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Decodes a result set based on the operation type.
|
|
34
|
+
*
|
|
35
|
+
* This is the main entry point for decoding query results, routing to the
|
|
36
|
+
* appropriate decoder based on whether it's a count, cursor, or regular query.
|
|
37
|
+
*
|
|
38
|
+
* @param rows - The raw database rows
|
|
39
|
+
* @param operation - The retrieval operation defining how to decode the result
|
|
40
|
+
* @returns The decoded result (number for count, CursorResult for cursor, array otherwise)
|
|
41
|
+
*/
|
|
42
|
+
decodeResultSet(rows, operation) {
|
|
43
|
+
if (operation.type === "count") return this.decodeCountResult(rows);
|
|
44
|
+
const decodedRows = rows.map((row) => decodeResult(row, operation.table, this.#driverConfig));
|
|
45
|
+
if (operation.withCursor) return this.decodeCursorResult(decodedRows, operation.table, operation);
|
|
46
|
+
return decodedRows;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Decodes a count query result to a number.
|
|
50
|
+
*
|
|
51
|
+
* @param rows - The raw database rows (should contain a single row with a count column)
|
|
52
|
+
* @returns The count as a number
|
|
53
|
+
* @throws If the count value is invalid or missing
|
|
54
|
+
*/
|
|
55
|
+
decodeCountResult(rows) {
|
|
56
|
+
const firstRow = rows[0];
|
|
57
|
+
if (!firstRow) return 0;
|
|
58
|
+
const count = Number(firstRow["count"]);
|
|
59
|
+
if (Number.isNaN(count)) throw new Error(`Unexpected result for count, received: ${count}`);
|
|
60
|
+
return count;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Handles cursor generation and hasNextPage detection for cursor-paginated queries.
|
|
64
|
+
*
|
|
65
|
+
* Checks if we received more rows than the requested pageSize (we fetch pageSize + 1).
|
|
66
|
+
*
|
|
67
|
+
* @param decodedRows - The already-decoded database rows (pageSize + 1 rows)
|
|
68
|
+
* @param table - The table schema definition (needed for cursor generation)
|
|
69
|
+
* @param operation - The find operation containing pagination options
|
|
70
|
+
* @returns A CursorResult with items, cursor, and hasNextPage
|
|
71
|
+
*/
|
|
72
|
+
decodeCursorResult(decodedRows, table, operation) {
|
|
73
|
+
let cursor;
|
|
74
|
+
let hasNextPage = false;
|
|
75
|
+
let items = decodedRows;
|
|
76
|
+
if (operation.options.pageSize && operation.options.pageSize > 0 && decodedRows.length > operation.options.pageSize) {
|
|
77
|
+
hasNextPage = true;
|
|
78
|
+
items = decodedRows.slice(0, operation.options.pageSize);
|
|
79
|
+
if (operation.options.orderByIndex) {
|
|
80
|
+
const lastItem = items[items.length - 1];
|
|
81
|
+
const indexName = operation.options.orderByIndex.indexName;
|
|
82
|
+
let indexColumns;
|
|
83
|
+
if (indexName === "_primary") indexColumns = [table.getIdColumn()];
|
|
84
|
+
else {
|
|
85
|
+
const index = table.indexes[indexName];
|
|
86
|
+
if (index) indexColumns = index.columns;
|
|
87
|
+
}
|
|
88
|
+
if (indexColumns && lastItem) cursor = createCursorFromRecord(lastItem, indexColumns, {
|
|
89
|
+
indexName: operation.options.orderByIndex.indexName,
|
|
90
|
+
orderDirection: operation.options.orderByIndex.direction,
|
|
91
|
+
pageSize: operation.options.pageSize
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
items,
|
|
97
|
+
cursor,
|
|
98
|
+
hasNextPage
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
//#endregion
|
|
104
|
+
export { UnitOfWorkDecoder };
|
|
105
|
+
//# sourceMappingURL=uow-decoder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uow-decoder.js","names":["#driverConfig","cursor: Cursor | undefined"],"sources":["../../../src/adapters/generic-sql/uow-decoder.ts"],"sourcesContent":["import type { UOWDecoder } from \"../../query/unit-of-work/unit-of-work\";\nimport type { RetrievalOperation } from \"../../query/unit-of-work/unit-of-work\";\nimport type { AnySchema, AnyTable } from \"../../schema/create\";\nimport { decodeResult } from \"../../query/value-decoding\";\nimport { createCursorFromRecord, type Cursor, type CursorResult } from \"../../query/cursor\";\nimport type { DriverConfig } from \"./driver-config\";\n\n/**\n * Decoder class for Unit of Work retrieval results.\n *\n * Transforms raw database results into application format (e.g., converting raw columns\n * into FragnoId objects with external ID, internal ID, and version).\n */\nexport class UnitOfWorkDecoder implements UOWDecoder<unknown> {\n readonly #driverConfig: DriverConfig;\n\n constructor(driverConfig: DriverConfig) {\n this.#driverConfig = driverConfig;\n }\n\n /**\n * Decode raw database results from the retrieval phase\n *\n * @param rawResults - Array of raw result sets from database queries\n * @param operations - Array of retrieval operations that produced these results\n * @returns Decoded results in application format\n */\n decode(rawResults: unknown[], operations: RetrievalOperation<AnySchema>[]): unknown[] {\n if (rawResults.length !== operations.length) {\n throw new Error(\"rawResults and ops must have the same length\");\n }\n\n return rawResults.map((rows, index) => {\n const op = operations[index];\n if (!op) {\n throw new Error(\"op must be defined\");\n }\n\n const rowArray = rows as Record<string, unknown>[];\n return this.decodeResultSet(rowArray, op);\n });\n }\n\n /**\n * Decodes a result set based on the operation type.\n *\n * This is the main entry point for decoding query results, routing to the\n * appropriate decoder based on whether it's a count, cursor, or regular query.\n *\n * @param rows - The raw database rows\n * @param operation - The retrieval operation defining how to decode the result\n * @returns The decoded result (number for count, CursorResult for cursor, array otherwise)\n */\n private decodeResultSet(\n rows: Record<string, unknown>[],\n operation: RetrievalOperation<AnySchema>,\n ): number | Record<string, unknown>[] | CursorResult<unknown> {\n // Handle count operations\n if (operation.type === \"count\") {\n return this.decodeCountResult(rows);\n }\n\n const decodedRows = rows.map((row) => decodeResult(row, operation.table, this.#driverConfig));\n\n if (operation.withCursor) {\n return this.decodeCursorResult(decodedRows, operation.table, operation);\n }\n\n return decodedRows;\n }\n\n /**\n * Decodes a count query result to a number.\n *\n * @param rows - The raw database rows (should contain a single row with a count column)\n * @returns The count as a number\n * @throws If the count value is invalid or missing\n */\n private decodeCountResult(rows: Record<string, unknown>[]): number {\n const firstRow = rows[0];\n if (!firstRow) {\n return 0;\n }\n const count = Number(firstRow[\"count\"]);\n if (Number.isNaN(count)) {\n throw new Error(`Unexpected result for count, received: ${count}`);\n }\n return count;\n }\n\n /**\n * Handles cursor generation and hasNextPage detection for cursor-paginated queries.\n *\n * Checks if we received more rows than the requested pageSize (we fetch pageSize + 1).\n *\n * @param decodedRows - The already-decoded database rows (pageSize + 1 rows)\n * @param table - The table schema definition (needed for cursor generation)\n * @param operation - The find operation containing pagination options\n * @returns A CursorResult with items, cursor, and hasNextPage\n */\n private decodeCursorResult(\n decodedRows: Record<string, unknown>[],\n table: AnyTable,\n operation: Extract<RetrievalOperation<AnySchema>, { type: \"find\" }>,\n ): CursorResult<unknown> {\n let cursor: Cursor | undefined;\n let hasNextPage = false;\n let items = decodedRows;\n\n // Check if there are more results (we fetched pageSize + 1)\n if (\n operation.options.pageSize &&\n operation.options.pageSize > 0 &&\n decodedRows.length > operation.options.pageSize\n ) {\n hasNextPage = true;\n // Trim to requested pageSize\n items = decodedRows.slice(0, operation.options.pageSize);\n\n // Generate cursor from the last item we're returning\n if (operation.options.orderByIndex) {\n const lastItem = items[items.length - 1];\n const indexName = operation.options.orderByIndex.indexName;\n\n // Get index columns\n let indexColumns;\n if (indexName === \"_primary\") {\n indexColumns = [table.getIdColumn()];\n } else {\n const index = table.indexes[indexName];\n if (index) {\n indexColumns = index.columns;\n }\n }\n\n if (indexColumns && lastItem) {\n cursor = createCursorFromRecord(lastItem, indexColumns, {\n indexName: operation.options.orderByIndex.indexName,\n orderDirection: operation.options.orderByIndex.direction,\n pageSize: operation.options.pageSize,\n });\n }\n }\n }\n\n return {\n items,\n cursor,\n hasNextPage,\n };\n }\n}\n"],"mappings":";;;;;;;;;;AAaA,IAAa,oBAAb,MAA8D;CAC5D,CAASA;CAET,YAAY,cAA4B;AACtC,QAAKA,eAAgB;;;;;;;;;CAUvB,OAAO,YAAuB,YAAwD;AACpF,MAAI,WAAW,WAAW,WAAW,OACnC,OAAM,IAAI,MAAM,+CAA+C;AAGjE,SAAO,WAAW,KAAK,MAAM,UAAU;GACrC,MAAM,KAAK,WAAW;AACtB,OAAI,CAAC,GACH,OAAM,IAAI,MAAM,qBAAqB;GAGvC,MAAM,WAAW;AACjB,UAAO,KAAK,gBAAgB,UAAU,GAAG;IACzC;;;;;;;;;;;;CAaJ,AAAQ,gBACN,MACA,WAC4D;AAE5D,MAAI,UAAU,SAAS,QACrB,QAAO,KAAK,kBAAkB,KAAK;EAGrC,MAAM,cAAc,KAAK,KAAK,QAAQ,aAAa,KAAK,UAAU,OAAO,MAAKA,aAAc,CAAC;AAE7F,MAAI,UAAU,WACZ,QAAO,KAAK,mBAAmB,aAAa,UAAU,OAAO,UAAU;AAGzE,SAAO;;;;;;;;;CAUT,AAAQ,kBAAkB,MAAyC;EACjE,MAAM,WAAW,KAAK;AACtB,MAAI,CAAC,SACH,QAAO;EAET,MAAM,QAAQ,OAAO,SAAS,SAAS;AACvC,MAAI,OAAO,MAAM,MAAM,CACrB,OAAM,IAAI,MAAM,0CAA0C,QAAQ;AAEpE,SAAO;;;;;;;;;;;;CAaT,AAAQ,mBACN,aACA,OACA,WACuB;EACvB,IAAIC;EACJ,IAAI,cAAc;EAClB,IAAI,QAAQ;AAGZ,MACE,UAAU,QAAQ,YAClB,UAAU,QAAQ,WAAW,KAC7B,YAAY,SAAS,UAAU,QAAQ,UACvC;AACA,iBAAc;AAEd,WAAQ,YAAY,MAAM,GAAG,UAAU,QAAQ,SAAS;AAGxD,OAAI,UAAU,QAAQ,cAAc;IAClC,MAAM,WAAW,MAAM,MAAM,SAAS;IACtC,MAAM,YAAY,UAAU,QAAQ,aAAa;IAGjD,IAAI;AACJ,QAAI,cAAc,WAChB,gBAAe,CAAC,MAAM,aAAa,CAAC;SAC/B;KACL,MAAM,QAAQ,MAAM,QAAQ;AAC5B,SAAI,MACF,gBAAe,MAAM;;AAIzB,QAAI,gBAAgB,SAClB,UAAS,uBAAuB,UAAU,cAAc;KACtD,WAAW,UAAU,QAAQ,aAAa;KAC1C,gBAAgB,UAAU,QAAQ,aAAa;KAC/C,UAAU,UAAU,QAAQ;KAC7B,CAAC;;;AAKR,SAAO;GACL;GACA;GACA;GACD"}
|