kysely 0.27.6 → 0.28.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +169 -1
- package/deno.check.d.ts +7 -0
- package/dist/cjs/dialect/mssql/mssql-dialect-config.d.ts +26 -16
- package/dist/cjs/dialect/mssql/mssql-driver.d.ts +6 -3
- package/dist/cjs/dialect/mssql/mssql-driver.js +33 -19
- package/dist/cjs/dialect/mssql/mssql-query-compiler.d.ts +2 -0
- package/dist/cjs/dialect/mssql/mssql-query-compiler.js +11 -0
- package/dist/cjs/dialect/mysql/mysql-driver.d.ts +4 -0
- package/dist/cjs/dialect/mysql/mysql-driver.js +27 -12
- package/dist/cjs/dialect/postgres/postgres-driver.d.ts +4 -0
- package/dist/cjs/dialect/postgres/postgres-driver.js +28 -18
- package/dist/cjs/dialect/postgres/postgres-introspector.js +7 -17
- package/dist/cjs/dialect/sqlite/sqlite-driver.d.ts +4 -0
- package/dist/cjs/dialect/sqlite/sqlite-driver.js +19 -13
- package/dist/cjs/dialect/sqlite/sqlite-query-compiler.d.ts +2 -0
- package/dist/cjs/dialect/sqlite/sqlite-query-compiler.js +4 -0
- package/dist/cjs/driver/database-connection.d.ts +0 -4
- package/dist/cjs/driver/driver.d.ts +17 -0
- package/dist/cjs/driver/driver.js +13 -1
- package/dist/cjs/driver/dummy-driver.d.ts +3 -0
- package/dist/cjs/driver/dummy-driver.js +9 -0
- package/dist/cjs/driver/runtime-driver.d.ts +4 -0
- package/dist/cjs/driver/runtime-driver.js +43 -3
- package/dist/cjs/expression/expression-builder.d.ts +7 -10
- package/dist/cjs/helpers/postgres.d.ts +48 -0
- package/dist/cjs/helpers/postgres.js +50 -0
- package/dist/cjs/index.d.ts +13 -2
- package/dist/cjs/index.js +13 -2
- package/dist/cjs/kysely.d.ts +339 -2
- package/dist/cjs/kysely.js +465 -11
- package/dist/cjs/migration/migrator.d.ts +8 -0
- package/dist/cjs/migration/migrator.js +1 -1
- package/dist/cjs/operation-node/aggregate-function-node.d.ts +2 -1
- package/dist/cjs/operation-node/aggregate-function-node.js +4 -3
- package/dist/cjs/operation-node/alter-table-node.d.ts +3 -1
- package/dist/cjs/operation-node/collate-node.d.ts +13 -0
- package/dist/cjs/operation-node/collate-node.js +19 -0
- package/dist/cjs/operation-node/constraint-node.d.ts +1 -1
- package/dist/cjs/operation-node/create-type-node.d.ts +1 -1
- package/dist/cjs/operation-node/create-type-node.js +1 -1
- package/dist/cjs/operation-node/delete-query-node.d.ts +8 -2
- package/dist/cjs/operation-node/delete-query-node.js +11 -15
- package/dist/cjs/operation-node/foreign-key-constraint-node.d.ts +4 -0
- package/dist/cjs/operation-node/insert-query-node.d.ts +3 -0
- package/dist/cjs/operation-node/join-node.d.ts +1 -1
- package/dist/cjs/operation-node/merge-query-node.d.ts +2 -0
- package/dist/cjs/operation-node/operation-node-transformer.d.ts +106 -97
- package/dist/cjs/operation-node/operation-node-transformer.js +352 -312
- package/dist/cjs/operation-node/operation-node-visitor.d.ts +9 -1
- package/dist/cjs/operation-node/operation-node-visitor.js +4 -0
- package/dist/cjs/operation-node/operation-node.d.ts +1 -1
- package/dist/cjs/operation-node/or-action-node.d.ts +12 -0
- package/dist/cjs/operation-node/or-action-node.js +18 -0
- package/dist/cjs/operation-node/order-by-item-node.d.ts +5 -0
- package/dist/cjs/operation-node/order-by-item-node.js +6 -0
- package/dist/cjs/operation-node/primary-key-constraint-node.d.ts +29 -0
- package/dist/cjs/operation-node/{primary-constraint-node.js → primary-key-constraint-node.js} +11 -2
- package/dist/cjs/operation-node/query-node.d.ts +7 -0
- package/dist/cjs/operation-node/query-node.js +15 -0
- package/dist/cjs/operation-node/refresh-materialized-view-node.d.ts +17 -0
- package/dist/cjs/operation-node/refresh-materialized-view-node.js +25 -0
- package/dist/cjs/operation-node/rename-constraint-node.d.ts +14 -0
- package/dist/cjs/operation-node/rename-constraint-node.js +20 -0
- package/dist/cjs/operation-node/select-query-node.d.ts +8 -2
- package/dist/cjs/operation-node/select-query-node.js +11 -15
- package/dist/cjs/operation-node/unique-constraint-node.d.ts +2 -0
- package/dist/cjs/operation-node/update-query-node.d.ts +3 -4
- package/dist/cjs/operation-node/update-query-node.js +5 -2
- package/dist/cjs/parser/collate-parser.d.ts +1 -0
- package/dist/cjs/parser/collate-parser.js +2 -0
- package/dist/cjs/parser/delete-from-parser.d.ts +5 -0
- package/dist/cjs/parser/delete-from-parser.js +2 -0
- package/dist/cjs/parser/join-parser.d.ts +1 -1
- package/dist/cjs/parser/join-parser.js +7 -1
- package/dist/cjs/parser/merge-into-parser.d.ts +5 -0
- package/dist/cjs/parser/merge-into-parser.js +2 -0
- package/dist/cjs/parser/order-by-parser.d.ts +18 -5
- package/dist/cjs/parser/order-by-parser.js +24 -14
- package/dist/cjs/parser/savepoint-parser.d.ts +4 -0
- package/dist/cjs/parser/savepoint-parser.js +11 -0
- package/dist/cjs/parser/select-from-parser.d.ts +4 -0
- package/dist/cjs/parser/select-from-parser.js +2 -0
- package/dist/cjs/parser/table-parser.d.ts +2 -5
- package/dist/cjs/parser/update-parser.d.ts +5 -0
- package/dist/cjs/parser/update-parser.js +2 -0
- package/dist/cjs/parser/update-set-parser.d.ts +7 -4
- package/dist/cjs/plugin/camel-case/camel-case-plugin.js +1 -1
- package/dist/cjs/plugin/camel-case/camel-case-transformer.d.ts +2 -1
- package/dist/cjs/plugin/camel-case/camel-case-transformer.js +2 -2
- package/dist/cjs/plugin/deduplicate-joins/deduplicate-joins-plugin.js +1 -1
- package/dist/cjs/plugin/deduplicate-joins/deduplicate-joins-transformer.d.ts +4 -3
- package/dist/cjs/plugin/deduplicate-joins/deduplicate-joins-transformer.js +6 -6
- package/dist/cjs/plugin/handle-empty-in-lists/handle-empty-in-lists-plugin.d.ts +211 -0
- package/dist/cjs/plugin/handle-empty-in-lists/handle-empty-in-lists-plugin.js +162 -0
- package/dist/cjs/plugin/handle-empty-in-lists/handle-empty-in-lists-transformer.d.ts +8 -0
- package/dist/cjs/plugin/handle-empty-in-lists/handle-empty-in-lists-transformer.js +29 -0
- package/dist/cjs/plugin/handle-empty-in-lists/handle-empty-in-lists.d.ts +44 -0
- package/dist/cjs/plugin/handle-empty-in-lists/handle-empty-in-lists.js +66 -0
- package/dist/cjs/plugin/immediate-value/immediate-value-plugin.js +1 -1
- package/dist/cjs/plugin/immediate-value/immediate-value-transformer.d.ts +2 -0
- package/dist/cjs/plugin/immediate-value/immediate-value-transformer.js +6 -4
- package/dist/cjs/plugin/with-schema/with-schema-plugin.js +1 -1
- package/dist/cjs/plugin/with-schema/with-schema-transformer.d.ts +6 -5
- package/dist/cjs/plugin/with-schema/with-schema-transformer.js +29 -24
- package/dist/cjs/query-builder/aggregate-function-builder.d.ts +83 -5
- package/dist/cjs/query-builder/aggregate-function-builder.js +15 -27
- package/dist/cjs/query-builder/cte-builder.js +0 -2
- package/dist/cjs/query-builder/delete-query-builder.d.ts +36 -47
- package/dist/cjs/query-builder/delete-query-builder.js +12 -78
- package/dist/cjs/query-builder/function-module.d.ts +31 -4
- package/dist/cjs/query-builder/insert-query-builder.d.ts +161 -6
- package/dist/cjs/query-builder/insert-query-builder.js +197 -10
- package/dist/cjs/query-builder/join-builder.js +0 -2
- package/dist/cjs/query-builder/merge-query-builder.d.ts +145 -3
- package/dist/cjs/query-builder/merge-query-builder.js +28 -7
- package/dist/cjs/query-builder/on-conflict-builder.js +0 -4
- package/dist/cjs/query-builder/order-by-interface.d.ts +176 -0
- package/dist/cjs/query-builder/order-by-interface.js +2 -0
- package/dist/cjs/query-builder/order-by-item-builder.d.ts +43 -0
- package/dist/cjs/query-builder/order-by-item-builder.js +75 -0
- package/dist/cjs/query-builder/over-builder.d.ts +43 -6
- package/dist/cjs/query-builder/over-builder.js +8 -25
- package/dist/cjs/query-builder/returning-interface.d.ts +20 -3
- package/dist/cjs/query-builder/select-query-builder.d.ts +279 -98
- package/dist/cjs/query-builder/select-query-builder.js +26 -26
- package/dist/cjs/query-builder/update-query-builder.d.ts +88 -9
- package/dist/cjs/query-builder/update-query-builder.js +17 -15
- package/dist/cjs/query-compiler/compiled-query.d.ts +2 -0
- package/dist/cjs/query-compiler/compiled-query.js +2 -0
- package/dist/cjs/query-compiler/default-query-compiler.d.ts +17 -2
- package/dist/cjs/query-compiler/default-query-compiler.js +97 -2
- package/dist/cjs/query-compiler/query-compiler.d.ts +4 -2
- package/dist/cjs/query-creator.d.ts +23 -25
- package/dist/cjs/query-creator.js +280 -8
- package/dist/cjs/query-executor/default-query-executor.d.ts +2 -1
- package/dist/cjs/query-executor/default-query-executor.js +2 -2
- package/dist/cjs/query-executor/query-executor-base.js +7 -25
- package/dist/cjs/raw-builder/raw-builder.js +0 -3
- package/dist/cjs/raw-builder/sql.d.ts +3 -3
- package/dist/cjs/raw-builder/sql.js +1 -1
- package/dist/cjs/schema/alter-column-builder.js +0 -3
- package/dist/cjs/schema/alter-table-add-foreign-key-constraint-builder.d.ts +4 -0
- package/dist/cjs/schema/alter-table-add-foreign-key-constraint-builder.js +24 -2
- package/dist/cjs/schema/alter-table-add-index-builder.js +0 -2
- package/dist/cjs/schema/alter-table-builder.d.ts +7 -3
- package/dist/cjs/schema/alter-table-builder.js +21 -10
- package/dist/cjs/schema/alter-table-drop-constraint-builder.js +0 -2
- package/dist/cjs/schema/alter-table-executor.js +0 -2
- package/dist/cjs/schema/check-constraint-builder.d.ts +13 -0
- package/dist/cjs/schema/check-constraint-builder.js +20 -0
- package/dist/cjs/schema/column-definition-builder.js +0 -2
- package/dist/cjs/schema/create-index-builder.js +1 -3
- package/dist/cjs/schema/create-schema-builder.js +0 -2
- package/dist/cjs/schema/create-table-builder.d.ts +5 -4
- package/dist/cjs/schema/create-table-builder.js +9 -7
- package/dist/cjs/schema/create-type-builder.d.ts +1 -1
- package/dist/cjs/schema/create-type-builder.js +0 -2
- package/dist/cjs/schema/create-view-builder.js +0 -2
- package/dist/cjs/schema/drop-index-builder.js +0 -2
- package/dist/cjs/schema/drop-schema-builder.js +0 -2
- package/dist/cjs/schema/drop-table-builder.js +0 -2
- package/dist/cjs/schema/drop-type-builder.js +0 -2
- package/dist/cjs/schema/drop-view-builder.js +0 -2
- package/dist/cjs/schema/foreign-key-constraint-builder.d.ts +9 -0
- package/dist/cjs/schema/foreign-key-constraint-builder.js +16 -2
- package/dist/cjs/schema/primary-key-constraint-builder.d.ts +17 -0
- package/dist/cjs/schema/primary-key-constraint-builder.js +37 -0
- package/dist/cjs/schema/refresh-materialized-view-builder.d.ts +47 -0
- package/dist/cjs/schema/refresh-materialized-view-builder.js +75 -0
- package/dist/cjs/schema/schema.d.ts +14 -0
- package/dist/cjs/schema/schema.js +21 -0
- package/dist/cjs/schema/unique-constraint-builder.d.ts +10 -1
- package/dist/cjs/schema/unique-constraint-builder.js +26 -5
- package/dist/cjs/util/infer-result.d.ts +1 -1
- package/dist/cjs/util/log.d.ts +1 -0
- package/dist/cjs/util/log.js +3 -2
- package/dist/cjs/util/provide-controlled-connection.d.ts +7 -0
- package/dist/cjs/util/provide-controlled-connection.js +24 -0
- package/dist/esm/dialect/mssql/mssql-dialect-config.d.ts +26 -16
- package/dist/esm/dialect/mssql/mssql-driver.d.ts +6 -3
- package/dist/esm/dialect/mssql/mssql-driver.js +33 -19
- package/dist/esm/dialect/mssql/mssql-query-compiler.d.ts +2 -0
- package/dist/esm/dialect/mssql/mssql-query-compiler.js +11 -0
- package/dist/esm/dialect/mysql/mysql-driver.d.ts +4 -0
- package/dist/esm/dialect/mysql/mysql-driver.js +27 -12
- package/dist/esm/dialect/postgres/postgres-driver.d.ts +4 -0
- package/dist/esm/dialect/postgres/postgres-driver.js +28 -18
- package/dist/esm/dialect/postgres/postgres-introspector.js +7 -17
- package/dist/esm/dialect/sqlite/sqlite-driver.d.ts +4 -0
- package/dist/esm/dialect/sqlite/sqlite-driver.js +19 -13
- package/dist/esm/dialect/sqlite/sqlite-query-compiler.d.ts +2 -0
- package/dist/esm/dialect/sqlite/sqlite-query-compiler.js +4 -0
- package/dist/esm/driver/database-connection.d.ts +0 -4
- package/dist/esm/driver/driver.d.ts +17 -0
- package/dist/esm/driver/driver.js +11 -0
- package/dist/esm/driver/dummy-driver.d.ts +3 -0
- package/dist/esm/driver/dummy-driver.js +9 -0
- package/dist/esm/driver/runtime-driver.d.ts +4 -0
- package/dist/esm/driver/runtime-driver.js +43 -3
- package/dist/esm/expression/expression-builder.d.ts +7 -10
- package/dist/esm/helpers/postgres.d.ts +48 -0
- package/dist/esm/helpers/postgres.js +49 -0
- package/dist/esm/index.d.ts +13 -2
- package/dist/esm/index.js +11 -1
- package/dist/esm/kysely.d.ts +339 -2
- package/dist/esm/kysely.js +461 -10
- package/dist/esm/migration/migrator.d.ts +8 -0
- package/dist/esm/migration/migrator.js +1 -1
- package/dist/esm/operation-node/aggregate-function-node.d.ts +2 -1
- package/dist/esm/operation-node/aggregate-function-node.js +4 -3
- package/dist/esm/operation-node/alter-table-node.d.ts +3 -1
- package/dist/esm/operation-node/collate-node.d.ts +13 -0
- package/dist/esm/operation-node/collate-node.js +17 -0
- package/dist/esm/operation-node/constraint-node.d.ts +1 -1
- package/dist/esm/operation-node/create-type-node.d.ts +1 -1
- package/dist/esm/operation-node/create-type-node.js +1 -1
- package/dist/esm/operation-node/delete-query-node.d.ts +8 -2
- package/dist/esm/operation-node/delete-query-node.js +11 -15
- package/dist/esm/operation-node/foreign-key-constraint-node.d.ts +4 -0
- package/dist/esm/operation-node/insert-query-node.d.ts +3 -0
- package/dist/esm/operation-node/join-node.d.ts +1 -1
- package/dist/esm/operation-node/merge-query-node.d.ts +2 -0
- package/dist/esm/operation-node/operation-node-transformer.d.ts +106 -97
- package/dist/esm/operation-node/operation-node-transformer.js +352 -312
- package/dist/esm/operation-node/operation-node-visitor.d.ts +9 -1
- package/dist/esm/operation-node/operation-node-visitor.js +4 -0
- package/dist/esm/operation-node/operation-node.d.ts +1 -1
- package/dist/esm/operation-node/or-action-node.d.ts +12 -0
- package/dist/esm/operation-node/or-action-node.js +16 -0
- package/dist/esm/operation-node/order-by-item-node.d.ts +5 -0
- package/dist/esm/operation-node/order-by-item-node.js +6 -0
- package/dist/esm/operation-node/primary-key-constraint-node.d.ts +29 -0
- package/dist/esm/operation-node/{primary-constraint-node.js → primary-key-constraint-node.js} +11 -2
- package/dist/esm/operation-node/query-node.d.ts +7 -0
- package/dist/esm/operation-node/query-node.js +15 -0
- package/dist/esm/operation-node/refresh-materialized-view-node.d.ts +17 -0
- package/dist/esm/operation-node/refresh-materialized-view-node.js +23 -0
- package/dist/esm/operation-node/rename-constraint-node.d.ts +14 -0
- package/dist/esm/operation-node/rename-constraint-node.js +18 -0
- package/dist/esm/operation-node/select-query-node.d.ts +8 -2
- package/dist/esm/operation-node/select-query-node.js +11 -15
- package/dist/esm/operation-node/unique-constraint-node.d.ts +2 -0
- package/dist/esm/operation-node/update-query-node.d.ts +3 -4
- package/dist/esm/operation-node/update-query-node.js +5 -2
- package/dist/esm/parser/collate-parser.d.ts +1 -0
- package/dist/esm/parser/collate-parser.js +2 -0
- package/dist/esm/parser/delete-from-parser.d.ts +5 -0
- package/dist/esm/parser/delete-from-parser.js +2 -0
- package/dist/esm/parser/join-parser.d.ts +1 -1
- package/dist/esm/parser/join-parser.js +7 -1
- package/dist/esm/parser/merge-into-parser.d.ts +5 -0
- package/dist/esm/parser/merge-into-parser.js +2 -0
- package/dist/esm/parser/order-by-parser.d.ts +18 -5
- package/dist/esm/parser/order-by-parser.js +27 -17
- package/dist/esm/parser/savepoint-parser.d.ts +4 -0
- package/dist/esm/parser/savepoint-parser.js +9 -0
- package/dist/esm/parser/select-from-parser.d.ts +4 -0
- package/dist/esm/parser/select-from-parser.js +2 -0
- package/dist/esm/parser/table-parser.d.ts +2 -5
- package/dist/esm/parser/update-parser.d.ts +5 -0
- package/dist/esm/parser/update-parser.js +2 -0
- package/dist/esm/parser/update-set-parser.d.ts +7 -4
- package/dist/esm/plugin/camel-case/camel-case-plugin.js +1 -1
- package/dist/esm/plugin/camel-case/camel-case-transformer.d.ts +2 -1
- package/dist/esm/plugin/camel-case/camel-case-transformer.js +2 -2
- package/dist/esm/plugin/deduplicate-joins/deduplicate-joins-plugin.js +1 -1
- package/dist/esm/plugin/deduplicate-joins/deduplicate-joins-transformer.d.ts +4 -3
- package/dist/esm/plugin/deduplicate-joins/deduplicate-joins-transformer.js +6 -6
- package/dist/esm/plugin/handle-empty-in-lists/handle-empty-in-lists-plugin.d.ts +211 -0
- package/dist/esm/plugin/handle-empty-in-lists/handle-empty-in-lists-plugin.js +159 -0
- package/dist/esm/plugin/handle-empty-in-lists/handle-empty-in-lists-transformer.d.ts +8 -0
- package/dist/esm/plugin/handle-empty-in-lists/handle-empty-in-lists-transformer.js +26 -0
- package/dist/esm/plugin/handle-empty-in-lists/handle-empty-in-lists.d.ts +44 -0
- package/dist/esm/plugin/handle-empty-in-lists/handle-empty-in-lists.js +63 -0
- package/dist/esm/plugin/immediate-value/immediate-value-plugin.js +1 -1
- package/dist/esm/plugin/immediate-value/immediate-value-transformer.d.ts +2 -0
- package/dist/esm/plugin/immediate-value/immediate-value-transformer.js +6 -4
- package/dist/esm/plugin/with-schema/with-schema-plugin.js +1 -1
- package/dist/esm/plugin/with-schema/with-schema-transformer.d.ts +6 -5
- package/dist/esm/plugin/with-schema/with-schema-transformer.js +29 -24
- package/dist/esm/query-builder/aggregate-function-builder.d.ts +83 -5
- package/dist/esm/query-builder/aggregate-function-builder.js +15 -27
- package/dist/esm/query-builder/cte-builder.js +0 -2
- package/dist/esm/query-builder/delete-query-builder.d.ts +36 -47
- package/dist/esm/query-builder/delete-query-builder.js +12 -78
- package/dist/esm/query-builder/function-module.d.ts +31 -4
- package/dist/esm/query-builder/insert-query-builder.d.ts +161 -6
- package/dist/esm/query-builder/insert-query-builder.js +197 -10
- package/dist/esm/query-builder/join-builder.js +0 -2
- package/dist/esm/query-builder/merge-query-builder.d.ts +145 -3
- package/dist/esm/query-builder/merge-query-builder.js +29 -8
- package/dist/esm/query-builder/on-conflict-builder.js +0 -4
- package/dist/esm/query-builder/order-by-interface.d.ts +176 -0
- package/dist/esm/query-builder/order-by-interface.js +2 -0
- package/dist/esm/query-builder/order-by-item-builder.d.ts +43 -0
- package/dist/esm/query-builder/order-by-item-builder.js +72 -0
- package/dist/esm/query-builder/over-builder.d.ts +43 -6
- package/dist/esm/query-builder/over-builder.js +8 -25
- package/dist/esm/query-builder/returning-interface.d.ts +20 -3
- package/dist/esm/query-builder/select-query-builder.d.ts +279 -98
- package/dist/esm/query-builder/select-query-builder.js +26 -26
- package/dist/esm/query-builder/update-query-builder.d.ts +88 -9
- package/dist/esm/query-builder/update-query-builder.js +17 -15
- package/dist/esm/query-compiler/compiled-query.d.ts +2 -0
- package/dist/esm/query-compiler/compiled-query.js +2 -0
- package/dist/esm/query-compiler/default-query-compiler.d.ts +17 -2
- package/dist/esm/query-compiler/default-query-compiler.js +97 -2
- package/dist/esm/query-compiler/query-compiler.d.ts +4 -2
- package/dist/esm/query-creator.d.ts +23 -25
- package/dist/esm/query-creator.js +281 -9
- package/dist/esm/query-executor/default-query-executor.d.ts +2 -1
- package/dist/esm/query-executor/default-query-executor.js +2 -2
- package/dist/esm/query-executor/query-executor-base.js +7 -25
- package/dist/esm/raw-builder/raw-builder.js +0 -3
- package/dist/esm/raw-builder/sql.d.ts +3 -3
- package/dist/esm/raw-builder/sql.js +1 -1
- package/dist/esm/schema/alter-column-builder.js +0 -3
- package/dist/esm/schema/alter-table-add-foreign-key-constraint-builder.d.ts +4 -0
- package/dist/esm/schema/alter-table-add-foreign-key-constraint-builder.js +24 -2
- package/dist/esm/schema/alter-table-add-index-builder.js +0 -2
- package/dist/esm/schema/alter-table-builder.d.ts +7 -3
- package/dist/esm/schema/alter-table-builder.js +22 -11
- package/dist/esm/schema/alter-table-drop-constraint-builder.js +0 -2
- package/dist/esm/schema/alter-table-executor.js +0 -2
- package/dist/esm/schema/check-constraint-builder.d.ts +13 -0
- package/dist/esm/schema/check-constraint-builder.js +17 -0
- package/dist/esm/schema/column-definition-builder.js +0 -2
- package/dist/esm/schema/create-index-builder.js +1 -3
- package/dist/esm/schema/create-schema-builder.js +0 -2
- package/dist/esm/schema/create-table-builder.d.ts +5 -4
- package/dist/esm/schema/create-table-builder.js +10 -8
- package/dist/esm/schema/create-type-builder.d.ts +1 -1
- package/dist/esm/schema/create-type-builder.js +0 -2
- package/dist/esm/schema/create-view-builder.js +0 -2
- package/dist/esm/schema/drop-index-builder.js +0 -2
- package/dist/esm/schema/drop-schema-builder.js +0 -2
- package/dist/esm/schema/drop-table-builder.js +0 -2
- package/dist/esm/schema/drop-type-builder.js +0 -2
- package/dist/esm/schema/drop-view-builder.js +0 -2
- package/dist/esm/schema/foreign-key-constraint-builder.d.ts +9 -0
- package/dist/esm/schema/foreign-key-constraint-builder.js +16 -2
- package/dist/esm/schema/primary-key-constraint-builder.d.ts +17 -0
- package/dist/esm/schema/primary-key-constraint-builder.js +34 -0
- package/dist/esm/schema/refresh-materialized-view-builder.d.ts +47 -0
- package/dist/esm/schema/refresh-materialized-view-builder.js +72 -0
- package/dist/esm/schema/schema.d.ts +14 -0
- package/dist/esm/schema/schema.js +21 -0
- package/dist/esm/schema/unique-constraint-builder.d.ts +10 -1
- package/dist/esm/schema/unique-constraint-builder.js +26 -5
- package/dist/esm/util/infer-result.d.ts +1 -1
- package/dist/esm/util/log.d.ts +1 -0
- package/dist/esm/util/log.js +3 -2
- package/dist/esm/util/provide-controlled-connection.d.ts +7 -0
- package/dist/esm/util/provide-controlled-connection.js +22 -0
- package/outdated-typescript.d.ts +5 -0
- package/package.json +16 -2
- package/CONTRIBUTING.md +0 -168
- package/dist/cjs/operation-node/primary-constraint-node.d.ts +0 -15
- package/dist/cjs/util/prevent-await.d.ts +0 -1
- package/dist/cjs/util/prevent-await.js +0 -13
- package/dist/esm/operation-node/primary-constraint-node.d.ts +0 -15
- package/dist/esm/util/prevent-await.d.ts +0 -1
- package/dist/esm/util/prevent-await.js +0 -11
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/// <reference types="./order-by-parser.d.ts" />
|
|
2
|
-
import { isDynamicReferenceBuilder } from '../dynamic/dynamic-reference-builder.js';
|
|
2
|
+
import { isDynamicReferenceBuilder, } from '../dynamic/dynamic-reference-builder.js';
|
|
3
|
+
import { isExpression } from '../expression/expression.js';
|
|
3
4
|
import { OrderByItemNode } from '../operation-node/order-by-item-node.js';
|
|
4
5
|
import { RawNode } from '../operation-node/raw-node.js';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
6
|
+
import { OrderByItemBuilder } from '../query-builder/order-by-item-builder.js';
|
|
7
|
+
import { logOnce } from '../util/log-once.js';
|
|
8
|
+
import { isExpressionOrFactory, parseExpression, } from './expression-parser.js';
|
|
9
|
+
import { parseStringReference, } from './reference-parser.js';
|
|
7
10
|
export function isOrderByDirection(thing) {
|
|
8
11
|
return thing === 'asc' || thing === 'desc';
|
|
9
12
|
}
|
|
@@ -14,21 +17,22 @@ export function parseOrderBy(args) {
|
|
|
14
17
|
if (args.length === 1) {
|
|
15
18
|
const [orderBy] = args;
|
|
16
19
|
if (Array.isArray(orderBy)) {
|
|
20
|
+
logOnce('orderBy(array) is deprecated, use multiple orderBy calls instead.');
|
|
17
21
|
return orderBy.map((item) => parseOrderByItem(item));
|
|
18
22
|
}
|
|
19
23
|
return [parseOrderByItem(orderBy)];
|
|
20
24
|
}
|
|
21
25
|
throw new Error(`Invalid number of arguments at order by! expected 1-2, received ${args.length}`);
|
|
22
26
|
}
|
|
23
|
-
export function parseOrderByItem(
|
|
24
|
-
const parsedRef = parseOrderByExpression(
|
|
27
|
+
export function parseOrderByItem(expr, modifiers) {
|
|
28
|
+
const parsedRef = parseOrderByExpression(expr);
|
|
25
29
|
if (OrderByItemNode.is(parsedRef)) {
|
|
26
|
-
if (
|
|
30
|
+
if (modifiers) {
|
|
27
31
|
throw new Error('Cannot specify direction twice!');
|
|
28
32
|
}
|
|
29
33
|
return parsedRef;
|
|
30
34
|
}
|
|
31
|
-
return
|
|
35
|
+
return parseOrderByWithModifiers(parsedRef, modifiers);
|
|
32
36
|
}
|
|
33
37
|
function parseOrderByExpression(expr) {
|
|
34
38
|
if (isExpressionOrFactory(expr)) {
|
|
@@ -39,19 +43,25 @@ function parseOrderByExpression(expr) {
|
|
|
39
43
|
}
|
|
40
44
|
const [ref, direction] = expr.split(' ');
|
|
41
45
|
if (direction) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
return OrderByItemNode.create(parseStringReference(ref), parseOrderByDirectionExpression(direction));
|
|
46
|
+
logOnce("`orderBy('column asc')` is deprecated. Use `orderBy('column', 'asc')` instead.");
|
|
47
|
+
return parseOrderByWithModifiers(parseStringReference(ref), direction);
|
|
46
48
|
}
|
|
47
49
|
return parseStringReference(expr);
|
|
48
50
|
}
|
|
49
|
-
function
|
|
50
|
-
if (
|
|
51
|
-
|
|
51
|
+
function parseOrderByWithModifiers(expr, modifiers) {
|
|
52
|
+
if (typeof modifiers === 'string') {
|
|
53
|
+
if (!isOrderByDirection(modifiers)) {
|
|
54
|
+
throw new Error(`Invalid order by direction: ${modifiers}`);
|
|
55
|
+
}
|
|
56
|
+
return OrderByItemNode.create(expr, RawNode.createWithSql(modifiers));
|
|
57
|
+
}
|
|
58
|
+
if (isExpression(modifiers)) {
|
|
59
|
+
logOnce("`orderBy(..., expr)` is deprecated. Use `orderBy(..., 'asc')` or `orderBy(..., (ob) => ...)` instead.");
|
|
60
|
+
return OrderByItemNode.create(expr, modifiers.toOperationNode());
|
|
52
61
|
}
|
|
53
|
-
|
|
54
|
-
|
|
62
|
+
const node = OrderByItemNode.create(expr);
|
|
63
|
+
if (!modifiers) {
|
|
64
|
+
return node;
|
|
55
65
|
}
|
|
56
|
-
return
|
|
66
|
+
return modifiers(new OrderByItemBuilder({ node })).toOperationNode();
|
|
57
67
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { RawNode } from '../operation-node/raw-node.js';
|
|
2
|
+
export type RollbackToSavepoint<S extends string[], SN extends S[number]> = S extends [...infer L, infer R] ? R extends SN ? S : RollbackToSavepoint<L extends string[] ? L : never, SN> : never;
|
|
3
|
+
export type ReleaseSavepoint<S extends string[], SN extends S[number]> = S extends [...infer L, infer R] ? R extends SN ? L : ReleaseSavepoint<L extends string[] ? L : never, SN> : never;
|
|
4
|
+
export declare function parseSavepointCommand(command: string, savepointName: string): RawNode;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/// <reference types="./savepoint-parser.d.ts" />
|
|
2
|
+
import { IdentifierNode } from '../operation-node/identifier-node.js';
|
|
3
|
+
import { RawNode } from '../operation-node/raw-node.js';
|
|
4
|
+
export function parseSavepointCommand(command, savepointName) {
|
|
5
|
+
return RawNode.createWithChildren([
|
|
6
|
+
RawNode.createWithSql(`${command} `),
|
|
7
|
+
IdentifierNode.create(savepointName), // ensures savepointName gets sanitized
|
|
8
|
+
]);
|
|
9
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { SelectQueryBuilder } from '../query-builder/select-query-builder.js';
|
|
2
|
+
import type { ShallowRecord } from '../util/type-utils.js';
|
|
3
|
+
import type { ExtractTableAlias, From, FromTables, TableExpressionOrList } from './table-parser.js';
|
|
4
|
+
export type SelectFrom<DB, TB extends keyof DB, TE extends TableExpressionOrList<DB, TB>> = TE extends keyof DB & string ? SelectQueryBuilder<DB, TB | ExtractTableAlias<DB, TE>, {}> : TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? SelectQueryBuilder<DB & ShallowRecord<A, DB[T]>, TB | A, {}> : never : TE extends ReadonlyArray<infer T> ? SelectQueryBuilder<From<DB, T>, FromTables<DB, TB, T>, {}> : SelectQueryBuilder<From<DB, TE>, FromTables<DB, TB, TE>, {}>;
|
|
@@ -3,22 +3,19 @@ import { TableNode } from '../operation-node/table-node.js';
|
|
|
3
3
|
import { AliasedExpressionOrFactory } from './expression-parser.js';
|
|
4
4
|
import { OperationNode } from '../operation-node/operation-node.js';
|
|
5
5
|
import { AliasedExpression } from '../expression/expression.js';
|
|
6
|
-
import { DrainOuterGeneric
|
|
6
|
+
import { DrainOuterGeneric } from '../util/type-utils.js';
|
|
7
7
|
export type TableExpression<DB, TB extends keyof DB> = AnyAliasedTable<DB> | AnyTable<DB> | AliasedExpressionOrFactory<DB, TB>;
|
|
8
8
|
export type TableExpressionOrList<DB, TB extends keyof DB> = TableExpression<DB, TB> | ReadonlyArray<TableExpression<DB, TB>>;
|
|
9
|
-
export type TableReference<DB> = SimpleTableReference<DB> | AliasedExpression<any, any>;
|
|
10
9
|
export type SimpleTableReference<DB> = AnyAliasedTable<DB> | AnyTable<DB>;
|
|
11
10
|
export type AnyAliasedTable<DB> = `${AnyTable<DB>} as ${string}`;
|
|
12
|
-
export type
|
|
11
|
+
export type AnyTable<DB> = keyof DB & string;
|
|
13
12
|
export type From<DB, TE> = DrainOuterGeneric<{
|
|
14
13
|
[C in keyof DB | ExtractAliasFromTableExpression<DB, TE>]: C extends ExtractAliasFromTableExpression<DB, TE> ? ExtractRowTypeFromTableExpression<DB, TE, C> : C extends keyof DB ? DB[C] : never;
|
|
15
14
|
}>;
|
|
16
15
|
export type FromTables<DB, TB extends keyof DB, TE> = DrainOuterGeneric<TB | ExtractAliasFromTableExpression<DB, TE>>;
|
|
17
16
|
export type ExtractTableAlias<DB, TE> = TE extends `${string} as ${infer TA}` ? TA extends keyof DB ? TA : never : TE extends keyof DB ? TE : never;
|
|
18
|
-
export type PickTableWithAlias<DB, T extends AnyAliasedTable<DB>> = T extends `${infer TB} as ${infer A}` ? TB extends keyof DB ? ShallowRecord<A, DB[TB]> : never : never;
|
|
19
17
|
type ExtractAliasFromTableExpression<DB, TE> = TE extends string ? TE extends `${string} as ${infer TA}` ? TA : TE extends keyof DB ? TE : never : TE extends AliasedExpression<any, infer QA> ? QA : TE extends (qb: any) => AliasedExpression<any, infer QA> ? QA : never;
|
|
20
18
|
type ExtractRowTypeFromTableExpression<DB, TE, A extends keyof any> = TE extends `${infer T} as ${infer TA}` ? TA extends A ? T extends keyof DB ? DB[T] : never : never : TE extends A ? TE extends keyof DB ? DB[TE] : never : TE extends AliasedExpression<infer O, infer QA> ? QA extends A ? O : never : TE extends (qb: any) => AliasedExpression<infer O, infer QA> ? QA extends A ? O : never : never;
|
|
21
|
-
type AnyTable<DB> = keyof DB & string;
|
|
22
19
|
export declare function parseTableExpressionOrList(table: TableExpressionOrList<any, any>): OperationNode[];
|
|
23
20
|
export declare function parseTableExpression(table: TableExpression<any, any>): OperationNode;
|
|
24
21
|
export declare function parseAliasedTable(from: string): TableNode | AliasNode;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { UpdateQueryBuilder } from '../query-builder/update-query-builder.js';
|
|
2
|
+
import type { UpdateResult } from '../query-builder/update-result.js';
|
|
3
|
+
import type { ShallowRecord } from '../util/type-utils.js';
|
|
4
|
+
import type { ExtractTableAlias, From, FromTables, TableExpressionOrList } from './table-parser.js';
|
|
5
|
+
export type UpdateTable<DB, TE extends TableExpressionOrList<DB, never>> = TE extends ReadonlyArray<infer T> ? UpdateQueryBuilder<From<DB, T>, FromTables<DB, never, T>, FromTables<DB, never, T>, UpdateResult> : TE extends keyof DB & string ? UpdateQueryBuilder<DB, ExtractTableAlias<DB, TE>, ExtractTableAlias<DB, TE>, UpdateResult> : TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? UpdateQueryBuilder<DB & ShallowRecord<A, DB[T]>, A, A, UpdateResult> : never : UpdateQueryBuilder<From<DB, TE>, FromTables<DB, never, TE>, FromTables<DB, never, TE>, UpdateResult>;
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { ColumnUpdateNode } from '../operation-node/column-update-node.js';
|
|
2
2
|
import { ExpressionBuilder } from '../expression/expression-builder.js';
|
|
3
|
-
import {
|
|
3
|
+
import { UpdateType } from '../util/column-type.js';
|
|
4
4
|
import { ValueExpression } from './value-parser.js';
|
|
5
5
|
import { ExtractRawTypeFromReferenceExpression, ReferenceExpression } from './reference-parser.js';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
import { AnyColumn, DrainOuterGeneric } from '../util/type-utils.js';
|
|
7
|
+
export type UpdateObject<DB, TB extends keyof DB, UT extends keyof DB = TB> = DrainOuterGeneric<{
|
|
8
|
+
[C in AnyColumn<DB, UT>]?: {
|
|
9
|
+
[T in UT]: C extends keyof DB[T] ? ValueExpression<DB, TB, UpdateType<DB[T][C]>> | undefined : never;
|
|
10
|
+
}[UT];
|
|
11
|
+
}>;
|
|
9
12
|
export type UpdateObjectFactory<DB, TB extends keyof DB, UT extends keyof DB> = (eb: ExpressionBuilder<DB, TB>) => UpdateObject<DB, TB, UT>;
|
|
10
13
|
export type UpdateObjectExpression<DB, TB extends keyof DB, UT extends keyof DB = TB> = UpdateObject<DB, TB, UT> | UpdateObjectFactory<DB, TB, UT>;
|
|
11
14
|
export type ExtractUpdateTypeFromReferenceExpression<DB, TB extends keyof DB, RE, DV = unknown> = UpdateType<ExtractRawTypeFromReferenceExpression<DB, TB, RE, DV>>;
|
|
@@ -83,7 +83,7 @@ export class CamelCasePlugin {
|
|
|
83
83
|
this.#snakeCaseTransformer = new SnakeCaseTransformer(this.snakeCase.bind(this));
|
|
84
84
|
}
|
|
85
85
|
transformQuery(args) {
|
|
86
|
-
return this.#snakeCaseTransformer.transformNode(args.node);
|
|
86
|
+
return this.#snakeCaseTransformer.transformNode(args.node, args.queryId);
|
|
87
87
|
}
|
|
88
88
|
async transformResult(args) {
|
|
89
89
|
if (args.result.rows && Array.isArray(args.result.rows)) {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { IdentifierNode } from '../../operation-node/identifier-node.js';
|
|
2
2
|
import { OperationNodeTransformer } from '../../operation-node/operation-node-transformer.js';
|
|
3
|
+
import { QueryId } from '../../util/query-id.js';
|
|
3
4
|
import { StringMapper } from './camel-case.js';
|
|
4
5
|
export declare class SnakeCaseTransformer extends OperationNodeTransformer {
|
|
5
6
|
#private;
|
|
6
7
|
constructor(snakeCase: StringMapper);
|
|
7
|
-
protected transformIdentifier(node: IdentifierNode): IdentifierNode;
|
|
8
|
+
protected transformIdentifier(node: IdentifierNode, queryId: QueryId): IdentifierNode;
|
|
8
9
|
}
|
|
@@ -6,8 +6,8 @@ export class SnakeCaseTransformer extends OperationNodeTransformer {
|
|
|
6
6
|
super();
|
|
7
7
|
this.#snakeCase = snakeCase;
|
|
8
8
|
}
|
|
9
|
-
transformIdentifier(node) {
|
|
10
|
-
node = super.transformIdentifier(node);
|
|
9
|
+
transformIdentifier(node, queryId) {
|
|
10
|
+
node = super.transformIdentifier(node, queryId);
|
|
11
11
|
return {
|
|
12
12
|
...node,
|
|
13
13
|
name: this.#snakeCase(node.name),
|
|
@@ -8,7 +8,7 @@ import { DeduplicateJoinsTransformer } from './deduplicate-joins-transformer.js'
|
|
|
8
8
|
export class DeduplicateJoinsPlugin {
|
|
9
9
|
#transformer = new DeduplicateJoinsTransformer();
|
|
10
10
|
transformQuery(args) {
|
|
11
|
-
return this.#transformer.transformNode(args.node);
|
|
11
|
+
return this.#transformer.transformNode(args.node, args.queryId);
|
|
12
12
|
}
|
|
13
13
|
transformResult(args) {
|
|
14
14
|
return Promise.resolve(args.result);
|
|
@@ -2,9 +2,10 @@ import { DeleteQueryNode } from '../../operation-node/delete-query-node.js';
|
|
|
2
2
|
import { OperationNodeTransformer } from '../../operation-node/operation-node-transformer.js';
|
|
3
3
|
import { SelectQueryNode } from '../../operation-node/select-query-node.js';
|
|
4
4
|
import { UpdateQueryNode } from '../../operation-node/update-query-node.js';
|
|
5
|
+
import { QueryId } from '../../util/query-id.js';
|
|
5
6
|
export declare class DeduplicateJoinsTransformer extends OperationNodeTransformer {
|
|
6
7
|
#private;
|
|
7
|
-
protected transformSelectQuery(node: SelectQueryNode): SelectQueryNode;
|
|
8
|
-
protected transformUpdateQuery(node: UpdateQueryNode): UpdateQueryNode;
|
|
9
|
-
protected transformDeleteQuery(node: DeleteQueryNode): DeleteQueryNode;
|
|
8
|
+
protected transformSelectQuery(node: SelectQueryNode, queryId: QueryId): SelectQueryNode;
|
|
9
|
+
protected transformUpdateQuery(node: UpdateQueryNode, queryId: QueryId): UpdateQueryNode;
|
|
10
|
+
protected transformDeleteQuery(node: DeleteQueryNode, queryId: QueryId): DeleteQueryNode;
|
|
10
11
|
}
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import { OperationNodeTransformer } from '../../operation-node/operation-node-transformer.js';
|
|
3
3
|
import { compare, freeze } from '../../util/object-utils.js';
|
|
4
4
|
export class DeduplicateJoinsTransformer extends OperationNodeTransformer {
|
|
5
|
-
transformSelectQuery(node) {
|
|
6
|
-
return this.#transformQuery(super.transformSelectQuery(node));
|
|
5
|
+
transformSelectQuery(node, queryId) {
|
|
6
|
+
return this.#transformQuery(super.transformSelectQuery(node, queryId));
|
|
7
7
|
}
|
|
8
|
-
transformUpdateQuery(node) {
|
|
9
|
-
return this.#transformQuery(super.transformUpdateQuery(node));
|
|
8
|
+
transformUpdateQuery(node, queryId) {
|
|
9
|
+
return this.#transformQuery(super.transformUpdateQuery(node, queryId));
|
|
10
10
|
}
|
|
11
|
-
transformDeleteQuery(node) {
|
|
12
|
-
return this.#transformQuery(super.transformDeleteQuery(node));
|
|
11
|
+
transformDeleteQuery(node, queryId) {
|
|
12
|
+
return this.#transformQuery(super.transformDeleteQuery(node, queryId));
|
|
13
13
|
}
|
|
14
14
|
#transformQuery(node) {
|
|
15
15
|
if (!node.joins || node.joins.length === 0) {
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { QueryResult } from '../../driver/database-connection.js';
|
|
2
|
+
import { RootOperationNode } from '../../query-compiler/query-compiler.js';
|
|
3
|
+
import { KyselyPlugin, PluginTransformQueryArgs, PluginTransformResultArgs } from '../kysely-plugin.js';
|
|
4
|
+
import { UnknownRow } from '../../util/type-utils.js';
|
|
5
|
+
import { HandleEmptyInListsOptions } from './handle-empty-in-lists.js';
|
|
6
|
+
/**
|
|
7
|
+
* A plugin that allows handling `in ()` and `not in ()` expressions.
|
|
8
|
+
*
|
|
9
|
+
* These expressions are invalid SQL syntax for many databases, and result in runtime
|
|
10
|
+
* database errors.
|
|
11
|
+
*
|
|
12
|
+
* The workarounds used by other libraries always involve modifying the query under
|
|
13
|
+
* the hood, which is not aligned with Kysely's philosophy of WYSIWYG. We recommend manually checking
|
|
14
|
+
* for empty arrays before passing them as arguments to `in` and `not in` expressions
|
|
15
|
+
* instead, but understand that this can be cumbersome. Hence we're going with an
|
|
16
|
+
* opt-in approach where you can choose if and how to handle these cases. We do
|
|
17
|
+
* not want to make this the default behavior, as it can lead to unexpected behavior.
|
|
18
|
+
* Use it at your own risk. Test it. Make sure it works as expected for you.
|
|
19
|
+
*
|
|
20
|
+
* Using this plugin also allows you to throw an error (thus avoiding unnecessary
|
|
21
|
+
* requests to the database) or print a warning in these cases.
|
|
22
|
+
*
|
|
23
|
+
* ### Examples
|
|
24
|
+
*
|
|
25
|
+
* The following strategy replaces the `in`/`not in` expression with a noncontingent
|
|
26
|
+
* expression. A contradiction (falsy) `1 = 0` for `in`, and a tautology (truthy) `1 = 1` for `not in`),
|
|
27
|
+
* similarily to how {@link https://github.com/knex/knex/blob/176151d8048b2a7feeb89a3d649a5580786d4f4e/docs/src/guide/query-builder.md#L1763 | Knex.js},
|
|
28
|
+
* {@link https://github.com/prisma/prisma-engines/blob/99168c54187178484dae45d9478aa40cfd1866d2/quaint/src/visitor.rs#L804-L823 | PrismaORM},
|
|
29
|
+
* {@link https://github.com/laravel/framework/blob/8.x/src/Illuminate/Database/Query/Grammars/Grammar.php#L284-L291 | Laravel},
|
|
30
|
+
* {@link https://docs.sqlalchemy.org/en/13/core/engines.html#sqlalchemy.create_engine.params.empty_in_strategy | SQLAlchemy}
|
|
31
|
+
* handle this.
|
|
32
|
+
*
|
|
33
|
+
* ```ts
|
|
34
|
+
* import Sqlite from 'better-sqlite3'
|
|
35
|
+
* import {
|
|
36
|
+
* HandleEmptyInListsPlugin,
|
|
37
|
+
* Kysely,
|
|
38
|
+
* replaceWithNoncontingentExpression,
|
|
39
|
+
* SqliteDialect,
|
|
40
|
+
* } from 'kysely'
|
|
41
|
+
* import type { Database } from 'type-editor' // imaginary module
|
|
42
|
+
*
|
|
43
|
+
* const db = new Kysely<Database>({
|
|
44
|
+
* dialect: new SqliteDialect({
|
|
45
|
+
* database: new Sqlite(':memory:'),
|
|
46
|
+
* }),
|
|
47
|
+
* plugins: [
|
|
48
|
+
* new HandleEmptyInListsPlugin({
|
|
49
|
+
* strategy: replaceWithNoncontingentExpression
|
|
50
|
+
* })
|
|
51
|
+
* ],
|
|
52
|
+
* })
|
|
53
|
+
*
|
|
54
|
+
* const results = await db
|
|
55
|
+
* .selectFrom('person')
|
|
56
|
+
* .where('id', 'in', [])
|
|
57
|
+
* .where('first_name', 'not in', [])
|
|
58
|
+
* .selectAll()
|
|
59
|
+
* .execute()
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* The generated SQL (SQLite):
|
|
63
|
+
*
|
|
64
|
+
* ```sql
|
|
65
|
+
* select * from "person" where 1 = 0 and 1 = 1
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* The following strategy does the following:
|
|
69
|
+
*
|
|
70
|
+
* When `in`, pushes a `null` value into the empty list resulting in `in (null)`,
|
|
71
|
+
* similiarly to how {@link https://github.com/typeorm/typeorm/blob/0280cdc451c35ef73c830eb1191c95d34f6ce06e/src/query-builder/QueryBuilder.ts#L919-L922 | TypeORM}
|
|
72
|
+
* and {@link https://github.com/sequelize/sequelize/blob/0f2891c6897e12bf9bf56df344aae5b698f58c7d/packages/core/src/abstract-dialect/where-sql-builder.ts#L368-L379 | Sequelize}
|
|
73
|
+
* handle `in ()`. `in (null)` is logically the equivalent of `= null`, which returns
|
|
74
|
+
* `null`, which is a falsy expression in most SQL databases. We recommend NOT
|
|
75
|
+
* using this strategy if you plan to use `in` in `select`, `returning`, or `output`
|
|
76
|
+
* clauses, as the return type differs from the `SqlBool` default type for comparisons.
|
|
77
|
+
*
|
|
78
|
+
* When `not in`, casts the left operand as `char` and pushes a unique value into
|
|
79
|
+
* the empty list resulting in `cast({{lhs}} as char) not in ({{VALUE}})`. Casting
|
|
80
|
+
* is required to avoid database errors with non-string values.
|
|
81
|
+
*
|
|
82
|
+
* ```ts
|
|
83
|
+
* import Sqlite from 'better-sqlite3'
|
|
84
|
+
* import {
|
|
85
|
+
* HandleEmptyInListsPlugin,
|
|
86
|
+
* Kysely,
|
|
87
|
+
* pushValueIntoList,
|
|
88
|
+
* SqliteDialect
|
|
89
|
+
* } from 'kysely'
|
|
90
|
+
* import type { Database } from 'type-editor' // imaginary module
|
|
91
|
+
*
|
|
92
|
+
* const db = new Kysely<Database>({
|
|
93
|
+
* dialect: new SqliteDialect({
|
|
94
|
+
* database: new Sqlite(':memory:'),
|
|
95
|
+
* }),
|
|
96
|
+
* plugins: [
|
|
97
|
+
* new HandleEmptyInListsPlugin({
|
|
98
|
+
* strategy: pushValueIntoList('__kysely_no_values_were_provided__') // choose a unique value for not in. has to be something with zero chance being in the data.
|
|
99
|
+
* })
|
|
100
|
+
* ],
|
|
101
|
+
* })
|
|
102
|
+
*
|
|
103
|
+
* const results = await db
|
|
104
|
+
* .selectFrom('person')
|
|
105
|
+
* .where('id', 'in', [])
|
|
106
|
+
* .where('first_name', 'not in', [])
|
|
107
|
+
* .selectAll()
|
|
108
|
+
* .execute()
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* The generated SQL (SQLite):
|
|
112
|
+
*
|
|
113
|
+
* ```sql
|
|
114
|
+
* select * from "person" where "id" in (null) and cast("first_name" as char) not in ('__kysely_no_values_were_provided__')
|
|
115
|
+
* ```
|
|
116
|
+
*
|
|
117
|
+
* The following custom strategy throws an error when an empty list is encountered
|
|
118
|
+
* to avoid unnecessary requests to the database:
|
|
119
|
+
*
|
|
120
|
+
* ```ts
|
|
121
|
+
* import Sqlite from 'better-sqlite3'
|
|
122
|
+
* import {
|
|
123
|
+
* HandleEmptyInListsPlugin,
|
|
124
|
+
* Kysely,
|
|
125
|
+
* SqliteDialect
|
|
126
|
+
* } from 'kysely'
|
|
127
|
+
* import type { Database } from 'type-editor' // imaginary module
|
|
128
|
+
*
|
|
129
|
+
* const db = new Kysely<Database>({
|
|
130
|
+
* dialect: new SqliteDialect({
|
|
131
|
+
* database: new Sqlite(':memory:'),
|
|
132
|
+
* }),
|
|
133
|
+
* plugins: [
|
|
134
|
+
* new HandleEmptyInListsPlugin({
|
|
135
|
+
* strategy: () => {
|
|
136
|
+
* throw new Error('Empty in/not-in is not allowed')
|
|
137
|
+
* }
|
|
138
|
+
* })
|
|
139
|
+
* ],
|
|
140
|
+
* })
|
|
141
|
+
*
|
|
142
|
+
* const results = await db
|
|
143
|
+
* .selectFrom('person')
|
|
144
|
+
* .where('id', 'in', [])
|
|
145
|
+
* .selectAll()
|
|
146
|
+
* .execute() // throws an error with 'Empty in/not-in is not allowed' message!
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export declare class HandleEmptyInListsPlugin implements KyselyPlugin {
|
|
150
|
+
#private;
|
|
151
|
+
readonly opt: HandleEmptyInListsOptions;
|
|
152
|
+
constructor(opt: HandleEmptyInListsOptions);
|
|
153
|
+
/**
|
|
154
|
+
* This is called for each query before it is executed. You can modify the query by
|
|
155
|
+
* transforming its {@link OperationNode} tree provided in {@link PluginTransformQueryArgs.node | args.node}
|
|
156
|
+
* and returning the transformed tree. You'd usually want to use an {@link OperationNodeTransformer}
|
|
157
|
+
* for this.
|
|
158
|
+
*
|
|
159
|
+
* If you need to pass some query-related data between this method and `transformResult` you
|
|
160
|
+
* can use a `WeakMap` with {@link PluginTransformQueryArgs.queryId | args.queryId} as the key:
|
|
161
|
+
*
|
|
162
|
+
* ```ts
|
|
163
|
+
* import type {
|
|
164
|
+
* KyselyPlugin,
|
|
165
|
+
* QueryResult,
|
|
166
|
+
* RootOperationNode,
|
|
167
|
+
* UnknownRow
|
|
168
|
+
* } from 'kysely'
|
|
169
|
+
*
|
|
170
|
+
* interface MyData {
|
|
171
|
+
* // ...
|
|
172
|
+
* }
|
|
173
|
+
* const data = new WeakMap<any, MyData>()
|
|
174
|
+
*
|
|
175
|
+
* const plugin = {
|
|
176
|
+
* transformQuery(args: PluginTransformQueryArgs): RootOperationNode {
|
|
177
|
+
* const something: MyData = {}
|
|
178
|
+
*
|
|
179
|
+
* // ...
|
|
180
|
+
*
|
|
181
|
+
* data.set(args.queryId, something)
|
|
182
|
+
*
|
|
183
|
+
* // ...
|
|
184
|
+
*
|
|
185
|
+
* return args.node
|
|
186
|
+
* },
|
|
187
|
+
*
|
|
188
|
+
* async transformResult(args: PluginTransformResultArgs): Promise<QueryResult<UnknownRow>> {
|
|
189
|
+
* // ...
|
|
190
|
+
*
|
|
191
|
+
* const something = data.get(args.queryId)
|
|
192
|
+
*
|
|
193
|
+
* // ...
|
|
194
|
+
*
|
|
195
|
+
* return args.result
|
|
196
|
+
* }
|
|
197
|
+
* } satisfies KyselyPlugin
|
|
198
|
+
* ```
|
|
199
|
+
*
|
|
200
|
+
* You should use a `WeakMap` instead of a `Map` or some other strong references because `transformQuery`
|
|
201
|
+
* is not always matched by a call to `transformResult` which would leave orphaned items in the map
|
|
202
|
+
* and cause a memory leak.
|
|
203
|
+
*/
|
|
204
|
+
transformQuery(args: PluginTransformQueryArgs): RootOperationNode;
|
|
205
|
+
/**
|
|
206
|
+
* This method is called for each query after it has been executed. The result
|
|
207
|
+
* of the query can be accessed through {@link PluginTransformResultArgs.result | args.result}.
|
|
208
|
+
* You can modify the result and return the modifier result.
|
|
209
|
+
*/
|
|
210
|
+
transformResult(args: PluginTransformResultArgs): Promise<QueryResult<UnknownRow>>;
|
|
211
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/// <reference types="./handle-empty-in-lists-plugin.d.ts" />
|
|
2
|
+
import { HandleEmptyInListsTransformer } from './handle-empty-in-lists-transformer.js';
|
|
3
|
+
/**
|
|
4
|
+
* A plugin that allows handling `in ()` and `not in ()` expressions.
|
|
5
|
+
*
|
|
6
|
+
* These expressions are invalid SQL syntax for many databases, and result in runtime
|
|
7
|
+
* database errors.
|
|
8
|
+
*
|
|
9
|
+
* The workarounds used by other libraries always involve modifying the query under
|
|
10
|
+
* the hood, which is not aligned with Kysely's philosophy of WYSIWYG. We recommend manually checking
|
|
11
|
+
* for empty arrays before passing them as arguments to `in` and `not in` expressions
|
|
12
|
+
* instead, but understand that this can be cumbersome. Hence we're going with an
|
|
13
|
+
* opt-in approach where you can choose if and how to handle these cases. We do
|
|
14
|
+
* not want to make this the default behavior, as it can lead to unexpected behavior.
|
|
15
|
+
* Use it at your own risk. Test it. Make sure it works as expected for you.
|
|
16
|
+
*
|
|
17
|
+
* Using this plugin also allows you to throw an error (thus avoiding unnecessary
|
|
18
|
+
* requests to the database) or print a warning in these cases.
|
|
19
|
+
*
|
|
20
|
+
* ### Examples
|
|
21
|
+
*
|
|
22
|
+
* The following strategy replaces the `in`/`not in` expression with a noncontingent
|
|
23
|
+
* expression. A contradiction (falsy) `1 = 0` for `in`, and a tautology (truthy) `1 = 1` for `not in`),
|
|
24
|
+
* similarily to how {@link https://github.com/knex/knex/blob/176151d8048b2a7feeb89a3d649a5580786d4f4e/docs/src/guide/query-builder.md#L1763 | Knex.js},
|
|
25
|
+
* {@link https://github.com/prisma/prisma-engines/blob/99168c54187178484dae45d9478aa40cfd1866d2/quaint/src/visitor.rs#L804-L823 | PrismaORM},
|
|
26
|
+
* {@link https://github.com/laravel/framework/blob/8.x/src/Illuminate/Database/Query/Grammars/Grammar.php#L284-L291 | Laravel},
|
|
27
|
+
* {@link https://docs.sqlalchemy.org/en/13/core/engines.html#sqlalchemy.create_engine.params.empty_in_strategy | SQLAlchemy}
|
|
28
|
+
* handle this.
|
|
29
|
+
*
|
|
30
|
+
* ```ts
|
|
31
|
+
* import Sqlite from 'better-sqlite3'
|
|
32
|
+
* import {
|
|
33
|
+
* HandleEmptyInListsPlugin,
|
|
34
|
+
* Kysely,
|
|
35
|
+
* replaceWithNoncontingentExpression,
|
|
36
|
+
* SqliteDialect,
|
|
37
|
+
* } from 'kysely'
|
|
38
|
+
* import type { Database } from 'type-editor' // imaginary module
|
|
39
|
+
*
|
|
40
|
+
* const db = new Kysely<Database>({
|
|
41
|
+
* dialect: new SqliteDialect({
|
|
42
|
+
* database: new Sqlite(':memory:'),
|
|
43
|
+
* }),
|
|
44
|
+
* plugins: [
|
|
45
|
+
* new HandleEmptyInListsPlugin({
|
|
46
|
+
* strategy: replaceWithNoncontingentExpression
|
|
47
|
+
* })
|
|
48
|
+
* ],
|
|
49
|
+
* })
|
|
50
|
+
*
|
|
51
|
+
* const results = await db
|
|
52
|
+
* .selectFrom('person')
|
|
53
|
+
* .where('id', 'in', [])
|
|
54
|
+
* .where('first_name', 'not in', [])
|
|
55
|
+
* .selectAll()
|
|
56
|
+
* .execute()
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* The generated SQL (SQLite):
|
|
60
|
+
*
|
|
61
|
+
* ```sql
|
|
62
|
+
* select * from "person" where 1 = 0 and 1 = 1
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* The following strategy does the following:
|
|
66
|
+
*
|
|
67
|
+
* When `in`, pushes a `null` value into the empty list resulting in `in (null)`,
|
|
68
|
+
* similiarly to how {@link https://github.com/typeorm/typeorm/blob/0280cdc451c35ef73c830eb1191c95d34f6ce06e/src/query-builder/QueryBuilder.ts#L919-L922 | TypeORM}
|
|
69
|
+
* and {@link https://github.com/sequelize/sequelize/blob/0f2891c6897e12bf9bf56df344aae5b698f58c7d/packages/core/src/abstract-dialect/where-sql-builder.ts#L368-L379 | Sequelize}
|
|
70
|
+
* handle `in ()`. `in (null)` is logically the equivalent of `= null`, which returns
|
|
71
|
+
* `null`, which is a falsy expression in most SQL databases. We recommend NOT
|
|
72
|
+
* using this strategy if you plan to use `in` in `select`, `returning`, or `output`
|
|
73
|
+
* clauses, as the return type differs from the `SqlBool` default type for comparisons.
|
|
74
|
+
*
|
|
75
|
+
* When `not in`, casts the left operand as `char` and pushes a unique value into
|
|
76
|
+
* the empty list resulting in `cast({{lhs}} as char) not in ({{VALUE}})`. Casting
|
|
77
|
+
* is required to avoid database errors with non-string values.
|
|
78
|
+
*
|
|
79
|
+
* ```ts
|
|
80
|
+
* import Sqlite from 'better-sqlite3'
|
|
81
|
+
* import {
|
|
82
|
+
* HandleEmptyInListsPlugin,
|
|
83
|
+
* Kysely,
|
|
84
|
+
* pushValueIntoList,
|
|
85
|
+
* SqliteDialect
|
|
86
|
+
* } from 'kysely'
|
|
87
|
+
* import type { Database } from 'type-editor' // imaginary module
|
|
88
|
+
*
|
|
89
|
+
* const db = new Kysely<Database>({
|
|
90
|
+
* dialect: new SqliteDialect({
|
|
91
|
+
* database: new Sqlite(':memory:'),
|
|
92
|
+
* }),
|
|
93
|
+
* plugins: [
|
|
94
|
+
* new HandleEmptyInListsPlugin({
|
|
95
|
+
* strategy: pushValueIntoList('__kysely_no_values_were_provided__') // choose a unique value for not in. has to be something with zero chance being in the data.
|
|
96
|
+
* })
|
|
97
|
+
* ],
|
|
98
|
+
* })
|
|
99
|
+
*
|
|
100
|
+
* const results = await db
|
|
101
|
+
* .selectFrom('person')
|
|
102
|
+
* .where('id', 'in', [])
|
|
103
|
+
* .where('first_name', 'not in', [])
|
|
104
|
+
* .selectAll()
|
|
105
|
+
* .execute()
|
|
106
|
+
* ```
|
|
107
|
+
*
|
|
108
|
+
* The generated SQL (SQLite):
|
|
109
|
+
*
|
|
110
|
+
* ```sql
|
|
111
|
+
* select * from "person" where "id" in (null) and cast("first_name" as char) not in ('__kysely_no_values_were_provided__')
|
|
112
|
+
* ```
|
|
113
|
+
*
|
|
114
|
+
* The following custom strategy throws an error when an empty list is encountered
|
|
115
|
+
* to avoid unnecessary requests to the database:
|
|
116
|
+
*
|
|
117
|
+
* ```ts
|
|
118
|
+
* import Sqlite from 'better-sqlite3'
|
|
119
|
+
* import {
|
|
120
|
+
* HandleEmptyInListsPlugin,
|
|
121
|
+
* Kysely,
|
|
122
|
+
* SqliteDialect
|
|
123
|
+
* } from 'kysely'
|
|
124
|
+
* import type { Database } from 'type-editor' // imaginary module
|
|
125
|
+
*
|
|
126
|
+
* const db = new Kysely<Database>({
|
|
127
|
+
* dialect: new SqliteDialect({
|
|
128
|
+
* database: new Sqlite(':memory:'),
|
|
129
|
+
* }),
|
|
130
|
+
* plugins: [
|
|
131
|
+
* new HandleEmptyInListsPlugin({
|
|
132
|
+
* strategy: () => {
|
|
133
|
+
* throw new Error('Empty in/not-in is not allowed')
|
|
134
|
+
* }
|
|
135
|
+
* })
|
|
136
|
+
* ],
|
|
137
|
+
* })
|
|
138
|
+
*
|
|
139
|
+
* const results = await db
|
|
140
|
+
* .selectFrom('person')
|
|
141
|
+
* .where('id', 'in', [])
|
|
142
|
+
* .selectAll()
|
|
143
|
+
* .execute() // throws an error with 'Empty in/not-in is not allowed' message!
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
export class HandleEmptyInListsPlugin {
|
|
147
|
+
opt;
|
|
148
|
+
#transformer;
|
|
149
|
+
constructor(opt) {
|
|
150
|
+
this.opt = opt;
|
|
151
|
+
this.#transformer = new HandleEmptyInListsTransformer(opt.strategy);
|
|
152
|
+
}
|
|
153
|
+
transformQuery(args) {
|
|
154
|
+
return this.#transformer.transformNode(args.node, args.queryId);
|
|
155
|
+
}
|
|
156
|
+
async transformResult(args) {
|
|
157
|
+
return args.result;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { BinaryOperationNode } from '../../operation-node/binary-operation-node.js';
|
|
2
|
+
import { OperationNodeTransformer } from '../../operation-node/operation-node-transformer.js';
|
|
3
|
+
import { EmptyInListsStrategy } from './handle-empty-in-lists.js';
|
|
4
|
+
export declare class HandleEmptyInListsTransformer extends OperationNodeTransformer {
|
|
5
|
+
#private;
|
|
6
|
+
constructor(strategy: EmptyInListsStrategy);
|
|
7
|
+
protected transformBinaryOperation(node: BinaryOperationNode): BinaryOperationNode;
|
|
8
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/// <reference types="./handle-empty-in-lists-transformer.d.ts" />
|
|
2
|
+
import { OperationNodeTransformer } from '../../operation-node/operation-node-transformer.js';
|
|
3
|
+
import { PrimitiveValueListNode } from '../../operation-node/primitive-value-list-node.js';
|
|
4
|
+
import { OperatorNode } from '../../operation-node/operator-node.js';
|
|
5
|
+
import { ValueListNode } from '../../operation-node/value-list-node.js';
|
|
6
|
+
export class HandleEmptyInListsTransformer extends OperationNodeTransformer {
|
|
7
|
+
#strategy;
|
|
8
|
+
constructor(strategy) {
|
|
9
|
+
super();
|
|
10
|
+
this.#strategy = strategy;
|
|
11
|
+
}
|
|
12
|
+
transformBinaryOperation(node) {
|
|
13
|
+
if (this.#isEmptyInListNode(node)) {
|
|
14
|
+
return this.#strategy(node);
|
|
15
|
+
}
|
|
16
|
+
return node;
|
|
17
|
+
}
|
|
18
|
+
#isEmptyInListNode(node) {
|
|
19
|
+
const { operator, rightOperand } = node;
|
|
20
|
+
return ((PrimitiveValueListNode.is(rightOperand) ||
|
|
21
|
+
ValueListNode.is(rightOperand)) &&
|
|
22
|
+
rightOperand.values.length === 0 &&
|
|
23
|
+
OperatorNode.is(operator) &&
|
|
24
|
+
(operator.operator === 'in' || operator.operator === 'not in'));
|
|
25
|
+
}
|
|
26
|
+
}
|