├── .github └── workflows │ ├── preview.yml │ └── test.yml ├── .gitignore ├── .node-version ├── .nvmrc ├── .prettierignore ├── .prettierrc.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── FUNDING.md ├── LICENSE ├── README.md ├── assets └── demo.gif ├── deno.check.d.ts ├── deno.check.json ├── docker-compose.yml ├── docs └── index.html ├── example ├── .env ├── .gitignore ├── .prettierrc.json ├── README.md ├── package-lock.json ├── package.json ├── src │ ├── app.ts │ ├── authentication │ │ ├── auth-token.service.ts │ │ ├── auth-token.ts │ │ ├── authentication.service.ts │ │ ├── refresh-token.repository.ts │ │ ├── refresh-token.table.ts │ │ └── refresh-token.ts │ ├── config.ts │ ├── context.ts │ ├── database.ts │ ├── migrate-to-latest.ts │ ├── migrations │ │ ├── 2021_09_18_06_54_59_create_user.ts │ │ ├── 2021_09_18_14_05_20_create_refresh_token.ts │ │ └── 2021_09_18_18_22_45_create_sign_in_method.ts │ ├── router.ts │ ├── user │ │ ├── sign-in-method │ │ │ ├── password-sign-in-method.table.ts │ │ │ ├── sign-in-method.controller.ts │ │ │ ├── sign-in-method.repository.ts │ │ │ ├── sign-in-method.service.ts │ │ │ ├── sign-in-method.table.ts │ │ │ └── sign-in-method.ts │ │ ├── signed-in-user.ts │ │ ├── user.controller.ts │ │ ├── user.repository.ts │ │ ├── user.service.ts │ │ ├── user.table.ts │ │ └── user.ts │ └── util │ │ ├── ajv.ts │ │ ├── errors.ts │ │ └── object.ts ├── test │ ├── test-config.ts │ ├── test-context.ts │ └── user │ │ └── user.test.ts └── tsconfig.json ├── outdated-typescript.d.ts ├── package-lock.json ├── package.json ├── scripts ├── add-deno-type-references.js ├── align-site-version.js ├── check-esm-imports.js ├── check-exports.js ├── copy-interface-documentation.js ├── exclude-test-files-for-backwards-compat.mts ├── generate-site-examples.js ├── module-fixup.js ├── tsconfig.json └── util │ └── for-each-file.js ├── site ├── .gitignore ├── babel.config.js ├── docs │ ├── dialects.md │ ├── examples │ │ ├── _category_.json │ │ ├── cte │ │ │ ├── 0010-simple-selects.js │ │ │ ├── 0010-simple-selects.mdx │ │ │ ├── 0020-inserts-updates-and-deletions.js │ │ │ ├── 0020-inserts-updates-and-deletions.mdx │ │ │ └── _category_.json │ │ ├── delete │ │ │ ├── 0010-single-row.js │ │ │ ├── 0010-single-row.mdx │ │ │ └── _category_.json │ │ ├── insert │ │ │ ├── 0010-single-row.js │ │ │ ├── 0010-single-row.mdx │ │ │ ├── 0020-multiple-rows.js │ │ │ ├── 0020-multiple-rows.mdx │ │ │ ├── 0030-returning-data.js │ │ │ ├── 0030-returning-data.mdx │ │ │ ├── 0040-complex-values.js │ │ │ ├── 0040-complex-values.mdx │ │ │ ├── 0050-insert-subquery.js │ │ │ ├── 0050-insert-subquery.mdx │ │ │ └── _category_.json │ │ ├── join │ │ │ ├── 0010-simple-inner-join.js │ │ │ ├── 0010-simple-inner-join.mdx │ │ │ ├── 0020-aliased-inner-join.js │ │ │ ├── 0020-aliased-inner-join.mdx │ │ │ ├── 0030-complex-join.js │ │ │ ├── 0030-complex-join.mdx │ │ │ ├── 0040-subquery-join.js │ │ │ ├── 0040-subquery-join.mdx │ │ │ └── _category_.json │ │ ├── merge │ │ │ ├── 0010-source-row-existence.js │ │ │ ├── 0010-source-row-existence.mdx │ │ │ ├── 0020-temporary-changes-table.js │ │ │ ├── 0020-temporary-changes-table.mdx │ │ │ └── _category_.json │ │ ├── select │ │ │ ├── 0010-a-single-column.js │ │ │ ├── 0010-a-single-column.mdx │ │ │ ├── 0020-column-with-a-table.js │ │ │ ├── 0020-column-with-a-table.mdx │ │ │ ├── 0030-multiple-columns.js │ │ │ ├── 0030-multiple-columns.mdx │ │ │ ├── 0040-aliases.js │ │ │ ├── 0040-aliases.mdx │ │ │ ├── 0050-complex-selections.js │ │ │ ├── 0050-complex-selections.mdx │ │ │ ├── 0051-not-null.js │ │ │ ├── 0051-not-null.mdx │ │ │ ├── 0060-function-calls.js │ │ │ ├── 0060-function-calls.mdx │ │ │ ├── 0070-distinct.js │ │ │ ├── 0070-distinct.mdx │ │ │ ├── 0080-distinct-on.js │ │ │ ├── 0080-distinct-on.mdx │ │ │ ├── 0090-all-columns.js │ │ │ ├── 0090-all-columns.mdx │ │ │ ├── 0100-all-columns-of-a-table.js │ │ │ ├── 0100-all-columns-of-a-table.mdx │ │ │ ├── 0110-nested-array.js │ │ │ ├── 0110-nested-array.mdx │ │ │ ├── 0120-nested-object.js │ │ │ ├── 0120-nested-object.mdx │ │ │ ├── 0130-generic-find-query.js │ │ │ ├── 0130-generic-find-query.mdx │ │ │ └── _category_.json │ │ ├── transactions │ │ │ ├── 0010-simple-transaction.js │ │ │ ├── 0010-simple-transaction.mdx │ │ │ ├── 0011-controlled-transaction.js │ │ │ ├── 0011-controlled-transaction.mdx │ │ │ ├── 0012-controlled-transaction-w-savepoints.js │ │ │ ├── 0012-controlled-transaction-w-savepoints.mdx │ │ │ └── _category_.json │ │ ├── update │ │ │ ├── 0010-single-row.js │ │ │ ├── 0010-single-row.mdx │ │ │ ├── 0020-complex-values.js │ │ │ ├── 0020-complex-values.mdx │ │ │ ├── 0030-my-sql-joins.js │ │ │ ├── 0030-my-sql-joins.mdx │ │ │ └── _category_.json │ │ └── where │ │ │ ├── 0010-simple-where-clause.js │ │ │ ├── 0010-simple-where-clause.mdx │ │ │ ├── 0020-where-in.js │ │ │ ├── 0020-where-in.mdx │ │ │ ├── 0030-object-filter.js │ │ │ ├── 0030-object-filter.mdx │ │ │ ├── 0040-or-where.js │ │ │ ├── 0040-or-where.mdx │ │ │ ├── 0050-conditional-where-calls.js │ │ │ ├── 0050-conditional-where-calls.mdx │ │ │ ├── 0060-complex-where-clause.js │ │ │ ├── 0060-complex-where-clause.mdx │ │ │ └── _category_.json │ ├── generating-types.md │ ├── getting-started.mdx │ ├── getting-started │ │ ├── Dialects.tsx │ │ ├── IUseADifferentDatabase.tsx │ │ ├── IUseADifferentPackageManager.tsx │ │ ├── Installation.tsx │ │ ├── Instantiation.tsx │ │ ├── Querying.tsx │ │ ├── Summary.tsx │ │ ├── _prerequisites.mdx │ │ ├── _types.mdx │ │ └── shared.tsx │ ├── intro.mdx │ ├── migrations.mdx │ ├── playground.mdx │ ├── plugins.md │ ├── recipes │ │ ├── 0001-relations.md │ │ ├── 0001-reusable-helpers.md │ │ ├── 0002-data-types.md │ │ ├── 0003-raw-sql.md │ │ ├── 0004-splitting-query-building-and-execution.md │ │ ├── 0005-conditional-selects.md │ │ ├── 0006-expressions.md │ │ ├── 0007-schemas.md │ │ ├── 0008-deduplicate-joins.md │ │ ├── 0009-excessively-deep-types.md │ │ ├── 0010-extending-kysely.md │ │ ├── 0011-introspecting-relation-metadata.md │ │ ├── 0012-logging.md │ │ └── _category_.json │ └── runtimes │ │ ├── _category_.json │ │ ├── browser.md │ │ └── deno.mdx ├── docusaurus.config.ts ├── package-lock.json ├── package.json ├── sidebars.js ├── src │ ├── components │ │ ├── DemoVideo.module.css │ │ ├── DemoVideo.tsx │ │ ├── Playground.module.css │ │ ├── Playground.tsx │ │ ├── SectionFeatures │ │ │ ├── index.tsx │ │ │ └── styles.module.css │ │ ├── SectionQuotes │ │ │ ├── Quote.tsx │ │ │ ├── index.tsx │ │ │ ├── quotes.ts │ │ │ ├── reddit.module.css │ │ │ └── styles.module.css │ │ └── playground-example-types.ts │ ├── css │ │ └── custom.css │ └── pages │ │ ├── index.module.css │ │ └── index.tsx ├── static │ ├── .nojekyll │ ├── demo.mp4 │ └── img │ │ ├── avatars │ │ ├── alberto.jpeg │ │ ├── alexanderson.jpeg │ │ ├── bekacru.png │ │ ├── benholmes.jpeg │ │ ├── capaj.png │ │ ├── catalin.png │ │ ├── daxraad.jpeg │ │ ├── gal.jpeg │ │ ├── gannon.jpeg │ │ ├── gudmundur.png │ │ ├── guga.png │ │ ├── harminder.png │ │ ├── johan.jpeg │ │ ├── julius.jpeg │ │ ├── leerob.jpeg │ │ ├── marvin.png │ │ ├── marvinh.jpeg │ │ ├── mehul.jpeg │ │ ├── nexxel.jpeg │ │ ├── nicholas.jpeg │ │ ├── niels.png │ │ ├── orta.jpeg │ │ ├── pilcrowonpaper.jpeg │ │ ├── ross.jpeg │ │ ├── samcook.jpeg │ │ ├── sommelier.jpeg │ │ ├── tgriesser.jpeg │ │ ├── theo.jpeg │ │ └── yusuke.jpeg │ │ ├── docusaurus.png │ │ ├── favicon.ico │ │ ├── logo.svg │ │ ├── powered-by-vercel.svg │ │ ├── undraw_docusaurus_mountain.svg │ │ ├── undraw_docusaurus_react.svg │ │ └── undraw_docusaurus_tree.svg └── tsconfig.json ├── src ├── dialect │ ├── database-introspector.ts │ ├── dialect-adapter-base.ts │ ├── dialect-adapter.ts │ ├── dialect.ts │ ├── mssql │ │ ├── mssql-adapter.ts │ │ ├── mssql-dialect-config.ts │ │ ├── mssql-dialect.ts │ │ ├── mssql-driver.ts │ │ ├── mssql-introspector.ts │ │ └── mssql-query-compiler.ts │ ├── mysql │ │ ├── mysql-adapter.ts │ │ ├── mysql-dialect-config.ts │ │ ├── mysql-dialect.ts │ │ ├── mysql-driver.ts │ │ ├── mysql-introspector.ts │ │ └── mysql-query-compiler.ts │ ├── postgres │ │ ├── postgres-adapter.ts │ │ ├── postgres-dialect-config.ts │ │ ├── postgres-dialect.ts │ │ ├── postgres-driver.ts │ │ ├── postgres-introspector.ts │ │ └── postgres-query-compiler.ts │ └── sqlite │ │ ├── sqlite-adapter.ts │ │ ├── sqlite-dialect-config.ts │ │ ├── sqlite-dialect.ts │ │ ├── sqlite-driver.ts │ │ ├── sqlite-introspector.ts │ │ └── sqlite-query-compiler.ts ├── driver │ ├── connection-provider.ts │ ├── database-connection.ts │ ├── default-connection-provider.ts │ ├── driver.ts │ ├── dummy-driver.ts │ ├── runtime-driver.ts │ └── single-connection-provider.ts ├── dynamic │ ├── dynamic-reference-builder.ts │ ├── dynamic-table-builder.ts │ └── dynamic.ts ├── expression │ ├── expression-builder.ts │ ├── expression-wrapper.ts │ └── expression.ts ├── helpers │ ├── mssql.ts │ ├── mysql.ts │ ├── postgres.ts │ └── sqlite.ts ├── index.ts ├── kysely.ts ├── migration │ ├── file-migration-provider.ts │ └── migrator.ts ├── operation-node │ ├── add-column-node.ts │ ├── add-constraint-node.ts │ ├── add-index-node.ts │ ├── aggregate-function-node.ts │ ├── alias-node.ts │ ├── alter-column-node.ts │ ├── alter-table-node.ts │ ├── and-node.ts │ ├── binary-operation-node.ts │ ├── case-node.ts │ ├── cast-node.ts │ ├── check-constraint-node.ts │ ├── collate-node.ts │ ├── column-definition-node.ts │ ├── column-node.ts │ ├── column-update-node.ts │ ├── common-table-expression-name-node.ts │ ├── common-table-expression-node.ts │ ├── constraint-node.ts │ ├── create-index-node.ts │ ├── create-schema-node.ts │ ├── create-table-node.ts │ ├── create-type-node.ts │ ├── create-view-node.ts │ ├── data-type-node.ts │ ├── default-insert-value-node.ts │ ├── default-value-node.ts │ ├── delete-query-node.ts │ ├── drop-column-node.ts │ ├── drop-constraint-node.ts │ ├── drop-index-node.ts │ ├── drop-schema-node.ts │ ├── drop-table-node.ts │ ├── drop-type-node.ts │ ├── drop-view-node.ts │ ├── explain-node.ts │ ├── fetch-node.ts │ ├── foreign-key-constraint-node.ts │ ├── from-node.ts │ ├── function-node.ts │ ├── generated-node.ts │ ├── group-by-item-node.ts │ ├── group-by-node.ts │ ├── having-node.ts │ ├── identifier-node.ts │ ├── insert-query-node.ts │ ├── join-node.ts │ ├── json-operator-chain-node.ts │ ├── json-path-leg-node.ts │ ├── json-path-node.ts │ ├── json-reference-node.ts │ ├── limit-node.ts │ ├── list-node.ts │ ├── matched-node.ts │ ├── merge-query-node.ts │ ├── modify-column-node.ts │ ├── offset-node.ts │ ├── on-conflict-node.ts │ ├── on-duplicate-key-node.ts │ ├── on-node.ts │ ├── operation-node-source.ts │ ├── operation-node-transformer.ts │ ├── operation-node-visitor.ts │ ├── operation-node.ts │ ├── operator-node.ts │ ├── or-action-node.ts │ ├── or-node.ts │ ├── order-by-item-node.ts │ ├── order-by-node.ts │ ├── output-node.ts │ ├── over-node.ts │ ├── parens-node.ts │ ├── partition-by-item-node.ts │ ├── partition-by-node.ts │ ├── primary-key-constraint-node.ts │ ├── primitive-value-list-node.ts │ ├── query-node.ts │ ├── raw-node.ts │ ├── reference-node.ts │ ├── references-node.ts │ ├── refresh-materialized-view-node.ts │ ├── rename-column-node.ts │ ├── rename-constraint-node.ts │ ├── returning-node.ts │ ├── schemable-identifier-node.ts │ ├── select-all-node.ts │ ├── select-modifier-node.ts │ ├── select-query-node.ts │ ├── selection-node.ts │ ├── set-operation-node.ts │ ├── simple-reference-expression-node.ts │ ├── table-node.ts │ ├── top-node.ts │ ├── tuple-node.ts │ ├── unary-operation-node.ts │ ├── unique-constraint-node.ts │ ├── update-query-node.ts │ ├── using-node.ts │ ├── value-list-node.ts │ ├── value-node.ts │ ├── values-node.ts │ ├── when-node.ts │ ├── where-node.ts │ └── with-node.ts ├── parser │ ├── binary-operation-parser.ts │ ├── coalesce-parser.ts │ ├── collate-parser.ts │ ├── data-type-parser.ts │ ├── default-value-parser.ts │ ├── delete-from-parser.ts │ ├── expression-parser.ts │ ├── fetch-parser.ts │ ├── group-by-parser.ts │ ├── identifier-parser.ts │ ├── insert-values-parser.ts │ ├── join-parser.ts │ ├── merge-into-parser.ts │ ├── merge-parser.ts │ ├── on-commit-action-parse.ts │ ├── on-modify-action-parser.ts │ ├── order-by-parser.ts │ ├── parse-utils.ts │ ├── partition-by-parser.ts │ ├── reference-parser.ts │ ├── returning-parser.ts │ ├── savepoint-parser.ts │ ├── select-from-parser.ts │ ├── select-parser.ts │ ├── set-operation-parser.ts │ ├── table-parser.ts │ ├── top-parser.ts │ ├── tuple-parser.ts │ ├── unary-operation-parser.ts │ ├── update-parser.ts │ ├── update-set-parser.ts │ ├── value-parser.ts │ └── with-parser.ts ├── plugin │ ├── camel-case │ │ ├── camel-case-plugin.ts │ │ ├── camel-case-transformer.ts │ │ └── camel-case.ts │ ├── deduplicate-joins │ │ ├── deduplicate-joins-plugin.ts │ │ └── deduplicate-joins-transformer.ts │ ├── handle-empty-in-lists │ │ ├── handle-empty-in-lists-plugin.ts │ │ ├── handle-empty-in-lists-transformer.ts │ │ └── handle-empty-in-lists.ts │ ├── immediate-value │ │ ├── immediate-value-plugin.ts │ │ └── immediate-value-transformer.ts │ ├── kysely-plugin.ts │ ├── noop-plugin.ts │ ├── parse-json-results │ │ └── parse-json-results-plugin.ts │ └── with-schema │ │ ├── with-schema-plugin.ts │ │ └── with-schema-transformer.ts ├── query-builder │ ├── aggregate-function-builder.ts │ ├── case-builder.ts │ ├── cte-builder.ts │ ├── delete-query-builder.ts │ ├── delete-result.ts │ ├── function-module.ts │ ├── having-interface.ts │ ├── insert-query-builder.ts │ ├── insert-result.ts │ ├── join-builder.ts │ ├── json-path-builder.ts │ ├── merge-query-builder.ts │ ├── merge-result.ts │ ├── no-result-error.ts │ ├── on-conflict-builder.ts │ ├── order-by-interface.ts │ ├── order-by-item-builder.ts │ ├── output-interface.ts │ ├── over-builder.ts │ ├── returning-interface.ts │ ├── select-query-builder-expression.ts │ ├── select-query-builder.ts │ ├── update-query-builder.ts │ ├── update-result.ts │ └── where-interface.ts ├── query-compiler │ ├── compiled-query.ts │ ├── default-query-compiler.ts │ └── query-compiler.ts ├── query-creator.ts ├── query-executor │ ├── default-query-executor.ts │ ├── noop-query-executor.ts │ ├── query-executor-base.ts │ ├── query-executor-provider.ts │ └── query-executor.ts ├── raw-builder │ ├── raw-builder.ts │ └── sql.ts ├── schema │ ├── alter-column-builder.ts │ ├── alter-table-add-foreign-key-constraint-builder.ts │ ├── alter-table-add-index-builder.ts │ ├── alter-table-builder.ts │ ├── alter-table-drop-constraint-builder.ts │ ├── alter-table-executor.ts │ ├── check-constraint-builder.ts │ ├── column-definition-builder.ts │ ├── create-index-builder.ts │ ├── create-schema-builder.ts │ ├── create-table-builder.ts │ ├── create-type-builder.ts │ ├── create-view-builder.ts │ ├── drop-index-builder.ts │ ├── drop-schema-builder.ts │ ├── drop-table-builder.ts │ ├── drop-type-builder.ts │ ├── drop-view-builder.ts │ ├── foreign-key-constraint-builder.ts │ ├── primary-key-constraint-builder.ts │ ├── refresh-materialized-view-builder.ts │ ├── schema.ts │ └── unique-constraint-builder.ts └── util │ ├── assert.ts │ ├── column-type.ts │ ├── compilable.ts │ ├── deferred.ts │ ├── explainable.ts │ ├── infer-result.ts │ ├── json-object-args.ts │ ├── log-once.ts │ ├── log.ts │ ├── object-utils.ts │ ├── performance-now.ts │ ├── provide-controlled-connection.ts │ ├── query-id.ts │ ├── random-string.ts │ ├── require-all-props.ts │ ├── stack-trace-utils.ts │ ├── streamable.ts │ ├── type-error.ts │ └── type-utils.ts ├── test ├── browser │ ├── index.html │ ├── main.ts │ └── test.js ├── bun │ ├── bun.lockb │ ├── bun.test.ts │ └── package.json ├── cloudflare-workers │ ├── .dev.vars │ ├── api.ts │ ├── package-lock.json │ ├── package.json │ └── test.ts ├── deno │ ├── cdn.test.ts │ ├── deno.json │ ├── deno.lock │ └── local.test.ts ├── node │ ├── src │ │ ├── aggregate-function.test.ts │ │ ├── array.test.ts │ │ ├── async-dispose.test.ts │ │ ├── camel-case.test.ts │ │ ├── case.test.ts │ │ ├── clear.test.ts │ │ ├── coalesce.test.ts │ │ ├── controlled-transaction.test.ts │ │ ├── deduplicate-joins.test.ts │ │ ├── delete.test.ts │ │ ├── disconnects.test.ts │ │ ├── error-stack.test.ts │ │ ├── execute.test.ts │ │ ├── explain.test.ts │ │ ├── expression.test.ts │ │ ├── group-by.test.ts │ │ ├── handle-empty-in-lists-plugin.test.ts │ │ ├── having.test.ts │ │ ├── immediate-value-plugin.test.ts │ │ ├── insert.test.ts │ │ ├── introspect.test.ts │ │ ├── join.test.ts │ │ ├── json-traversal.test.ts │ │ ├── json.test.ts │ │ ├── log-once.test.ts │ │ ├── logging.test.ts │ │ ├── merge.test.ts │ │ ├── migration.test.ts │ │ ├── object-util.test.ts │ │ ├── order-by.test.ts │ │ ├── parse-json-results-plugin.test.ts │ │ ├── performance.test.ts │ │ ├── query-id.test.ts │ │ ├── raw-query.test.ts │ │ ├── raw-sql.test.ts │ │ ├── replace.test.ts │ │ ├── sanitize-identifiers.test.ts │ │ ├── schema.test.ts │ │ ├── select.test.ts │ │ ├── set-operation.test.ts │ │ ├── sql-injection.test.ts │ │ ├── stream.test.ts │ │ ├── test-migrations │ │ │ ├── migration1.ts │ │ │ └── migration2.ts │ │ ├── test-setup.ts │ │ ├── transaction.test.ts │ │ ├── update.test.ts │ │ ├── where.test.ts │ │ ├── with-schema.test.ts │ │ └── with.test.ts │ └── tsconfig.json ├── outdated-ts │ ├── outdated-ts.test.ts │ ├── package-lock.json │ ├── package.json │ └── tsconfig.json ├── scripts │ └── mysql-init.sql ├── ts-benchmarks │ ├── index.ts │ ├── order-by.bench.ts │ ├── package.json │ ├── select-from.bench.ts │ └── tsconfig.json └── typings │ ├── index.d.ts │ ├── package.json │ ├── shared.d.ts │ ├── test-d │ ├── aggregate-function.test-d.ts │ ├── alter-table.test-d.ts │ ├── assert-type.test-d.ts │ ├── case.test-d.ts │ ├── clear.test-d.ts │ ├── coalesce.test-d.ts │ ├── create-table.test-d.ts │ ├── delete-query-builder.test-d.ts │ ├── expression.test-d.ts │ ├── generic.test-d.ts │ ├── huge-db.test-d.ts │ ├── if.test-d.ts │ ├── index.test-d.ts │ ├── infer-result.test-d.ts │ ├── insert.test-d.ts │ ├── join.test-d.ts │ ├── json-traversal.test-d.ts │ ├── kysely-any.test-d.ts │ ├── merge.test-d.ts │ ├── postgres-json.test-d.ts │ ├── select-from.test-d.ts │ ├── select-no-from.test-d.ts │ ├── select.test-d.ts │ ├── set-operation.test-d.ts │ ├── update.test-d.ts │ ├── where.test-d.ts │ └── with.test-d.ts │ └── tsconfig.json ├── tsconfig-base.json ├── tsconfig-cjs.json └── tsconfig.json /.github/workflows/preview.yml: -------------------------------------------------------------------------------- 1 | name: preview 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | paths-ignore: 9 | - '.github/workflows/test.yml' 10 | - 'assets/**' 11 | - 'docs/**' 12 | - 'example/**' 13 | - 'site/**' 14 | - 'test/**' 15 | - '.npmignore' 16 | - '.prettierignore' 17 | - '.prettierrc' 18 | - '.renovaterc.json' 19 | - '*.md' 20 | - 'LICENSE' 21 | 22 | jobs: 23 | release: 24 | name: Release preview build 25 | runs-on: ubuntu-latest 26 | 27 | steps: 28 | - uses: actions/checkout@v4 29 | 30 | - name: Use Node.js 31 | uses: actions/setup-node@v4 32 | with: 33 | cache: 'npm' 34 | node-version: lts/* 35 | 36 | - name: Install dependencies 37 | run: npm ci 38 | 39 | - name: Build 40 | run: npm run build 41 | 42 | - name: Release preview version 43 | run: npx pkg-pr-new@0.0.50 publish --template './example' 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | /helpers 3 | /test/browser/bundle.js 4 | node_modules 5 | .vscode 6 | .idea 7 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 22 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | lts/* 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | *.md -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "trailingComma": "all" 5 | } 6 | -------------------------------------------------------------------------------- /FUNDING.md: -------------------------------------------------------------------------------- 1 | # Funding 2 | 3 | Kysely is an MIT-licensed open-source project and is completely free to use - and will remain so. 4 | 5 | Kysely is a labor of love. We do this in our free time. 6 | 7 | We do not accept donations. 8 | 9 | - Getting paid for open-source won't make us put more time and effort into open-source. 10 | We have family, friends, and other hobbies and interests. 11 | 12 | - We work in the tech industry, full-time, as software developers. We are comfortable as-is. 13 | 14 | - We don't believe in freelance open-source as a stable source of income for the long term. 15 | We have mouths to feed, and careers to maintain. 16 | 17 | - Sponsored projects tend to be affected by big sponsors. We want to keep Kysely away 18 | from companies' and VCs' opinions and business needs. 19 | 20 | - Kysely is escapism for us. We don't want it to feel like another job. 21 | 22 | 23 | Instead of donating to us, we encourage you to support meaningful causes or other open-source projects in need of funding. 24 | 25 | Thank you for supporting Kysely through your usage, contributions, and feedback. 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2022 Sami Koskimäki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /assets/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/assets/demo.gif -------------------------------------------------------------------------------- /deno.check.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://deno.land/x/deno/cli/schemas/config-file.v1.json", 3 | "compilerOptions": { 4 | "types": ["./deno.check.d.ts"] 5 | }, 6 | "imports": { 7 | "better-sqlite3": "npm:better-sqlite3", 8 | "kysely": "./dist/esm", 9 | "kysely/helpers/mssql": "./dist/esm/helpers/mssql.js", 10 | "kysely/helpers/mysql": "./dist/esm/helpers/mysql.js", 11 | "kysely/helpers/postgres": "./dist/esm/helpers/postgres.js", 12 | "kysely/helpers/sqlite": "./dist/esm/helpers/sqlite.js", 13 | "lodash/snakeCase": "npm:lodash/snakeCase", 14 | "mysql2": "npm:mysql2", 15 | "pg": "npm:pg", 16 | "pg-cursor": "npm:pg-cursor", 17 | "tarn": "npm:tarn", 18 | "tedious": "npm:tedious", 19 | "type-editor": "./deno.check.d.ts" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/.env: -------------------------------------------------------------------------------- 1 | # IMPORTANT! 2 | # 3 | # Normally you'd never ever include the .env file in the repo, but for simplicity 4 | # of this example project we do. 5 | # 6 | # Let me say this again: DO NOT INCLUDE THIS FILE IN THE REPO OF ANY REAL PROJECT. 7 | 8 | PORT=3000 9 | AUTH_TOKEN_SECRET=50a7d98cb1f35f2cf746b7be83b36395463b76647c7fca8c86 10 | AUTH_TOKEN_EXIRY_DURATION=2h 11 | DATABASE_HOST=localhost 12 | DATABASE_USER=postgres 13 | DATABASE=kysely_koa_example -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | lib 2 | node_modules 3 | .vscode 4 | -------------------------------------------------------------------------------- /example/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true 4 | } -------------------------------------------------------------------------------- /example/src/authentication/auth-token.ts: -------------------------------------------------------------------------------- 1 | export interface AuthToken { 2 | authToken: string 3 | } 4 | -------------------------------------------------------------------------------- /example/src/authentication/refresh-token.table.ts: -------------------------------------------------------------------------------- 1 | import { Generated, Insertable, Selectable, Updateable } from 'kysely' 2 | 3 | export interface RefreshTokenTable { 4 | refresh_token_id: Generated 5 | user_id: string 6 | last_refreshed_at: Date 7 | created_at: Generated 8 | } 9 | 10 | export type RefreshTokenRow = Selectable 11 | export type InsertableRefreshTokenRow = Insertable 12 | export type UpdateableRefreshTokenRow = Updateable 13 | -------------------------------------------------------------------------------- /example/src/authentication/refresh-token.ts: -------------------------------------------------------------------------------- 1 | import { ajv } from '../util/ajv' 2 | 3 | export interface RefreshToken { 4 | refreshToken: string 5 | } 6 | 7 | export const validateRefreshToken = ajv.compile({ 8 | type: 'object', 9 | required: ['refreshToken'], 10 | properties: { 11 | refreshToken: { 12 | type: 'string', 13 | }, 14 | }, 15 | }) 16 | -------------------------------------------------------------------------------- /example/src/config.ts: -------------------------------------------------------------------------------- 1 | import * as dotenv from 'dotenv' 2 | import { ConnectionConfig } from 'pg' 3 | 4 | dotenv.config() 5 | 6 | export interface Config { 7 | readonly port: number 8 | readonly authTokenSecret: string 9 | readonly authTokenExpiryDuration: string 10 | readonly database: ConnectionConfig 11 | } 12 | 13 | export const config: Config = Object.freeze({ 14 | port: parseInt(getEnvVariable('PORT'), 10), 15 | authTokenSecret: getEnvVariable('AUTH_TOKEN_SECRET'), 16 | authTokenExpiryDuration: getEnvVariable('AUTH_TOKEN_EXIRY_DURATION'), 17 | database: Object.freeze({ 18 | database: getEnvVariable('DATABASE'), 19 | host: getEnvVariable('DATABASE_HOST'), 20 | user: getEnvVariable('DATABASE_USER'), 21 | }), 22 | }) 23 | 24 | function getEnvVariable(name: string): string { 25 | if (!process.env[name]) { 26 | throw new Error(`environment variable ${name} not found`) 27 | } 28 | 29 | return process.env[name]! 30 | } 31 | -------------------------------------------------------------------------------- /example/src/context.ts: -------------------------------------------------------------------------------- 1 | import * as Koa from 'koa' 2 | import * as KoaRouter from 'koa-router' 3 | 4 | import { Kysely } from 'kysely' 5 | import { Database } from './database' 6 | 7 | export interface ContextExtension { 8 | db: Kysely 9 | } 10 | 11 | export type Context = Koa.ParameterizedContext< 12 | any, 13 | ContextExtension & KoaRouter.IRouterParamContext, 14 | any 15 | > 16 | -------------------------------------------------------------------------------- /example/src/database.ts: -------------------------------------------------------------------------------- 1 | import { RefreshTokenTable } from './authentication/refresh-token.table' 2 | import { PasswordSignInMethodTable } from './user/sign-in-method/password-sign-in-method.table' 3 | import { SignInMethodTable } from './user/sign-in-method/sign-in-method.table' 4 | import { UserTable } from './user/user.table' 5 | 6 | export interface Database { 7 | user: UserTable 8 | refresh_token: RefreshTokenTable 9 | sign_in_method: SignInMethodTable 10 | password_sign_in_method: PasswordSignInMethodTable 11 | } 12 | -------------------------------------------------------------------------------- /example/src/migrations/2021_09_18_06_54_59_create_user.ts: -------------------------------------------------------------------------------- 1 | import { Kysely, sql } from 'kysely' 2 | 3 | export async function up(db: Kysely): Promise { 4 | await db.schema 5 | .createTable('user') 6 | .addColumn('user_id', 'uuid', (col) => 7 | col.primaryKey().defaultTo(sql`gen_random_uuid()`) 8 | ) 9 | .addColumn('first_name', 'text') 10 | .addColumn('last_name', 'text') 11 | .addColumn('email', 'text', (col) => col.unique()) 12 | .addColumn('created_at', 'timestamp', (col) => col.defaultTo(sql`NOW()`)) 13 | .execute() 14 | } 15 | 16 | export async function down(db: Kysely): Promise { 17 | await db.schema.dropTable('user').execute() 18 | } 19 | -------------------------------------------------------------------------------- /example/src/migrations/2021_09_18_14_05_20_create_refresh_token.ts: -------------------------------------------------------------------------------- 1 | import { Kysely, sql } from 'kysely' 2 | 3 | export async function up(db: Kysely): Promise { 4 | await db.schema 5 | .createTable('refresh_token') 6 | .addColumn('refresh_token_id', 'uuid', (col) => 7 | col.primaryKey().defaultTo(sql`gen_random_uuid()`) 8 | ) 9 | .addColumn('user_id', 'uuid', (col) => 10 | col.references('user.user_id').notNull().onDelete('cascade') 11 | ) 12 | .addColumn('last_refreshed_at', 'timestamp', (col) => col.notNull()) 13 | .addColumn('created_at', 'timestamp', (col) => 14 | col.notNull().defaultTo(sql`NOW()`) 15 | ) 16 | .execute() 17 | 18 | await db.schema 19 | .createIndex('refresh_token_user_id_index') 20 | .on('refresh_token') 21 | .column('user_id') 22 | .execute() 23 | } 24 | 25 | export async function down(db: Kysely): Promise { 26 | await db.schema.dropTable('refresh_token').execute() 27 | } 28 | -------------------------------------------------------------------------------- /example/src/router.ts: -------------------------------------------------------------------------------- 1 | import * as KoaRouter from 'koa-router' 2 | 3 | import { ContextExtension } from './context' 4 | 5 | export class Router extends KoaRouter {} 6 | -------------------------------------------------------------------------------- /example/src/user/sign-in-method/password-sign-in-method.table.ts: -------------------------------------------------------------------------------- 1 | import { Insertable, Selectable, Updateable } from 'kysely' 2 | 3 | export interface PasswordSignInMethodTable { 4 | user_id: string 5 | password_hash: string 6 | } 7 | 8 | export type PasswordSignInMethodRow = Selectable 9 | 10 | export type InsertablePasswordSignInMethodRow = 11 | Insertable 12 | 13 | export type UpdateablePasswordSignInMethodRow = 14 | Updateable 15 | -------------------------------------------------------------------------------- /example/src/user/sign-in-method/sign-in-method.repository.ts: -------------------------------------------------------------------------------- 1 | import { Kysely } from 'kysely' 2 | import { Database } from '../../database' 3 | import { 4 | InsertablePasswordSignInMethodRow, 5 | PasswordSignInMethodRow, 6 | } from './password-sign-in-method.table' 7 | 8 | export async function findPasswordSignInMethod( 9 | db: Kysely, 10 | userId: string 11 | ): Promise { 12 | const method = await db 13 | .selectFrom('sign_in_method as sim') 14 | .innerJoin('password_sign_in_method as psim', 'psim.user_id', 'sim.user_id') 15 | .selectAll('psim') 16 | .where('sim.type', '=', 'password') 17 | .where('sim.user_id', '=', userId) 18 | .executeTakeFirst() 19 | 20 | return method 21 | } 22 | 23 | export async function insertPasswordSignInMethod( 24 | db: Kysely, 25 | method: InsertablePasswordSignInMethodRow 26 | ): Promise { 27 | await db 28 | .with('sim', (db) => 29 | db 30 | .insertInto('sign_in_method') 31 | .values({ user_id: method.user_id, type: 'password' }) 32 | ) 33 | .insertInto('password_sign_in_method') 34 | .values(method) 35 | .execute() 36 | 37 | return method 38 | } 39 | -------------------------------------------------------------------------------- /example/src/user/sign-in-method/sign-in-method.table.ts: -------------------------------------------------------------------------------- 1 | import { Insertable, Selectable, Updateable } from 'kysely' 2 | 3 | export interface SignInMethodTable { 4 | user_id: string 5 | type: 'password' 6 | } 7 | 8 | export type SignInMethodRow = Selectable 9 | export type InsertableSignInMethodRow = Insertable 10 | export type UpdateableSignInMethodRow = Updateable 11 | -------------------------------------------------------------------------------- /example/src/user/sign-in-method/sign-in-method.ts: -------------------------------------------------------------------------------- 1 | import { ajv } from '../../util/ajv' 2 | 3 | export type SignInMethod = PasswordSignInMethod 4 | 5 | export interface PasswordSignInMethod { 6 | email: string 7 | password: string 8 | } 9 | 10 | export const validatePasswordSignInMethod = ajv.compile({ 11 | type: 'object', 12 | required: ['email', 'password'], 13 | properties: { 14 | email: { 15 | type: 'string', 16 | }, 17 | password: { 18 | type: 'string', 19 | }, 20 | }, 21 | }) 22 | -------------------------------------------------------------------------------- /example/src/user/signed-in-user.ts: -------------------------------------------------------------------------------- 1 | import { AuthToken } from '../authentication/auth-token' 2 | import { RefreshToken } from '../authentication/refresh-token' 3 | import { User } from './user' 4 | 5 | export interface SignedInUser { 6 | refreshToken: RefreshToken 7 | authToken: AuthToken 8 | user: User 9 | } 10 | -------------------------------------------------------------------------------- /example/src/user/user.table.ts: -------------------------------------------------------------------------------- 1 | import { Generated, Insertable, Selectable, Updateable } from 'kysely' 2 | 3 | export interface UserTable { 4 | user_id: Generated 5 | first_name: string | null 6 | last_name: string | null 7 | email: string | null 8 | created_at: Generated 9 | } 10 | 11 | export type UserRow = Selectable 12 | export type InsertableUserRow = Insertable 13 | export type UpdateableUserRow = Updateable 14 | -------------------------------------------------------------------------------- /example/src/user/user.ts: -------------------------------------------------------------------------------- 1 | import { ajv } from '../util/ajv' 2 | 3 | export interface User { 4 | id: string 5 | firstName: string | null 6 | lastName: string | null 7 | email: string | null 8 | } 9 | 10 | export interface CreateAnonymousUserRequest { 11 | firstName?: string 12 | lastName?: string 13 | } 14 | 15 | export const validateCreateAnonymousUserRequest = 16 | ajv.compile({ 17 | type: 'object', 18 | properties: { 19 | firstName: { 20 | type: 'string', 21 | }, 22 | lastName: { 23 | type: 'string', 24 | }, 25 | }, 26 | }) 27 | -------------------------------------------------------------------------------- /example/src/util/ajv.ts: -------------------------------------------------------------------------------- 1 | import Ajv from 'ajv' 2 | 3 | export const ajv = new Ajv() 4 | -------------------------------------------------------------------------------- /example/src/util/object.ts: -------------------------------------------------------------------------------- 1 | export function isObject(value: unknown): value is Record { 2 | return typeof value === 'object' && value !== null 3 | } 4 | -------------------------------------------------------------------------------- /example/test/test-config.ts: -------------------------------------------------------------------------------- 1 | import { ConnectionConfig } from 'pg' 2 | import { Config } from '../src/config' 3 | 4 | export interface TestConfig extends Config { 5 | readonly adminDatabase: ConnectionConfig 6 | } 7 | 8 | export const testConfig: TestConfig = { 9 | port: 3001, 10 | authTokenSecret: 'a498a5cf13a8194a2477f9284df34af3954fad3dc8459e343a', 11 | authTokenExpiryDuration: '2h', 12 | database: { 13 | host: 'localhost', 14 | database: 'kysely_koa_example_test', 15 | user: 'postgres', 16 | }, 17 | adminDatabase: { 18 | host: 'localhost', 19 | database: 'postgres', 20 | user: 'postgres', 21 | }, 22 | } 23 | -------------------------------------------------------------------------------- /example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ESNext", 5 | "declaration": true, 6 | "outDir": "./dist", 7 | "strict": true, 8 | "noImplicitAny": true, 9 | }, 10 | "include": ["src/**/*"], 11 | } 12 | -------------------------------------------------------------------------------- /outdated-typescript.d.ts: -------------------------------------------------------------------------------- 1 | import type { KyselyTypeError } from './dist/cjs/util/type-error' 2 | 3 | declare const Kysely: KyselyTypeError<'The installed TypeScript version is outdated and cannot guarantee type-safety with Kysely. Please upgrade to version 4.6 or newer.'> 4 | declare const RawBuilder: KyselyTypeError<'The installed TypeScript version is outdated and cannot guarantee type-safety with Kysely. Please upgrade to version 4.6 or newer.'> 5 | declare const sql: KyselyTypeError<'The installed TypeScript version is outdated and cannot guarantee type-safety with Kysely. Please upgrade to version 4.6 or newer.'> 6 | -------------------------------------------------------------------------------- /scripts/add-deno-type-references.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This scripts adds a `/// ` directive 3 | * at the beginning of each ESM JavaScript file so that they work with 4 | * deno. 5 | */ 6 | 7 | const fs = require('fs') 8 | const path = require('path') 9 | const forEachFile = require('./util/for-each-file') 10 | 11 | const ESM_DIST_PATH = path.join(__dirname, '..', 'dist', 'esm') 12 | 13 | forEachFile(ESM_DIST_PATH, (filePath) => { 14 | if (filePath.endsWith('.js')) { 15 | const dTsFile = path.basename(filePath).replace(/\.js$/, '.d.ts') 16 | const content = fs.readFileSync(filePath, { encoding: 'utf-8' }) 17 | 18 | fs.writeFileSync( 19 | filePath, 20 | `/// \n${content}` 21 | ) 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /scripts/align-site-version.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This script aligns docusaurus package.json & package-lock.json versions with 3 | * Kysely's version so we use only the latest published version in the docs. 4 | */ 5 | 6 | const { version } = require('../package.json') 7 | const sitePackageJson = require('../site/package.json') 8 | const sitePackageLockJson = require('../site/package-lock.json') 9 | const { writeFileSync } = require('fs') 10 | const { join } = require('path') 11 | 12 | const sitePath = join(__dirname, '..', 'site') 13 | 14 | writeFileSync( 15 | join(sitePath, 'package.json'), 16 | JSON.stringify({ ...sitePackageJson, version }, null, 2) + '\n' 17 | ) 18 | writeFileSync( 19 | join(sitePath, 'package-lock.json'), 20 | JSON.stringify({ ...sitePackageLockJson, version }, null, 2) + '\n' 21 | ) 22 | -------------------------------------------------------------------------------- /scripts/check-exports.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This script ensures all files in a path are exported in the index.ts file. 3 | * For now it only checks the operation-node folder, as we've had issues with 4 | * missing exports there. 5 | */ 6 | 7 | const fs = require('node:fs') 8 | const path = require('node:path') 9 | const forEachFile = require('./util/for-each-file') 10 | 11 | let errorsFound = false 12 | 13 | function checkExports(dir) { 14 | const indexFileContents = fs.readFileSync( 15 | path.join(__dirname, '..', 'src/index.ts'), 16 | 'utf-8', 17 | ) 18 | 19 | forEachFile(dir, (filePath) => { 20 | if (filePath.endsWith('.ts')) { 21 | const expectedExportPath = filePath.replace( 22 | /^.+\/src\/(.+)\.ts$/, 23 | "'./$1.js'", 24 | ) 25 | 26 | if (!indexFileContents.includes(expectedExportPath)) { 27 | console.log(`Missing export: ${expectedExportPath}`) 28 | errorsFound = true 29 | } 30 | } 31 | }) 32 | } 33 | 34 | checkExports(path.join(__dirname, '..', 'src/operation-node')) 35 | 36 | if (errorsFound) { 37 | console.log(' ') 38 | console.log('check-exports.js failed!') 39 | process.exit(1) 40 | } 41 | -------------------------------------------------------------------------------- /scripts/exclude-test-files-for-backwards-compat.mts: -------------------------------------------------------------------------------- 1 | import { writeFile } from 'node:fs/promises' 2 | import { dirname, resolve } from 'pathe' 3 | import { lt } from 'semver' 4 | import { devDependencies } from '../package.json' 5 | 6 | const typescriptVersion = devDependencies.typescript.replace('^', '') 7 | const testTsConfigRelativePath = '../test/node/tsconfig.json' 8 | 9 | if (lt(typescriptVersion, '5.0.0')) { 10 | const tsconfig = await import('../test/node/tsconfig.json') 11 | 12 | await writeFile( 13 | resolve( 14 | dirname(new URL(import.meta.url).pathname), 15 | testTsConfigRelativePath, 16 | ), 17 | JSON.stringify({ 18 | ...tsconfig, 19 | exclude: [...(tsconfig.exclude || []), 'src/async-dispose.test.ts'], 20 | }), 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /scripts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig-base.json", 3 | "compilerOptions": { 4 | "module": "ESNext", 5 | "resolveJsonModule": true 6 | }, 7 | "include": ["./"] 8 | } 9 | -------------------------------------------------------------------------------- /scripts/util/for-each-file.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | function forEachFile(dir, callback) { 5 | const files = fs.readdirSync(dir).filter((it) => it !== '.' && it !== '..') 6 | 7 | for (const file of files) { 8 | const filePath = path.join(dir, file) 9 | 10 | if (isDir(filePath)) { 11 | forEachFile(filePath, callback) 12 | } else { 13 | callback(filePath) 14 | } 15 | } 16 | } 17 | 18 | function isDir(file) { 19 | return fs.lstatSync(file).isDirectory() 20 | } 21 | 22 | module.exports = forEachFile 23 | -------------------------------------------------------------------------------- /site/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | 22 | .vercel 23 | -------------------------------------------------------------------------------- /site/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /site/docs/examples/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Examples", 3 | "position": 5, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Short and simple examples of how to use Kysely to achieve common tasks." 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /site/docs/examples/cte/0010-simple-selects.js: -------------------------------------------------------------------------------- 1 | export const simpleSelects = `const result = await db 2 | // Create a CTE called \`jennifers\` that selects all 3 | // persons named 'Jennifer'. 4 | .with('jennifers', (db) => db 5 | .selectFrom('person') 6 | .where('first_name', '=', 'Jennifer') 7 | .select(['id', 'age']) 8 | ) 9 | // Select all rows from the \`jennifers\` CTE and 10 | // further filter it. 11 | .with('adult_jennifers', (db) => db 12 | .selectFrom('jennifers') 13 | .where('age', '>', 18) 14 | .select(['id', 'age']) 15 | ) 16 | // Finally select all adult jennifers that are 17 | // also younger than 60. 18 | .selectFrom('adult_jennifers') 19 | .where('age', '<', 60) 20 | .selectAll() 21 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/cte/0010-simple-selects.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Simple selects' 3 | --- 4 | 5 | # Simple selects 6 | 7 | Common table expressions (CTE) are a great way to modularize complex queries. 8 | Essentially they allow you to run multiple separate queries within a 9 | single roundtrip to the DB. 10 | 11 | Since CTEs are a part of the main query, query optimizers inside DB 12 | engines are able to optimize the overall query. For example, postgres 13 | is able to inline the CTEs inside the using queries if it decides it's 14 | faster. 15 | 16 | import { Playground } from '../../../src/components/Playground' 17 | 18 | import { 19 | simpleSelects 20 | } from './0010-simple-selects' 21 | 22 |
23 | 24 |
25 | -------------------------------------------------------------------------------- /site/docs/examples/cte/0020-inserts-updates-and-deletions.js: -------------------------------------------------------------------------------- 1 | export const insertsUpdatesAndDeletions = `const result = await db 2 | .with('new_person', (db) => db 3 | .insertInto('person') 4 | .values({ 5 | first_name: 'Jennifer', 6 | age: 35, 7 | }) 8 | .returning('id') 9 | ) 10 | .with('new_pet', (db) => db 11 | .insertInto('pet') 12 | .values({ 13 | name: 'Doggo', 14 | species: 'dog', 15 | is_favorite: true, 16 | // Use the id of the person we just inserted. 17 | owner_id: db 18 | .selectFrom('new_person') 19 | .select('id') 20 | }) 21 | .returning('id') 22 | ) 23 | .selectFrom(['new_person', 'new_pet']) 24 | .select([ 25 | 'new_person.id as person_id', 26 | 'new_pet.id as pet_id' 27 | ]) 28 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/cte/0020-inserts-updates-and-deletions.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Inserts, updates and deletions' 3 | --- 4 | 5 | # Inserts, updates and deletions 6 | 7 | Some databases like postgres also allow you to run other queries than selects 8 | in CTEs. On these databases CTEs are extremely powerful: 9 | 10 | import { Playground } from '../../../src/components/Playground' 11 | 12 | import { 13 | insertsUpdatesAndDeletions 14 | } from './0020-inserts-updates-and-deletions' 15 | 16 |
17 | 18 |
19 | -------------------------------------------------------------------------------- /site/docs/examples/cte/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "CTE", 3 | "position": 9, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Short and simple examples of how to use Common Table Expressions (CTE) in queries." 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /site/docs/examples/delete/0010-single-row.js: -------------------------------------------------------------------------------- 1 | export const singleRow = `const result = await db 2 | .deleteFrom('person') 3 | .where('person.id', '=', 1) 4 | .executeTakeFirst() 5 | 6 | console.log(result.numDeletedRows)` -------------------------------------------------------------------------------- /site/docs/examples/delete/0010-single-row.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Single row' 3 | --- 4 | 5 | # Single row 6 | 7 | Delete a single row: 8 | 9 | import { Playground } from '../../../src/components/Playground' 10 | 11 | import { 12 | singleRow 13 | } from './0010-single-row' 14 | 15 |
16 | 17 |
18 | 19 | :::info[More examples] 20 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 21 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 22 | just one hover away! 23 | 24 | For example, check out these sections: 25 | - [deleteFrom method](https://kysely-org.github.io/kysely-apidoc/classes/Kysely.html#deleteFrom) 26 | - [returning method](https://kysely-org.github.io/kysely-apidoc/classes/DeleteQueryBuilder.html#returning) 27 | ::: 28 | -------------------------------------------------------------------------------- /site/docs/examples/delete/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "DELETE", 3 | "position": 6, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Short and simple examples of how to write DELETE queries." 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /site/docs/examples/insert/0010-single-row.js: -------------------------------------------------------------------------------- 1 | export const singleRow = `const result = await db 2 | .insertInto('person') 3 | .values({ 4 | first_name: 'Jennifer', 5 | last_name: 'Aniston', 6 | age: 40 7 | }) 8 | .executeTakeFirst() 9 | 10 | // \`insertId\` is only available on dialects that 11 | // automatically return the id of the inserted row 12 | // such as MySQL and SQLite. On PostgreSQL, for example, 13 | // you need to add a \`returning\` clause to the query to 14 | // get anything out. See the "returning data" example. 15 | console.log(result.insertId)` -------------------------------------------------------------------------------- /site/docs/examples/insert/0010-single-row.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Single row' 3 | --- 4 | 5 | # Single row 6 | 7 | Insert a single row: 8 | 9 | import { Playground } from '../../../src/components/Playground' 10 | 11 | import { 12 | singleRow 13 | } from './0010-single-row' 14 | 15 |
16 | 17 |
18 | 19 | :::info[More examples] 20 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 21 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 22 | just one hover away! 23 | 24 | For example, check out these sections: 25 | - [values method](https://kysely-org.github.io/kysely-apidoc/classes/InsertQueryBuilder.html#values) 26 | - [onConflict method](https://kysely-org.github.io/kysely-apidoc/classes/InsertQueryBuilder.html#onConflict) 27 | - [returning method](https://kysely-org.github.io/kysely-apidoc/classes/InsertQueryBuilder.html#returning) 28 | - [insertInto method](https://kysely-org.github.io/kysely-apidoc/classes/Kysely.html#insertInto) 29 | ::: 30 | -------------------------------------------------------------------------------- /site/docs/examples/insert/0020-multiple-rows.js: -------------------------------------------------------------------------------- 1 | export const multipleRows = `await db 2 | .insertInto('person') 3 | .values([{ 4 | first_name: 'Jennifer', 5 | last_name: 'Aniston', 6 | age: 40, 7 | }, { 8 | first_name: 'Arnold', 9 | last_name: 'Schwarzenegger', 10 | age: 70, 11 | }]) 12 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/insert/0030-returning-data.js: -------------------------------------------------------------------------------- 1 | export const returningData = `const result = await db 2 | .insertInto('person') 3 | .values({ 4 | first_name: 'Jennifer', 5 | last_name: 'Aniston', 6 | age: 40, 7 | }) 8 | .returning(['id', 'first_name as name']) 9 | .executeTakeFirstOrThrow()` -------------------------------------------------------------------------------- /site/docs/examples/insert/0040-complex-values.js: -------------------------------------------------------------------------------- 1 | export const complexValues = `import { sql } from 'kysely' 2 | 3 | const ani = "Ani" 4 | const ston = "ston" 5 | 6 | const result = await db 7 | .insertInto('person') 8 | .values(({ ref, selectFrom, fn }) => ({ 9 | first_name: 'Jennifer', 10 | last_name: sql\`concat(\${ani}, \${ston})\`, 11 | middle_name: ref('first_name'), 12 | age: selectFrom('person') 13 | .select(fn.avg('age').as('avg_age')), 14 | })) 15 | .executeTakeFirst()` -------------------------------------------------------------------------------- /site/docs/examples/insert/0050-insert-subquery.js: -------------------------------------------------------------------------------- 1 | export const insertSubquery = `const result = await db.insertInto('person') 2 | .columns(['first_name', 'last_name', 'age']) 3 | .expression((eb) => eb 4 | .selectFrom('pet') 5 | .select((eb) => [ 6 | 'pet.name', 7 | eb.val('Petson').as('last_name'), 8 | eb.lit(7).as('age'), 9 | ]) 10 | ) 11 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/insert/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "INSERT", 3 | "position": 4, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Short and simple examples of how to write INSERT queries." 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /site/docs/examples/join/0010-simple-inner-join.js: -------------------------------------------------------------------------------- 1 | export const simpleInnerJoin = `const result = await db 2 | .selectFrom('person') 3 | .innerJoin('pet', 'pet.owner_id', 'person.id') 4 | // \`select\` needs to come after the call to \`innerJoin\` so 5 | // that you can select from the joined table. 6 | .select(['person.id', 'pet.name as pet_name']) 7 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/join/0020-aliased-inner-join.js: -------------------------------------------------------------------------------- 1 | export const aliasedInnerJoin = `await db.selectFrom('person') 2 | .innerJoin('pet as p', 'p.owner_id', 'person.id') 3 | .where('p.name', '=', 'Doggo') 4 | .selectAll() 5 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/join/0030-complex-join.js: -------------------------------------------------------------------------------- 1 | export const complexJoin = `await db.selectFrom('person') 2 | .innerJoin( 3 | 'pet', 4 | (join) => join 5 | .onRef('pet.owner_id', '=', 'person.id') 6 | .on('pet.name', '=', 'Doggo') 7 | .on((eb) => eb.or([ 8 | eb('person.age', '>', 18), 9 | eb('person.age', '<', 100) 10 | ])) 11 | ) 12 | .selectAll() 13 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/join/0040-subquery-join.js: -------------------------------------------------------------------------------- 1 | export const subqueryJoin = `const result = await db.selectFrom('person') 2 | .innerJoin( 3 | (eb) => eb 4 | .selectFrom('pet') 5 | .select(['owner_id as owner', 'name']) 6 | .where('name', '=', 'Doggo') 7 | .as('doggos'), 8 | (join) => join 9 | .onRef('doggos.owner', '=', 'person.id'), 10 | ) 11 | .selectAll('doggos') 12 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/join/0040-subquery-join.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Subquery join' 3 | --- 4 | 5 | # Subquery join 6 | 7 | You can join a subquery by providing two callbacks: 8 | 9 | import { Playground } from '../../../src/components/Playground' 10 | 11 | import { 12 | subqueryJoin 13 | } from './0040-subquery-join' 14 | 15 |
16 | 17 |
18 | 19 | :::info[More examples] 20 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 21 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 22 | just one hover away! 23 | 24 | For example, check out these sections: 25 | - [innerJoin method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#innerJoin) 26 | - [leftJoin method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#leftJoin) 27 | - [rightJoin method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#rightJoin) 28 | - [fullJoin method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#fullJoin) 29 | ::: 30 | -------------------------------------------------------------------------------- /site/docs/examples/join/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "JOIN", 3 | "position": 3, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Examples of queries that use JOINs." 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /site/docs/examples/merge/0010-source-row-existence.js: -------------------------------------------------------------------------------- 1 | export const sourceRowExistence = `const result = await db 2 | .mergeInto('person as target') 3 | .using('pet as source', 'source.owner_id', 'target.id') 4 | .whenMatchedAnd('target.has_pets', '!=', 'Y') 5 | .thenUpdateSet({ has_pets: 'Y' }) 6 | .whenNotMatchedBySourceAnd('target.has_pets', '=', 'Y') 7 | .thenUpdateSet({ has_pets: 'N' }) 8 | .executeTakeFirstOrThrow() 9 | 10 | console.log(result.numChangedRows)` -------------------------------------------------------------------------------- /site/docs/examples/merge/0020-temporary-changes-table.js: -------------------------------------------------------------------------------- 1 | export const temporaryChangesTable = `const result = await db 2 | .mergeInto('wine as target') 3 | .using( 4 | 'wine_stock_change as source', 5 | 'source.wine_name', 6 | 'target.name', 7 | ) 8 | .whenNotMatchedAnd('source.stock_delta', '>', 0) 9 | .thenInsertValues(({ ref }) => ({ 10 | name: ref('source.wine_name'), 11 | stock: ref('source.stock_delta'), 12 | })) 13 | .whenMatchedAnd( 14 | (eb) => eb('target.stock', '+', eb.ref('source.stock_delta')), 15 | '>', 16 | 0, 17 | ) 18 | .thenUpdateSet('stock', (eb) => 19 | eb('target.stock', '+', eb.ref('source.stock_delta')), 20 | ) 21 | .whenMatched() 22 | .thenDelete() 23 | .executeTakeFirstOrThrow()` -------------------------------------------------------------------------------- /site/docs/examples/merge/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "MERGE", 3 | "position": 7, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Short and simple examples of how to write MERGE queries." 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /site/docs/examples/select/0010-a-single-column.js: -------------------------------------------------------------------------------- 1 | export const aSingleColumn = `const persons = await db 2 | .selectFrom('person') 3 | .select('id') 4 | .where('first_name', '=', 'Arnold') 5 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/select/0010-a-single-column.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'A single column' 3 | --- 4 | 5 | # A single column 6 | 7 | Select a single column: 8 | 9 | import { Playground } from '../../../src/components/Playground' 10 | 11 | import { 12 | aSingleColumn 13 | } from './0010-a-single-column' 14 | 15 |
16 | 17 |
18 | 19 | :::info[More examples] 20 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 21 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 22 | just one hover away! 23 | 24 | For example, check out these sections: 25 | - [select method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#select) 26 | - [selectAll method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#selectAll) 27 | - [selectFrom method](https://kysely-org.github.io/kysely-apidoc/classes/Kysely.html#selectFrom) 28 | ::: 29 | -------------------------------------------------------------------------------- /site/docs/examples/select/0020-column-with-a-table.js: -------------------------------------------------------------------------------- 1 | export const columnWithATable = `const persons = await db 2 | .selectFrom(['person', 'pet']) 3 | .select('person.id') 4 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/select/0020-column-with-a-table.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Column with a table' 3 | --- 4 | 5 | # Column with a table 6 | 7 | Select a single column and specify a table: 8 | 9 | import { Playground } from '../../../src/components/Playground' 10 | 11 | import { 12 | columnWithATable 13 | } from './0020-column-with-a-table' 14 | 15 |
16 | 17 |
18 | 19 | :::info[More examples] 20 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 21 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 22 | just one hover away! 23 | 24 | For example, check out these sections: 25 | - [select method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#select) 26 | - [selectAll method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#selectAll) 27 | - [selectFrom method](https://kysely-org.github.io/kysely-apidoc/classes/Kysely.html#selectFrom) 28 | ::: 29 | -------------------------------------------------------------------------------- /site/docs/examples/select/0030-multiple-columns.js: -------------------------------------------------------------------------------- 1 | export const multipleColumns = `const persons = await db 2 | .selectFrom('person') 3 | .select(['person.id', 'first_name']) 4 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/select/0030-multiple-columns.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Multiple columns' 3 | --- 4 | 5 | # Multiple columns 6 | 7 | Select multiple columns: 8 | 9 | import { Playground } from '../../../src/components/Playground' 10 | 11 | import { 12 | multipleColumns 13 | } from './0030-multiple-columns' 14 | 15 |
16 | 17 |
18 | 19 | :::info[More examples] 20 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 21 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 22 | just one hover away! 23 | 24 | For example, check out these sections: 25 | - [select method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#select) 26 | - [selectAll method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#selectAll) 27 | - [selectFrom method](https://kysely-org.github.io/kysely-apidoc/classes/Kysely.html#selectFrom) 28 | ::: 29 | -------------------------------------------------------------------------------- /site/docs/examples/select/0040-aliases.js: -------------------------------------------------------------------------------- 1 | export const aliases = `const persons = await db 2 | .selectFrom('person as p') 3 | .select([ 4 | 'first_name as fn', 5 | 'p.last_name as ln' 6 | ]) 7 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/select/0040-aliases.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Aliases' 3 | --- 4 | 5 | # Aliases 6 | 7 | You can give an alias for selections and tables by appending `as the_alias` to the name: 8 | 9 | import { Playground } from '../../../src/components/Playground' 10 | 11 | import { 12 | aliases 13 | } from './0040-aliases' 14 | 15 |
16 | 17 |
18 | 19 | :::info[More examples] 20 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 21 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 22 | just one hover away! 23 | 24 | For example, check out these sections: 25 | - [select method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#select) 26 | - [selectAll method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#selectAll) 27 | - [selectFrom method](https://kysely-org.github.io/kysely-apidoc/classes/Kysely.html#selectFrom) 28 | ::: 29 | -------------------------------------------------------------------------------- /site/docs/examples/select/0050-complex-selections.js: -------------------------------------------------------------------------------- 1 | export const complexSelections = `import { sql } from 'kysely' 2 | 3 | const persons = await db.selectFrom('person') 4 | .select(({ eb, selectFrom, or, val, lit }) => [ 5 | // Select a correlated subquery 6 | selectFrom('pet') 7 | .whereRef('person.id', '=', 'pet.owner_id') 8 | .select('pet.name') 9 | .orderBy('pet.name') 10 | .limit(1) 11 | .as('first_pet_name'), 12 | 13 | // Build and select an expression using 14 | // the expression builder 15 | or([ 16 | eb('first_name', '=', 'Jennifer'), 17 | eb('first_name', '=', 'Arnold') 18 | ]).as('is_jennifer_or_arnold'), 19 | 20 | // Select a raw sql expression 21 | sql\`concat(first_name, ' ', last_name)\`.as('full_name'), 22 | 23 | // Select a static string value 24 | val('Some value').as('string_value'), 25 | 26 | // Select a literal value 27 | lit(42).as('literal_value'), 28 | ]) 29 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/select/0051-not-null.js: -------------------------------------------------------------------------------- 1 | export const notNull = `import { NotNull } from 'kysely' 2 | import { jsonObjectFrom } from 'kysely/helpers/postgres' 3 | 4 | const persons = db 5 | .selectFrom('person') 6 | .select((eb) => [ 7 | 'last_name', 8 | // Let's assume we know the person has at least one 9 | // pet. We can use the \`.$notNull()\` method to make 10 | // the expression not null. You could just as well 11 | // add \`pet\` to the \`$narrowType\` call below. 12 | jsonObjectFrom( 13 | eb.selectFrom('pet') 14 | .selectAll() 15 | .limit(1) 16 | .whereRef('person.id', '=', 'pet.owner_id') 17 | ).$notNull().as('pet') 18 | ]) 19 | .where('last_name', 'is not', null) 20 | // $narrowType can be used to narrow the output type. 21 | // The special \`NotNull\` type can be used to make a 22 | // selection not null. You could add \`pet: NotNull\` 23 | // here and omit the \`$notNull()\` call on it. 24 | // Use whichever way you prefer. 25 | .$narrowType<{ last_name: NotNull }>() 26 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/select/0070-distinct.js: -------------------------------------------------------------------------------- 1 | export const distinct = `const persons = await db.selectFrom('person') 2 | .select('first_name') 3 | .distinct() 4 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/select/0070-distinct.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Distinct' 3 | --- 4 | 5 | # Distinct 6 | 7 | import { Playground } from '../../../src/components/Playground' 8 | 9 | import { 10 | distinct 11 | } from './0070-distinct' 12 | 13 |
14 | 15 |
16 | 17 | :::info[More examples] 18 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 19 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 20 | just one hover away! 21 | 22 | For example, check out these sections: 23 | - [select method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#select) 24 | - [selectAll method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#selectAll) 25 | - [selectFrom method](https://kysely-org.github.io/kysely-apidoc/classes/Kysely.html#selectFrom) 26 | ::: 27 | -------------------------------------------------------------------------------- /site/docs/examples/select/0080-distinct-on.js: -------------------------------------------------------------------------------- 1 | export const distinctOn = `const persons = await db.selectFrom('person') 2 | .innerJoin('pet', 'pet.owner_id', 'person.id') 3 | .where('pet.name', '=', 'Doggo') 4 | .distinctOn('person.id') 5 | .selectAll('person') 6 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/select/0080-distinct-on.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Distinct on' 3 | --- 4 | 5 | # Distinct on 6 | 7 | import { Playground } from '../../../src/components/Playground' 8 | 9 | import { 10 | distinctOn 11 | } from './0080-distinct-on' 12 | 13 |
14 | 15 |
16 | 17 | :::info[More examples] 18 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 19 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 20 | just one hover away! 21 | 22 | For example, check out these sections: 23 | - [select method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#select) 24 | - [selectAll method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#selectAll) 25 | - [selectFrom method](https://kysely-org.github.io/kysely-apidoc/classes/Kysely.html#selectFrom) 26 | ::: 27 | -------------------------------------------------------------------------------- /site/docs/examples/select/0090-all-columns.js: -------------------------------------------------------------------------------- 1 | export const allColumns = `const persons = await db 2 | .selectFrom('person') 3 | .selectAll() 4 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/select/0090-all-columns.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'All columns' 3 | --- 4 | 5 | # All columns 6 | 7 | The `selectAll` method generates `SELECT *`: 8 | 9 | import { Playground } from '../../../src/components/Playground' 10 | 11 | import { 12 | allColumns 13 | } from './0090-all-columns' 14 | 15 |
16 | 17 |
18 | 19 | :::info[More examples] 20 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 21 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 22 | just one hover away! 23 | 24 | For example, check out these sections: 25 | - [select method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#select) 26 | - [selectAll method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#selectAll) 27 | - [selectFrom method](https://kysely-org.github.io/kysely-apidoc/classes/Kysely.html#selectFrom) 28 | ::: 29 | -------------------------------------------------------------------------------- /site/docs/examples/select/0100-all-columns-of-a-table.js: -------------------------------------------------------------------------------- 1 | export const allColumnsOfATable = `const persons = await db 2 | .selectFrom('person') 3 | .selectAll('person') 4 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/select/0100-all-columns-of-a-table.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'All columns of a table' 3 | --- 4 | 5 | # All columns of a table 6 | 7 | Select all columns of a table: 8 | 9 | import { Playground } from '../../../src/components/Playground' 10 | 11 | import { 12 | allColumnsOfATable 13 | } from './0100-all-columns-of-a-table' 14 | 15 |
16 | 17 |
18 | 19 | :::info[More examples] 20 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 21 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 22 | just one hover away! 23 | 24 | For example, check out these sections: 25 | - [select method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#select) 26 | - [selectAll method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#selectAll) 27 | - [selectFrom method](https://kysely-org.github.io/kysely-apidoc/classes/Kysely.html#selectFrom) 28 | ::: 29 | -------------------------------------------------------------------------------- /site/docs/examples/select/0110-nested-array.js: -------------------------------------------------------------------------------- 1 | export const nestedArray = `import { jsonArrayFrom } from 'kysely/helpers/postgres' 2 | 3 | const result = await db 4 | .selectFrom('person') 5 | .select((eb) => [ 6 | 'id', 7 | jsonArrayFrom( 8 | eb.selectFrom('pet') 9 | .select(['pet.id as pet_id', 'pet.name']) 10 | .whereRef('pet.owner_id', '=', 'person.id') 11 | .orderBy('pet.name') 12 | ).as('pets') 13 | ]) 14 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/select/0120-nested-object.js: -------------------------------------------------------------------------------- 1 | export const nestedObject = `import { jsonObjectFrom } from 'kysely/helpers/postgres' 2 | 3 | const result = await db 4 | .selectFrom('person') 5 | .select((eb) => [ 6 | 'id', 7 | jsonObjectFrom( 8 | eb.selectFrom('pet') 9 | .select(['pet.id as pet_id', 'pet.name']) 10 | .whereRef('pet.owner_id', '=', 'person.id') 11 | .where('pet.is_favorite', '=', true) 12 | ).as('favorite_pet') 13 | ]) 14 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/select/0130-generic-find-query.js: -------------------------------------------------------------------------------- 1 | export const genericFindQuery = `import { SelectType } from 'kysely' 2 | import { Database } from 'type-editor' 3 | 4 | async function getRowByColumn< 5 | T extends keyof Database, 6 | C extends keyof Database[T] & string, 7 | V extends SelectType, 8 | >(t: T, c: C, v: V) { 9 | // We need to use the dynamic module since the table name 10 | // is not known at compile time. 11 | const { table, ref } = db.dynamic 12 | 13 | return await db 14 | .selectFrom(table(t).as('t')) 15 | .selectAll() 16 | .where(ref(c), '=', v) 17 | .orderBy('t.id') 18 | .executeTakeFirstOrThrow() 19 | } 20 | 21 | const person = await getRowByColumn('person', 'first_name', 'Arnold')` -------------------------------------------------------------------------------- /site/docs/examples/select/0130-generic-find-query.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Generic find query' 3 | --- 4 | 5 | # Generic find query 6 | 7 | A generic type-safe helper function for finding a row by a column value: 8 | 9 | import { 10 | Playground, 11 | exampleSetup, 12 | } from '../../../src/components/Playground' 13 | 14 | import { 15 | genericFindQuery 16 | } from './0130-generic-find-query' 17 | 18 |
19 | 20 |
21 | 22 | :::info[More examples] 23 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 24 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 25 | just one hover away! 26 | 27 | For example, check out these sections: 28 | - [select method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#select) 29 | - [selectAll method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#selectAll) 30 | - [selectFrom method](https://kysely-org.github.io/kysely-apidoc/classes/Kysely.html#selectFrom) 31 | ::: 32 | -------------------------------------------------------------------------------- /site/docs/examples/select/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "SELECT", 3 | "position": 1, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Short and simple examples of using the SELECT methods." 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /site/docs/examples/transactions/0010-simple-transaction.js: -------------------------------------------------------------------------------- 1 | export const simpleTransaction = `const catto = await db.transaction().execute(async (trx) => { 2 | const jennifer = await trx.insertInto('person') 3 | .values({ 4 | first_name: 'Jennifer', 5 | last_name: 'Aniston', 6 | age: 40, 7 | }) 8 | .returning('id') 9 | .executeTakeFirstOrThrow() 10 | 11 | return await trx.insertInto('pet') 12 | .values({ 13 | owner_id: jennifer.id, 14 | name: 'Catto', 15 | species: 'cat', 16 | is_favorite: false, 17 | }) 18 | .returningAll() 19 | .executeTakeFirst() 20 | })` -------------------------------------------------------------------------------- /site/docs/examples/transactions/0010-simple-transaction.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Simple transaction' 3 | --- 4 | 5 | # Simple transaction 6 | 7 | This example inserts two rows in a transaction. If an exception is thrown inside 8 | the callback passed to the `execute` method, 9 | 1. the exception is caught, 10 | 2. the transaction is rolled back, and 11 | 3. the exception is thrown again. 12 | Otherwise the transaction is committed. 13 | 14 | import { Playground } from '../../../src/components/Playground' 15 | 16 | import { 17 | simpleTransaction 18 | } from './0010-simple-transaction' 19 | 20 |
21 | 22 |
23 | 24 | :::info[More examples] 25 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 26 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 27 | just one hover away! 28 | 29 | For example, check out these sections: 30 | - [transaction method](https://kysely-org.github.io/kysely-apidoc/classes/Kysely.html#transaction) 31 | ::: 32 | -------------------------------------------------------------------------------- /site/docs/examples/transactions/0011-controlled-transaction.js: -------------------------------------------------------------------------------- 1 | export const controlledTransaction = `const trx = await db.startTransaction().execute() 2 | 3 | try { 4 | const jennifer = await trx.insertInto('person') 5 | .values({ 6 | first_name: 'Jennifer', 7 | last_name: 'Aniston', 8 | age: 40, 9 | }) 10 | .returning('id') 11 | .executeTakeFirstOrThrow() 12 | 13 | const catto = await trx.insertInto('pet') 14 | .values({ 15 | owner_id: jennifer.id, 16 | name: 'Catto', 17 | species: 'cat', 18 | is_favorite: false, 19 | }) 20 | .returningAll() 21 | .executeTakeFirstOrThrow() 22 | 23 | await trx.commit().execute() 24 | 25 | // ... 26 | } catch (error) { 27 | await trx.rollback().execute() 28 | }` -------------------------------------------------------------------------------- /site/docs/examples/transactions/0011-controlled-transaction.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Controlled transaction' 3 | --- 4 | 5 | # Controlled transaction 6 | 7 | A controlled transaction allows you to commit and rollback manually, execute 8 | savepoint commands, and queries in general. 9 | 10 | In this example we start a transaction, use it to insert two rows and then commit 11 | the transaction. If an error is thrown, we catch it and rollback the transaction. 12 | 13 | import { Playground } from '../../../src/components/Playground' 14 | 15 | import { 16 | controlledTransaction 17 | } from './0011-controlled-transaction' 18 | 19 |
20 | 21 |
22 | 23 | :::info[More examples] 24 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 25 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 26 | just one hover away! 27 | 28 | For example, check out these sections: 29 | - [transaction method](https://kysely-org.github.io/kysely-apidoc/classes/Kysely.html#transaction) 30 | ::: 31 | -------------------------------------------------------------------------------- /site/docs/examples/transactions/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Transactions", 3 | "position": 8, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Short and simple examples of how to use transactions." 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /site/docs/examples/update/0010-single-row.js: -------------------------------------------------------------------------------- 1 | export const singleRow = `const result = await db 2 | .updateTable('person') 3 | .set({ 4 | first_name: 'Jennifer', 5 | last_name: 'Aniston' 6 | }) 7 | .where('id', '=', 1) 8 | .executeTakeFirst()` -------------------------------------------------------------------------------- /site/docs/examples/update/0010-single-row.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Single row' 3 | --- 4 | 5 | # Single row 6 | 7 | Update a row in `person` table: 8 | 9 | import { Playground } from '../../../src/components/Playground' 10 | 11 | import { 12 | singleRow 13 | } from './0010-single-row' 14 | 15 |
16 | 17 |
18 | 19 | :::info[More examples] 20 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 21 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 22 | just one hover away! 23 | 24 | For example, check out these sections: 25 | - [set method](https://kysely-org.github.io/kysely-apidoc/classes/UpdateQueryBuilder.html#set) 26 | - [returning method](https://kysely-org.github.io/kysely-apidoc/classes/UpdateQueryBuilder.html#returning) 27 | - [updateTable method](https://kysely-org.github.io/kysely-apidoc/classes/Kysely.html#updateTable) 28 | ::: 29 | -------------------------------------------------------------------------------- /site/docs/examples/update/0020-complex-values.js: -------------------------------------------------------------------------------- 1 | export const complexValues = `const result = await db 2 | .updateTable('person') 3 | .set((eb) => ({ 4 | age: eb('age', '+', 1), 5 | first_name: eb.selectFrom('pet').select('name').limit(1), 6 | last_name: 'updated', 7 | })) 8 | .where('id', '=', 1) 9 | .executeTakeFirst()` -------------------------------------------------------------------------------- /site/docs/examples/update/0020-complex-values.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Complex values' 3 | --- 4 | 5 | # Complex values 6 | 7 | As always, you can provide a callback to the `set` method to get access 8 | to an expression builder: 9 | 10 | import { Playground } from '../../../src/components/Playground' 11 | 12 | import { 13 | complexValues 14 | } from './0020-complex-values' 15 | 16 |
17 | 18 |
19 | 20 | :::info[More examples] 21 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 22 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 23 | just one hover away! 24 | 25 | For example, check out these sections: 26 | - [set method](https://kysely-org.github.io/kysely-apidoc/classes/UpdateQueryBuilder.html#set) 27 | - [returning method](https://kysely-org.github.io/kysely-apidoc/classes/UpdateQueryBuilder.html#returning) 28 | - [updateTable method](https://kysely-org.github.io/kysely-apidoc/classes/Kysely.html#updateTable) 29 | ::: 30 | -------------------------------------------------------------------------------- /site/docs/examples/update/0030-my-sql-joins.js: -------------------------------------------------------------------------------- 1 | export const mySqlJoins = `const result = await db 2 | .updateTable(['person', 'pet']) 3 | .set('person.first_name', 'Updated person') 4 | .set('pet.name', 'Updated doggo') 5 | .whereRef('person.id', '=', 'pet.owner_id') 6 | .where('person.id', '=', 1) 7 | .executeTakeFirst()` -------------------------------------------------------------------------------- /site/docs/examples/update/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "UPDATE", 3 | "position": 5, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Short and simple examples of how to write UPDATE queries." 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /site/docs/examples/where/0010-simple-where-clause.js: -------------------------------------------------------------------------------- 1 | export const simpleWhereClause = `const person = await db 2 | .selectFrom('person') 3 | .selectAll() 4 | .where('first_name', '=', 'Jennifer') 5 | .where('age', '>', 40) 6 | .executeTakeFirst()` -------------------------------------------------------------------------------- /site/docs/examples/where/0010-simple-where-clause.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Simple where clause' 3 | --- 4 | 5 | # Simple where clause 6 | 7 | `where` method calls are combined with `AND`: 8 | 9 | import { Playground } from '../../../src/components/Playground' 10 | 11 | import { 12 | simpleWhereClause 13 | } from './0010-simple-where-clause' 14 | 15 |
16 | 17 |
18 | 19 | :::info[More examples] 20 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 21 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 22 | just one hover away! 23 | 24 | For example, check out these sections: 25 | - [where method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#where) 26 | - [whereRef method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#whereRef) 27 | ::: 28 | -------------------------------------------------------------------------------- /site/docs/examples/where/0020-where-in.js: -------------------------------------------------------------------------------- 1 | export const whereIn = `const persons = await db 2 | .selectFrom('person') 3 | .selectAll() 4 | .where('id', 'in', [1, 2, 3]) 5 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/where/0020-where-in.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Where in' 3 | --- 4 | 5 | # Where in 6 | 7 | Find multiple items using a list of identifiers: 8 | 9 | import { Playground } from '../../../src/components/Playground' 10 | 11 | import { 12 | whereIn 13 | } from './0020-where-in' 14 | 15 |
16 | 17 |
18 | 19 | :::info[More examples] 20 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 21 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 22 | just one hover away! 23 | 24 | For example, check out these sections: 25 | - [where method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#where) 26 | - [whereRef method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#whereRef) 27 | ::: 28 | -------------------------------------------------------------------------------- /site/docs/examples/where/0030-object-filter.js: -------------------------------------------------------------------------------- 1 | export const objectFilter = `const persons = await db 2 | .selectFrom('person') 3 | .selectAll() 4 | .where((eb) => eb.and({ 5 | first_name: 'Jennifer', 6 | last_name: eb.ref('first_name') 7 | })) 8 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/where/0030-object-filter.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Object filter' 3 | --- 4 | 5 | # Object filter 6 | 7 | You can use the `and` function to create a simple equality 8 | filter using an object 9 | 10 | import { Playground } from '../../../src/components/Playground' 11 | 12 | import { 13 | objectFilter 14 | } from './0030-object-filter' 15 | 16 |
17 | 18 |
19 | 20 | :::info[More examples] 21 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 22 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 23 | just one hover away! 24 | 25 | For example, check out these sections: 26 | - [where method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#where) 27 | - [whereRef method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#whereRef) 28 | ::: 29 | -------------------------------------------------------------------------------- /site/docs/examples/where/0040-or-where.js: -------------------------------------------------------------------------------- 1 | export const orWhere = `const persons = await db 2 | .selectFrom('person') 3 | .selectAll() 4 | // 1. Using the \`or\` method on the expression builder: 5 | .where((eb) => eb.or([ 6 | eb('first_name', '=', 'Jennifer'), 7 | eb('first_name', '=', 'Sylvester') 8 | ])) 9 | // 2. Chaining expressions using the \`or\` method on the 10 | // created expressions: 11 | .where((eb) => 12 | eb('last_name', '=', 'Aniston').or('last_name', '=', 'Stallone') 13 | ) 14 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/where/0040-or-where.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'OR where' 3 | --- 4 | 5 | # OR where 6 | 7 | To combine conditions using `OR`, you can use the expression builder. 8 | There are two ways to create `OR` expressions. Both are shown in this 9 | example: 10 | 11 | import { Playground } from '../../../src/components/Playground' 12 | 13 | import { 14 | orWhere 15 | } from './0040-or-where' 16 | 17 |
18 | 19 |
20 | 21 | :::info[More examples] 22 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 23 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 24 | just one hover away! 25 | 26 | For example, check out these sections: 27 | - [where method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#where) 28 | - [whereRef method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#whereRef) 29 | ::: 30 | -------------------------------------------------------------------------------- /site/docs/examples/where/0050-conditional-where-calls.js: -------------------------------------------------------------------------------- 1 | export const conditionalWhereCalls = `import { Expression, SqlBool } from 'kysely' 2 | 3 | const firstName: string | undefined = 'Jennifer' 4 | const lastName: string | undefined = 'Aniston' 5 | const under18 = true 6 | const over60 = true 7 | 8 | let query = db 9 | .selectFrom('person') 10 | .selectAll() 11 | 12 | if (firstName) { 13 | // The query builder is immutable. Remember to reassign 14 | // the result back to the query variable. 15 | query = query.where('first_name', '=', firstName) 16 | } 17 | 18 | if (lastName) { 19 | query = query.where('last_name', '=', lastName) 20 | } 21 | 22 | if (under18 || over60) { 23 | // Conditional OR expressions can be added like this. 24 | query = query.where((eb) => { 25 | const ors: Expression[] = [] 26 | 27 | if (under18) { 28 | ors.push(eb('age', '<', 18)) 29 | } 30 | 31 | if (over60) { 32 | ors.push(eb('age', '>', 60)) 33 | } 34 | 35 | return eb.or(ors) 36 | }) 37 | } 38 | 39 | const persons = await query.execute()` -------------------------------------------------------------------------------- /site/docs/examples/where/0050-conditional-where-calls.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Conditional where calls' 3 | --- 4 | 5 | # Conditional where calls 6 | 7 | You can add expressions conditionally like this: 8 | 9 | import { Playground } from '../../../src/components/Playground' 10 | 11 | import { 12 | conditionalWhereCalls 13 | } from './0050-conditional-where-calls' 14 | 15 |
16 | 17 |
18 | 19 | :::info[More examples] 20 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 21 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 22 | just one hover away! 23 | 24 | For example, check out these sections: 25 | - [where method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#where) 26 | - [whereRef method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#whereRef) 27 | ::: 28 | -------------------------------------------------------------------------------- /site/docs/examples/where/0060-complex-where-clause.js: -------------------------------------------------------------------------------- 1 | export const complexWhereClause = `const firstName = 'Jennifer' 2 | const maxAge = 60 3 | 4 | const persons = await db 5 | .selectFrom('person') 6 | .selectAll('person') 7 | .where(({ eb, or, and, not, exists, selectFrom }) => and([ 8 | or([ 9 | eb('first_name', '=', firstName), 10 | eb('age', '<', maxAge) 11 | ]), 12 | not(exists( 13 | selectFrom('pet') 14 | .select('pet.id') 15 | .whereRef('pet.owner_id', '=', 'person.id') 16 | )) 17 | ])) 18 | .execute()` -------------------------------------------------------------------------------- /site/docs/examples/where/0060-complex-where-clause.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Complex where clause' 3 | --- 4 | 5 | # Complex where clause 6 | 7 | For complex `where` expressions you can pass in a single callback and 8 | use the `ExpressionBuilder` to build your expression: 9 | 10 | import { Playground } from '../../../src/components/Playground' 11 | 12 | import { 13 | complexWhereClause 14 | } from './0060-complex-where-clause' 15 | 16 |
17 | 18 |
19 | 20 | :::info[More examples] 21 | The API documentation is packed with examples. The API docs are hosted [here](https://kysely-org.github.io/kysely-apidoc/), 22 | but you can access the same documentation by hovering over functions/methods/classes in your IDE. The examples are always 23 | just one hover away! 24 | 25 | For example, check out these sections: 26 | - [where method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#where) 27 | - [whereRef method](https://kysely-org.github.io/kysely-apidoc/interfaces/SelectQueryBuilder.html#whereRef) 28 | ::: 29 | -------------------------------------------------------------------------------- /site/docs/examples/where/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "WHERE", 3 | "position": 2, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Short and simple examples of how to use the where method to add a WHERE statement. While most of the examples show a SELECT query, the where method works exactly the same in UPDATE and DELETE queries too." 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /site/docs/getting-started/IUseADifferentDatabase.tsx: -------------------------------------------------------------------------------- 1 | import Link from '@docusaurus/Link' 2 | import { PRETTY_DIALECT_NAMES, type PropsWithDialect } from './shared' 3 | 4 | export function IUseADifferentDatabase(props: PropsWithDialect) { 5 | const dialectName = PRETTY_DIALECT_NAMES[props.dialect || 'postgresql'] 6 | 7 | return ( 8 |

9 | 10 | I use a different database (not {dialectName}) 11 | 12 |

13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /site/docs/getting-started/IUseADifferentPackageManager.tsx: -------------------------------------------------------------------------------- 1 | import Link from '@docusaurus/Link' 2 | import { PRETTY_PACKAGE_MANAGER_NAMES, type PackageManager } from './shared' 3 | 4 | export interface IUseADifferentPackageManagerProps { 5 | packageManager: PackageManager | undefined 6 | packageManagersURL: string 7 | } 8 | 9 | export function IUseADifferentPackageManager( 10 | props: IUseADifferentPackageManagerProps, 11 | ) { 12 | const packageManagerName = 13 | PRETTY_PACKAGE_MANAGER_NAMES[props.packageManager || 'npm'] 14 | 15 | return ( 16 |

17 | 18 | I use a different package manager (not {packageManagerName}) 19 | 20 |

21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /site/docs/getting-started/_prerequisites.mdx: -------------------------------------------------------------------------------- 1 | - [TypeScript](https://www.typescriptlang.org/) version 4.6 or later is supported for type-safety. For better autocompletion experience and compilation performance use version 5.3 or later. 2 | 3 | - You must enable `strict` mode in your `tsconfig.json` file's `compilerOptions`. 4 | 5 | ```ts title="tsconfig.json" 6 | { 7 | // ... 8 | "compilerOptions": { 9 | // ... 10 | "strict": true 11 | // ... 12 | } 13 | // ... 14 | } 15 | ``` 16 | -------------------------------------------------------------------------------- /site/docs/playground.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | --- 4 | 5 | # Playground 6 | 7 | [@wirekang](https://github.com/wirekang) has created a [playground for Kysely](https://kyse.link). You can use it to quickly test stuff out and for creating code examples for your issues, PRs and Discord messages. 8 | 9 | import { Playground } from '../src/components/Playground' 10 | 11 | 17 | first_name: string 18 | last_name: string | null 19 | } 20 | 21 | interface Database { 22 | person: Person 23 | } 24 | 25 | const db = new Kysely({ 26 | dialect: { 27 | createAdapter() { 28 | return new SqliteAdapter() 29 | }, 30 | createDriver() { 31 | return new DummyDriver() 32 | }, 33 | createIntrospector(db: Kysely) { 34 | return new SqliteIntrospector(db) 35 | }, 36 | createQueryCompiler() { 37 | return new SqliteQueryCompiler() 38 | }, 39 | }, 40 | }) 41 | 42 | window.addEventListener('load', () => { 43 | const sql = db.selectFrom('person').select('id').compile() 44 | 45 | const result = document.createElement('span') 46 | result.id = 'result' 47 | result.innerHTML = sql.sql 48 | 49 | document.body.appendChild(result) 50 | }) 51 | ``` 52 | -------------------------------------------------------------------------------- /site/sidebars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Creating a sidebar enables you to: 3 | - create an ordered group of docs 4 | - render a sidebar for each doc of that group 5 | - provide next/previous navigation 6 | 7 | The sidebars can be generated from the filesystem, or explicitly defined here. 8 | 9 | Create as many sidebars as you want. 10 | */ 11 | 12 | // @ts-check 13 | 14 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ 15 | const sidebars = { 16 | // By default, Docusaurus generates a sidebar from the docs folder structure 17 | tutorialSidebar: [{ type: 'autogenerated', dirName: '.' }], 18 | 19 | // But you can create a sidebar manually 20 | /* 21 | tutorialSidebar: [ 22 | 'intro', 23 | 'hello', 24 | { 25 | type: 'category', 26 | label: 'Tutorial', 27 | items: ['tutorial-basics/create-a-document'], 28 | }, 29 | ], 30 | */ 31 | } 32 | 33 | module.exports = sidebars 34 | -------------------------------------------------------------------------------- /site/src/components/DemoVideo.module.css: -------------------------------------------------------------------------------- 1 | .videoContainer { 2 | width: 100%; 3 | max-width: 832px; 4 | height: 0; 5 | padding-bottom: 55.59%; 6 | position: relative; 7 | overflow: hidden; 8 | } 9 | 10 | .videoContainer video { 11 | position: absolute; 12 | top: 0; 13 | width: fit-content; 14 | height: 100%; 15 | background: #1d1d1d; 16 | left: 50%; 17 | transform: translateX(-50%); 18 | max-height: 610px; 19 | border-radius: 12px; 20 | box-shadow: var(--shadow-elevation-medium); 21 | } 22 | -------------------------------------------------------------------------------- /site/src/components/DemoVideo.tsx: -------------------------------------------------------------------------------- 1 | import styles from './DemoVideo.module.css' 2 | 3 | export function DemoVideo() { 4 | return ( 5 |
6 | 9 |
10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /site/src/components/Playground.module.css: -------------------------------------------------------------------------------- 1 | .playground { 2 | border: 1px solid var(--gray3); 3 | border-radius: 7px; 4 | min-height: 600px; 5 | width: 100%; 6 | } 7 | -------------------------------------------------------------------------------- /site/src/components/SectionFeatures/styles.module.css: -------------------------------------------------------------------------------- 1 | .features { 2 | display: flex; 3 | align-items: center; 4 | width: 100%; 5 | position: relative; 6 | min-height: 80vh; 7 | padding: 64px 0; 8 | } 9 | 10 | [data-theme='dark'] .features { 11 | background-color: var(--gray12); 12 | } 13 | 14 | .featureTitle { 15 | align-items: center; 16 | color: var(--gray12); 17 | display: inline-flex; 18 | gap: 8px; 19 | } 20 | 21 | [data-theme='dark'] .featureTitle { 22 | color: var(--gray4); 23 | } 24 | 25 | .tickContainer { 26 | background-color: var(--sky7); 27 | border: 1px solid var(--sky10); 28 | border-radius: 100%; 29 | display: grid; 30 | font-size: 12px; 31 | height: 20px; 32 | place-items: center; 33 | width: 20px; 34 | } 35 | 36 | .tickIcon { 37 | height: 12px; 38 | fill: var(--sky12); 39 | width: 12px; 40 | } 41 | 42 | .featureDescription { 43 | color: var(--gray11); 44 | } 45 | 46 | [data-theme='dark'] .featureDescription { 47 | color: var(--gray8); 48 | } 49 | -------------------------------------------------------------------------------- /site/src/components/SectionQuotes/index.tsx: -------------------------------------------------------------------------------- 1 | import clsx from 'clsx' 2 | 3 | import { Quote } from './Quote' 4 | import { quotes } from './quotes' 5 | import styles from './styles.module.css' 6 | 7 | export function SectionQuotes() { 8 | return ( 9 |
10 |
11 |

What the internet is saying

12 |

Developers are loving Kysely for its simplicity and power.

13 |
14 | {quotes.map((quote, index) => ( 15 | 16 | ))} 17 |
18 |
19 |
20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /site/src/components/SectionQuotes/reddit.module.css: -------------------------------------------------------------------------------- 1 | .snoo1 { 2 | fill: url(#snoo-radial-gragient) white; 3 | } 4 | 5 | .snoo1, 6 | .snoo2, 7 | .snoo3, 8 | .snoo4, 9 | .snoo5, 10 | .snoo6, 11 | .snoo7, 12 | .snoo8, 13 | .snoo9, 14 | .snoo10, 15 | .snoo11 { 16 | stroke-width: 0px; 17 | } 18 | 19 | .snoo2 { 20 | fill: url(#snoo-radial-gragient-2) white; 21 | } 22 | 23 | .snoo3 { 24 | fill: url(#snoo-radial-gragient-3) white; 25 | } 26 | 27 | .snoo4 { 28 | fill: url(#snoo-radial-gragient-4) #fc4301; 29 | } 30 | 31 | .snoo5 { 32 | fill: url(#snoo-radial-gragient-6) black; 33 | } 34 | 35 | .snoo6 { 36 | fill: url(#snoo-radial-gragient-8) black; 37 | } 38 | 39 | .snoo7 { 40 | fill: url(#snoo-radial-gragient-5) #fc4301; 41 | } 42 | 43 | .snoo8 { 44 | fill: url(#snoo-radial-gragient-7) white; 45 | } 46 | 47 | .snoo9 { 48 | fill: #842123; 49 | } 50 | 51 | .snoo10 { 52 | fill: #ff4500; 53 | } 54 | 55 | .snoo11 { 56 | fill: #ffc49c; 57 | } 58 | -------------------------------------------------------------------------------- /site/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/.nojekyll -------------------------------------------------------------------------------- /site/static/demo.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/demo.mp4 -------------------------------------------------------------------------------- /site/static/img/avatars/alberto.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/alberto.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/alexanderson.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/alexanderson.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/bekacru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/bekacru.png -------------------------------------------------------------------------------- /site/static/img/avatars/benholmes.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/benholmes.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/capaj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/capaj.png -------------------------------------------------------------------------------- /site/static/img/avatars/catalin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/catalin.png -------------------------------------------------------------------------------- /site/static/img/avatars/daxraad.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/daxraad.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/gal.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/gal.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/gannon.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/gannon.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/gudmundur.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/gudmundur.png -------------------------------------------------------------------------------- /site/static/img/avatars/guga.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/guga.png -------------------------------------------------------------------------------- /site/static/img/avatars/harminder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/harminder.png -------------------------------------------------------------------------------- /site/static/img/avatars/johan.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/johan.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/julius.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/julius.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/leerob.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/leerob.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/marvin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/marvin.png -------------------------------------------------------------------------------- /site/static/img/avatars/marvinh.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/marvinh.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/mehul.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/mehul.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/nexxel.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/nexxel.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/nicholas.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/nicholas.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/niels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/niels.png -------------------------------------------------------------------------------- /site/static/img/avatars/orta.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/orta.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/pilcrowonpaper.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/pilcrowonpaper.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/ross.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/ross.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/samcook.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/samcook.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/sommelier.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/sommelier.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/tgriesser.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/tgriesser.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/theo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/theo.jpeg -------------------------------------------------------------------------------- /site/static/img/avatars/yusuke.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/avatars/yusuke.jpeg -------------------------------------------------------------------------------- /site/static/img/docusaurus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/docusaurus.png -------------------------------------------------------------------------------- /site/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/site/static/img/favicon.ico -------------------------------------------------------------------------------- /site/static/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /site/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file is not used in compilation. It is here just for a nice editor experience. 3 | "extends": "@docusaurus/tsconfig", 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "resolveJsonModule": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/dialect/dialect-adapter-base.ts: -------------------------------------------------------------------------------- 1 | import { Kysely } from '../kysely.js' 2 | import { DialectAdapter, MigrationLockOptions } from './dialect-adapter.js' 3 | 4 | /** 5 | * A basic implementation of `DialectAdapter` with sensible default values. 6 | * Third-party dialects can extend this instead of implementing the `DialectAdapter` 7 | * interface from scratch. That way all new settings will get default values when 8 | * they are added and there will be less breaking changes. 9 | */ 10 | export abstract class DialectAdapterBase implements DialectAdapter { 11 | get supportsCreateIfNotExists(): boolean { 12 | return true 13 | } 14 | 15 | get supportsTransactionalDdl(): boolean { 16 | return false 17 | } 18 | 19 | get supportsReturning(): boolean { 20 | return false 21 | } 22 | 23 | get supportsOutput(): boolean { 24 | return false 25 | } 26 | 27 | abstract acquireMigrationLock( 28 | db: Kysely, 29 | options: MigrationLockOptions, 30 | ): Promise 31 | 32 | abstract releaseMigrationLock( 33 | db: Kysely, 34 | options: MigrationLockOptions, 35 | ): Promise 36 | } 37 | -------------------------------------------------------------------------------- /src/dialect/postgres/postgres-query-compiler.ts: -------------------------------------------------------------------------------- 1 | import { DefaultQueryCompiler } from '../../query-compiler/default-query-compiler.js' 2 | 3 | const ID_WRAP_REGEX = /"/g 4 | 5 | export class PostgresQueryCompiler extends DefaultQueryCompiler { 6 | protected override sanitizeIdentifier(identifier: string): string { 7 | return identifier.replace(ID_WRAP_REGEX, '""') 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/dialect/sqlite/sqlite-adapter.ts: -------------------------------------------------------------------------------- 1 | import { Kysely } from '../../kysely.js' 2 | import { DialectAdapterBase } from '../dialect-adapter-base.js' 3 | import { MigrationLockOptions } from '../dialect-adapter.js' 4 | 5 | export class SqliteAdapter extends DialectAdapterBase { 6 | override get supportsTransactionalDdl(): boolean { 7 | return false 8 | } 9 | 10 | override get supportsReturning(): boolean { 11 | return true 12 | } 13 | 14 | override async acquireMigrationLock( 15 | _db: Kysely, 16 | _opt: MigrationLockOptions, 17 | ): Promise { 18 | // SQLite only has one connection that's reserved by the migration system 19 | // for the whole time between acquireMigrationLock and releaseMigrationLock. 20 | // We don't need to do anything here. 21 | } 22 | 23 | override async releaseMigrationLock( 24 | _db: Kysely, 25 | _opt: MigrationLockOptions, 26 | ): Promise { 27 | // SQLite only has one connection that's reserved by the migration system 28 | // for the whole time between acquireMigrationLock and releaseMigrationLock. 29 | // We don't need to do anything here. 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/driver/connection-provider.ts: -------------------------------------------------------------------------------- 1 | import { DatabaseConnection } from './database-connection.js' 2 | 3 | export interface ConnectionProvider { 4 | /** 5 | * Provides a connection for the callback and takes care of disposing 6 | * the connection after the callback has been run. 7 | */ 8 | provideConnection( 9 | consumer: (connection: DatabaseConnection) => Promise, 10 | ): Promise 11 | } 12 | -------------------------------------------------------------------------------- /src/driver/default-connection-provider.ts: -------------------------------------------------------------------------------- 1 | import { DatabaseConnection } from './database-connection.js' 2 | import { ConnectionProvider } from './connection-provider.js' 3 | import { Driver } from './driver.js' 4 | 5 | export class DefaultConnectionProvider implements ConnectionProvider { 6 | readonly #driver: Driver 7 | 8 | constructor(driver: Driver) { 9 | this.#driver = driver 10 | } 11 | 12 | async provideConnection( 13 | consumer: (connection: DatabaseConnection) => Promise, 14 | ): Promise { 15 | const connection = await this.#driver.acquireConnection() 16 | 17 | try { 18 | return await consumer(connection) 19 | } finally { 20 | await this.#driver.releaseConnection(connection) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/operation-node/add-column-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { ColumnDefinitionNode } from './column-definition-node.js' 3 | import { OperationNode } from './operation-node.js' 4 | 5 | export interface AddColumnNode extends OperationNode { 6 | readonly kind: 'AddColumnNode' 7 | readonly column: ColumnDefinitionNode 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const AddColumnNode = freeze({ 14 | is(node: OperationNode): node is AddColumnNode { 15 | return node.kind === 'AddColumnNode' 16 | }, 17 | 18 | create(column: ColumnDefinitionNode): AddColumnNode { 19 | return freeze({ 20 | kind: 'AddColumnNode', 21 | column, 22 | }) 23 | }, 24 | }) 25 | -------------------------------------------------------------------------------- /src/operation-node/add-constraint-node.ts: -------------------------------------------------------------------------------- 1 | import { OperationNode } from './operation-node.js' 2 | import { freeze } from '../util/object-utils.js' 3 | import { ConstraintNode } from './constraint-node.js' 4 | 5 | export interface AddConstraintNode extends OperationNode { 6 | readonly kind: 'AddConstraintNode' 7 | readonly constraint: ConstraintNode 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const AddConstraintNode = freeze({ 14 | is(node: OperationNode): node is AddConstraintNode { 15 | return node.kind === 'AddConstraintNode' 16 | }, 17 | 18 | create(constraint: ConstraintNode): AddConstraintNode { 19 | return freeze({ 20 | kind: 'AddConstraintNode', 21 | constraint, 22 | }) 23 | }, 24 | }) 25 | -------------------------------------------------------------------------------- /src/operation-node/alias-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface AliasNode extends OperationNode { 5 | readonly kind: 'AliasNode' 6 | readonly node: OperationNode 7 | readonly alias: OperationNode 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const AliasNode = freeze({ 14 | is(node: OperationNode): node is AliasNode { 15 | return node.kind === 'AliasNode' 16 | }, 17 | 18 | create(node: OperationNode, alias: OperationNode): AliasNode { 19 | return freeze({ 20 | kind: 'AliasNode', 21 | node, 22 | alias, 23 | }) 24 | }, 25 | }) 26 | -------------------------------------------------------------------------------- /src/operation-node/alter-column-node.ts: -------------------------------------------------------------------------------- 1 | import { OperationNode } from './operation-node.js' 2 | import { freeze } from '../util/object-utils.js' 3 | import { ColumnNode } from './column-node.js' 4 | import { RawNode } from './raw-node.js' 5 | 6 | export type AlterColumnNodeProps = Omit 7 | 8 | export interface AlterColumnNode extends OperationNode { 9 | readonly kind: 'AlterColumnNode' 10 | readonly column: ColumnNode 11 | readonly dataType?: OperationNode 12 | readonly dataTypeExpression?: RawNode 13 | readonly setDefault?: OperationNode 14 | readonly dropDefault?: true 15 | readonly setNotNull?: true 16 | readonly dropNotNull?: true 17 | } 18 | 19 | /** 20 | * @internal 21 | */ 22 | export const AlterColumnNode = freeze({ 23 | is(node: OperationNode): node is AlterColumnNode { 24 | return node.kind === 'AlterColumnNode' 25 | }, 26 | 27 | create( 28 | column: string, 29 | prop: T, 30 | value: Required[T], 31 | ): AlterColumnNode { 32 | return freeze({ 33 | kind: 'AlterColumnNode', 34 | column: ColumnNode.create(column), 35 | [prop]: value, 36 | }) 37 | }, 38 | }) 39 | -------------------------------------------------------------------------------- /src/operation-node/and-node.ts: -------------------------------------------------------------------------------- 1 | import { OperationNode } from './operation-node.js' 2 | import { freeze } from '../util/object-utils.js' 3 | 4 | export interface AndNode extends OperationNode { 5 | readonly kind: 'AndNode' 6 | readonly left: OperationNode 7 | readonly right: OperationNode 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const AndNode = freeze({ 14 | is(node: OperationNode): node is AndNode { 15 | return node.kind === 'AndNode' 16 | }, 17 | 18 | create(left: OperationNode, right: OperationNode): AndNode { 19 | return freeze({ 20 | kind: 'AndNode', 21 | left, 22 | right, 23 | }) 24 | }, 25 | }) 26 | -------------------------------------------------------------------------------- /src/operation-node/binary-operation-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface BinaryOperationNode extends OperationNode { 5 | readonly kind: 'BinaryOperationNode' 6 | readonly leftOperand: OperationNode 7 | readonly operator: OperationNode 8 | readonly rightOperand: OperationNode 9 | } 10 | 11 | /** 12 | * @internal 13 | */ 14 | export const BinaryOperationNode = freeze({ 15 | is(node: OperationNode): node is BinaryOperationNode { 16 | return node.kind === 'BinaryOperationNode' 17 | }, 18 | 19 | create( 20 | leftOperand: OperationNode, 21 | operator: OperationNode, 22 | rightOperand: OperationNode, 23 | ): BinaryOperationNode { 24 | return freeze({ 25 | kind: 'BinaryOperationNode', 26 | leftOperand, 27 | operator, 28 | rightOperand, 29 | }) 30 | }, 31 | }) 32 | -------------------------------------------------------------------------------- /src/operation-node/cast-node.ts: -------------------------------------------------------------------------------- 1 | import { OperationNode } from './operation-node.js' 2 | import { freeze } from '../util/object-utils.js' 3 | 4 | export interface CastNode extends OperationNode { 5 | readonly kind: 'CastNode' 6 | readonly expression: OperationNode 7 | readonly dataType: OperationNode 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const CastNode = freeze({ 14 | is(node: OperationNode): node is CastNode { 15 | return node.kind === 'CastNode' 16 | }, 17 | 18 | create(expression: OperationNode, dataType: OperationNode): CastNode { 19 | return freeze({ 20 | kind: 'CastNode', 21 | expression, 22 | dataType, 23 | }) 24 | }, 25 | }) 26 | -------------------------------------------------------------------------------- /src/operation-node/check-constraint-node.ts: -------------------------------------------------------------------------------- 1 | import { OperationNode } from './operation-node.js' 2 | import { freeze } from '../util/object-utils.js' 3 | import { IdentifierNode } from './identifier-node.js' 4 | 5 | export interface CheckConstraintNode extends OperationNode { 6 | readonly kind: 'CheckConstraintNode' 7 | readonly expression: OperationNode 8 | readonly name?: IdentifierNode 9 | } 10 | 11 | /** 12 | * @internal 13 | */ 14 | export const CheckConstraintNode = freeze({ 15 | is(node: OperationNode): node is CheckConstraintNode { 16 | return node.kind === 'CheckConstraintNode' 17 | }, 18 | 19 | create( 20 | expression: OperationNode, 21 | constraintName?: string, 22 | ): CheckConstraintNode { 23 | return freeze({ 24 | kind: 'CheckConstraintNode', 25 | expression, 26 | name: constraintName ? IdentifierNode.create(constraintName) : undefined, 27 | }) 28 | }, 29 | }) 30 | -------------------------------------------------------------------------------- /src/operation-node/collate-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { IdentifierNode } from './identifier-node.js' 3 | import { OperationNode } from './operation-node.js' 4 | 5 | export interface CollateNode extends OperationNode { 6 | readonly kind: 'CollateNode' 7 | readonly collation: IdentifierNode 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const CollateNode = { 14 | is(node: OperationNode): node is CollateNode { 15 | return node.kind === 'CollateNode' 16 | }, 17 | 18 | create(collation: string): CollateNode { 19 | return freeze({ 20 | kind: 'CollateNode', 21 | collation: IdentifierNode.create(collation), 22 | }) 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /src/operation-node/column-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { IdentifierNode } from './identifier-node.js' 3 | import { OperationNode } from './operation-node.js' 4 | 5 | export interface ColumnNode extends OperationNode { 6 | readonly kind: 'ColumnNode' 7 | readonly column: IdentifierNode 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const ColumnNode = freeze({ 14 | is(node: OperationNode): node is ColumnNode { 15 | return node.kind === 'ColumnNode' 16 | }, 17 | 18 | create(column: string): ColumnNode { 19 | return freeze({ 20 | kind: 'ColumnNode', 21 | column: IdentifierNode.create(column), 22 | }) 23 | }, 24 | }) 25 | -------------------------------------------------------------------------------- /src/operation-node/column-update-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface ColumnUpdateNode extends OperationNode { 5 | readonly kind: 'ColumnUpdateNode' 6 | readonly column: OperationNode 7 | readonly value: OperationNode 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const ColumnUpdateNode = freeze({ 14 | is(node: OperationNode): node is ColumnUpdateNode { 15 | return node.kind === 'ColumnUpdateNode' 16 | }, 17 | 18 | create(column: OperationNode, value: OperationNode): ColumnUpdateNode { 19 | return freeze({ 20 | kind: 'ColumnUpdateNode', 21 | column, 22 | value, 23 | }) 24 | }, 25 | }) 26 | -------------------------------------------------------------------------------- /src/operation-node/common-table-expression-name-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { ColumnNode } from './column-node.js' 3 | import { OperationNode } from './operation-node.js' 4 | import { TableNode } from './table-node.js' 5 | 6 | export interface CommonTableExpressionNameNode extends OperationNode { 7 | readonly kind: 'CommonTableExpressionNameNode' 8 | readonly table: TableNode 9 | readonly columns?: ReadonlyArray 10 | } 11 | 12 | /** 13 | * @internal 14 | */ 15 | export const CommonTableExpressionNameNode = freeze({ 16 | is(node: OperationNode): node is CommonTableExpressionNameNode { 17 | return node.kind === 'CommonTableExpressionNameNode' 18 | }, 19 | 20 | create( 21 | tableName: string, 22 | columnNames?: ReadonlyArray, 23 | ): CommonTableExpressionNameNode { 24 | return freeze({ 25 | kind: 'CommonTableExpressionNameNode', 26 | table: TableNode.create(tableName), 27 | columns: columnNames 28 | ? freeze(columnNames.map(ColumnNode.create)) 29 | : undefined, 30 | }) 31 | }, 32 | }) 33 | -------------------------------------------------------------------------------- /src/operation-node/constraint-node.ts: -------------------------------------------------------------------------------- 1 | import { CheckConstraintNode } from './check-constraint-node.js' 2 | import { ForeignKeyConstraintNode } from './foreign-key-constraint-node.js' 3 | import { PrimaryKeyConstraintNode } from './primary-key-constraint-node.js' 4 | import { UniqueConstraintNode } from './unique-constraint-node.js' 5 | 6 | export type ConstraintNode = 7 | | PrimaryKeyConstraintNode 8 | | UniqueConstraintNode 9 | | CheckConstraintNode 10 | | ForeignKeyConstraintNode 11 | -------------------------------------------------------------------------------- /src/operation-node/create-schema-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { IdentifierNode } from './identifier-node.js' 3 | import { OperationNode } from './operation-node.js' 4 | 5 | export type CreateSchemaNodeParams = Omit< 6 | Partial, 7 | 'kind' | 'schema' 8 | > 9 | 10 | export interface CreateSchemaNode extends OperationNode { 11 | readonly kind: 'CreateSchemaNode' 12 | readonly schema: IdentifierNode 13 | readonly ifNotExists?: boolean 14 | } 15 | 16 | /** 17 | * @internal 18 | */ 19 | export const CreateSchemaNode = freeze({ 20 | is(node: OperationNode): node is CreateSchemaNode { 21 | return node.kind === 'CreateSchemaNode' 22 | }, 23 | 24 | create(schema: string, params?: CreateSchemaNodeParams): CreateSchemaNode { 25 | return freeze({ 26 | kind: 'CreateSchemaNode', 27 | schema: IdentifierNode.create(schema), 28 | ...params, 29 | }) 30 | }, 31 | 32 | cloneWith( 33 | createSchema: CreateSchemaNode, 34 | params: CreateSchemaNodeParams, 35 | ): CreateSchemaNode { 36 | return freeze({ 37 | ...createSchema, 38 | ...params, 39 | }) 40 | }, 41 | }) 42 | -------------------------------------------------------------------------------- /src/operation-node/create-type-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | import { SchemableIdentifierNode } from './schemable-identifier-node.js' 4 | import { ValueListNode } from './value-list-node.js' 5 | import { ValueNode } from './value-node.js' 6 | 7 | export type CreateTypeNodeParams = Omit, 'kind'> 8 | 9 | export interface CreateTypeNode extends OperationNode { 10 | readonly kind: 'CreateTypeNode' 11 | readonly name: SchemableIdentifierNode 12 | readonly enum?: ValueListNode 13 | } 14 | 15 | /** 16 | * @internal 17 | */ 18 | export const CreateTypeNode = freeze({ 19 | is(node: OperationNode): node is CreateTypeNode { 20 | return node.kind === 'CreateTypeNode' 21 | }, 22 | 23 | create(name: SchemableIdentifierNode): CreateTypeNode { 24 | return freeze({ 25 | kind: 'CreateTypeNode', 26 | name, 27 | }) 28 | }, 29 | 30 | cloneWithEnum( 31 | createType: CreateTypeNode, 32 | values: readonly string[], 33 | ): CreateTypeNode { 34 | return freeze({ 35 | ...createType, 36 | enum: ValueListNode.create(values.map(ValueNode.createImmediate)), 37 | }) 38 | }, 39 | }) 40 | -------------------------------------------------------------------------------- /src/operation-node/default-insert-value-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface DefaultInsertValueNode extends OperationNode { 5 | readonly kind: 'DefaultInsertValueNode' 6 | } 7 | 8 | /** 9 | * @internal 10 | */ 11 | export const DefaultInsertValueNode = freeze({ 12 | is(node: OperationNode): node is DefaultInsertValueNode { 13 | return node.kind === 'DefaultInsertValueNode' 14 | }, 15 | 16 | create(): DefaultInsertValueNode { 17 | return freeze({ 18 | kind: 'DefaultInsertValueNode', 19 | }) 20 | }, 21 | }) 22 | -------------------------------------------------------------------------------- /src/operation-node/default-value-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface DefaultValueNode extends OperationNode { 5 | readonly kind: 'DefaultValueNode' 6 | readonly defaultValue: OperationNode 7 | } 8 | 9 | /** 10 | * @internal 11 | */ 12 | export const DefaultValueNode = freeze({ 13 | is(node: OperationNode): node is DefaultValueNode { 14 | return node.kind === 'DefaultValueNode' 15 | }, 16 | 17 | create(defaultValue: OperationNode): DefaultValueNode { 18 | return freeze({ 19 | kind: 'DefaultValueNode', 20 | defaultValue, 21 | }) 22 | }, 23 | }) 24 | -------------------------------------------------------------------------------- /src/operation-node/drop-column-node.ts: -------------------------------------------------------------------------------- 1 | import { OperationNode } from './operation-node.js' 2 | import { freeze } from '../util/object-utils.js' 3 | import { ColumnNode } from './column-node.js' 4 | 5 | export interface DropColumnNode extends OperationNode { 6 | readonly kind: 'DropColumnNode' 7 | readonly column: ColumnNode 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const DropColumnNode = freeze({ 14 | is(node: OperationNode): node is DropColumnNode { 15 | return node.kind === 'DropColumnNode' 16 | }, 17 | 18 | create(column: string): DropColumnNode { 19 | return freeze({ 20 | kind: 'DropColumnNode', 21 | column: ColumnNode.create(column), 22 | }) 23 | }, 24 | }) 25 | -------------------------------------------------------------------------------- /src/operation-node/drop-constraint-node.ts: -------------------------------------------------------------------------------- 1 | import { OperationNode } from './operation-node.js' 2 | import { freeze } from '../util/object-utils.js' 3 | import { IdentifierNode } from './identifier-node.js' 4 | 5 | export type DropConstraintNodeProps = Omit< 6 | DropConstraintNode, 7 | 'kind' | 'constraintName' 8 | > 9 | 10 | export interface DropConstraintNode extends OperationNode { 11 | readonly kind: 'DropConstraintNode' 12 | readonly constraintName: IdentifierNode 13 | readonly ifExists?: boolean 14 | readonly modifier?: 'cascade' | 'restrict' 15 | } 16 | 17 | /** 18 | * @internal 19 | */ 20 | export const DropConstraintNode = freeze({ 21 | is(node: OperationNode): node is DropConstraintNode { 22 | return node.kind === 'DropConstraintNode' 23 | }, 24 | 25 | create(constraintName: string): DropConstraintNode { 26 | return freeze({ 27 | kind: 'DropConstraintNode', 28 | constraintName: IdentifierNode.create(constraintName), 29 | }) 30 | }, 31 | 32 | cloneWith( 33 | dropConstraint: DropConstraintNode, 34 | props: DropConstraintNodeProps, 35 | ): DropConstraintNode { 36 | return freeze({ 37 | ...dropConstraint, 38 | ...props, 39 | }) 40 | }, 41 | }) 42 | -------------------------------------------------------------------------------- /src/operation-node/drop-schema-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { IdentifierNode } from './identifier-node.js' 3 | import { OperationNode } from './operation-node.js' 4 | 5 | export type DropSchemaNodeParams = Omit< 6 | Partial, 7 | 'kind' | 'schema' 8 | > 9 | 10 | export interface DropSchemaNode extends OperationNode { 11 | readonly kind: 'DropSchemaNode' 12 | readonly schema: IdentifierNode 13 | readonly ifExists?: boolean 14 | readonly cascade?: boolean 15 | } 16 | 17 | /** 18 | * @internal 19 | */ 20 | export const DropSchemaNode = freeze({ 21 | is(node: OperationNode): node is DropSchemaNode { 22 | return node.kind === 'DropSchemaNode' 23 | }, 24 | 25 | create(schema: string, params?: DropSchemaNodeParams): DropSchemaNode { 26 | return freeze({ 27 | kind: 'DropSchemaNode', 28 | schema: IdentifierNode.create(schema), 29 | ...params, 30 | }) 31 | }, 32 | 33 | cloneWith( 34 | dropSchema: DropSchemaNode, 35 | params: DropSchemaNodeParams, 36 | ): DropSchemaNode { 37 | return freeze({ 38 | ...dropSchema, 39 | ...params, 40 | }) 41 | }, 42 | }) 43 | -------------------------------------------------------------------------------- /src/operation-node/drop-table-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | import { TableNode } from './table-node.js' 4 | 5 | export type DropTablexNodeParams = Omit< 6 | Partial, 7 | 'kind' | 'table' 8 | > 9 | export interface DropTableNode extends OperationNode { 10 | readonly kind: 'DropTableNode' 11 | readonly table: TableNode 12 | readonly ifExists?: boolean 13 | readonly cascade?: boolean 14 | } 15 | 16 | /** 17 | * @internal 18 | */ 19 | export const DropTableNode = freeze({ 20 | is(node: OperationNode): node is DropTableNode { 21 | return node.kind === 'DropTableNode' 22 | }, 23 | 24 | create(table: TableNode, params?: DropTablexNodeParams): DropTableNode { 25 | return freeze({ 26 | kind: 'DropTableNode', 27 | table, 28 | ...params, 29 | }) 30 | }, 31 | 32 | cloneWith( 33 | dropIndex: DropTableNode, 34 | params: DropTablexNodeParams, 35 | ): DropTableNode { 36 | return freeze({ 37 | ...dropIndex, 38 | ...params, 39 | }) 40 | }, 41 | }) 42 | -------------------------------------------------------------------------------- /src/operation-node/drop-type-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | import { SchemableIdentifierNode } from './schemable-identifier-node.js' 4 | 5 | export type DropTypeNodeParams = Omit, 'kind' | 'name'> 6 | 7 | export interface DropTypeNode extends OperationNode { 8 | readonly kind: 'DropTypeNode' 9 | readonly name: SchemableIdentifierNode 10 | readonly ifExists?: boolean 11 | } 12 | 13 | /** 14 | * @internal 15 | */ 16 | export const DropTypeNode = freeze({ 17 | is(node: OperationNode): node is DropTypeNode { 18 | return node.kind === 'DropTypeNode' 19 | }, 20 | 21 | create(name: SchemableIdentifierNode): DropTypeNode { 22 | return freeze({ 23 | kind: 'DropTypeNode', 24 | name, 25 | }) 26 | }, 27 | 28 | cloneWith(dropType: DropTypeNode, params: DropTypeNodeParams): DropTypeNode { 29 | return freeze({ 30 | ...dropType, 31 | ...params, 32 | }) 33 | }, 34 | }) 35 | -------------------------------------------------------------------------------- /src/operation-node/drop-view-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | import { SchemableIdentifierNode } from './schemable-identifier-node.js' 4 | 5 | export type DropViewNodeParams = Omit, 'kind' | 'name'> 6 | 7 | export interface DropViewNode extends OperationNode { 8 | readonly kind: 'DropViewNode' 9 | readonly name: SchemableIdentifierNode 10 | readonly ifExists?: boolean 11 | readonly materialized?: boolean 12 | readonly cascade?: boolean 13 | } 14 | 15 | /** 16 | * @internal 17 | */ 18 | export const DropViewNode = freeze({ 19 | is(node: OperationNode): node is DropViewNode { 20 | return node.kind === 'DropViewNode' 21 | }, 22 | 23 | create(name: string): DropViewNode { 24 | return freeze({ 25 | kind: 'DropViewNode', 26 | name: SchemableIdentifierNode.create(name), 27 | }) 28 | }, 29 | 30 | cloneWith(dropView: DropViewNode, params: DropViewNodeParams): DropViewNode { 31 | return freeze({ 32 | ...dropView, 33 | ...params, 34 | }) 35 | }, 36 | }) 37 | -------------------------------------------------------------------------------- /src/operation-node/explain-node.ts: -------------------------------------------------------------------------------- 1 | import { ExplainFormat } from '../util/explainable.js' 2 | import { freeze } from '../util/object-utils.js' 3 | import { OperationNode } from './operation-node.js' 4 | 5 | export interface ExplainNode extends OperationNode { 6 | readonly kind: 'ExplainNode' 7 | readonly format?: ExplainFormat 8 | readonly options?: OperationNode 9 | } 10 | 11 | /** 12 | * @internal 13 | */ 14 | export const ExplainNode = freeze({ 15 | is(node: OperationNode): node is ExplainNode { 16 | return node.kind === 'ExplainNode' 17 | }, 18 | 19 | create(format?: ExplainFormat, options?: OperationNode): ExplainNode { 20 | return freeze({ 21 | kind: 'ExplainNode', 22 | format, 23 | options, 24 | }) 25 | }, 26 | }) 27 | -------------------------------------------------------------------------------- /src/operation-node/fetch-node.ts: -------------------------------------------------------------------------------- 1 | import { OperationNode } from './operation-node.js' 2 | import { ValueNode } from './value-node.js' 3 | 4 | export type FetchModifier = 'only' | 'with ties' 5 | 6 | export interface FetchNode extends OperationNode { 7 | readonly kind: 'FetchNode' 8 | readonly rowCount: ValueNode 9 | readonly modifier: FetchModifier 10 | } 11 | 12 | /** 13 | * @internal 14 | */ 15 | export const FetchNode = { 16 | is(node: OperationNode): node is FetchNode { 17 | return node.kind === 'FetchNode' 18 | }, 19 | 20 | create(rowCount: number | bigint, modifier: FetchModifier): FetchNode { 21 | return { 22 | kind: 'FetchNode', 23 | rowCount: ValueNode.create(rowCount), 24 | modifier, 25 | } 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /src/operation-node/from-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface FromNode extends OperationNode { 5 | readonly kind: 'FromNode' 6 | readonly froms: ReadonlyArray 7 | } 8 | 9 | /** 10 | * @internal 11 | */ 12 | export const FromNode = freeze({ 13 | is(node: OperationNode): node is FromNode { 14 | return node.kind === 'FromNode' 15 | }, 16 | 17 | create(froms: ReadonlyArray): FromNode { 18 | return freeze({ 19 | kind: 'FromNode', 20 | froms: freeze(froms), 21 | }) 22 | }, 23 | 24 | cloneWithFroms( 25 | from: FromNode, 26 | froms: ReadonlyArray, 27 | ): FromNode { 28 | return freeze({ 29 | ...from, 30 | froms: freeze([...from.froms, ...froms]), 31 | }) 32 | }, 33 | }) 34 | -------------------------------------------------------------------------------- /src/operation-node/function-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface FunctionNode extends OperationNode { 5 | readonly kind: 'FunctionNode' 6 | readonly func: string 7 | readonly arguments: ReadonlyArray 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const FunctionNode = freeze({ 14 | is(node: OperationNode): node is FunctionNode { 15 | return node.kind === 'FunctionNode' 16 | }, 17 | 18 | create(func: string, args: ReadonlyArray): FunctionNode { 19 | return freeze({ 20 | kind: 'FunctionNode', 21 | func, 22 | arguments: args, 23 | }) 24 | }, 25 | }) 26 | -------------------------------------------------------------------------------- /src/operation-node/group-by-item-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface GroupByItemNode extends OperationNode { 5 | readonly kind: 'GroupByItemNode' 6 | readonly groupBy: OperationNode 7 | } 8 | 9 | /** 10 | * @internal 11 | */ 12 | export const GroupByItemNode = freeze({ 13 | is(node: OperationNode): node is GroupByItemNode { 14 | return node.kind === 'GroupByItemNode' 15 | }, 16 | 17 | create(groupBy: OperationNode): GroupByItemNode { 18 | return freeze({ 19 | kind: 'GroupByItemNode', 20 | groupBy, 21 | }) 22 | }, 23 | }) 24 | -------------------------------------------------------------------------------- /src/operation-node/group-by-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | import { GroupByItemNode } from './group-by-item-node.js' 4 | 5 | export interface GroupByNode extends OperationNode { 6 | readonly kind: 'GroupByNode' 7 | readonly items: ReadonlyArray 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const GroupByNode = freeze({ 14 | is(node: OperationNode): node is GroupByNode { 15 | return node.kind === 'GroupByNode' 16 | }, 17 | 18 | create(items: ReadonlyArray): GroupByNode { 19 | return freeze({ 20 | kind: 'GroupByNode', 21 | items: freeze(items), 22 | }) 23 | }, 24 | 25 | cloneWithItems( 26 | groupBy: GroupByNode, 27 | items: ReadonlyArray, 28 | ): GroupByNode { 29 | return freeze({ 30 | ...groupBy, 31 | items: freeze([...groupBy.items, ...items]), 32 | }) 33 | }, 34 | }) 35 | -------------------------------------------------------------------------------- /src/operation-node/having-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { AndNode } from './and-node.js' 3 | import { OperationNode } from './operation-node.js' 4 | import { OrNode } from './or-node.js' 5 | 6 | export interface HavingNode extends OperationNode { 7 | readonly kind: 'HavingNode' 8 | readonly having: OperationNode 9 | } 10 | 11 | /** 12 | * @internal 13 | */ 14 | export const HavingNode = freeze({ 15 | is(node: OperationNode): node is HavingNode { 16 | return node.kind === 'HavingNode' 17 | }, 18 | 19 | create(filter: OperationNode): HavingNode { 20 | return freeze({ 21 | kind: 'HavingNode', 22 | having: filter, 23 | }) 24 | }, 25 | 26 | cloneWithOperation( 27 | havingNode: HavingNode, 28 | operator: 'And' | 'Or', 29 | operation: OperationNode, 30 | ): HavingNode { 31 | return freeze({ 32 | ...havingNode, 33 | having: 34 | operator === 'And' 35 | ? AndNode.create(havingNode.having, operation) 36 | : OrNode.create(havingNode.having, operation), 37 | }) 38 | }, 39 | }) 40 | -------------------------------------------------------------------------------- /src/operation-node/identifier-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface IdentifierNode extends OperationNode { 5 | readonly kind: 'IdentifierNode' 6 | readonly name: string 7 | } 8 | 9 | /** 10 | * @internal 11 | */ 12 | export const IdentifierNode = freeze({ 13 | is(node: OperationNode): node is IdentifierNode { 14 | return node.kind === 'IdentifierNode' 15 | }, 16 | 17 | create(name: string): IdentifierNode { 18 | return freeze({ 19 | kind: 'IdentifierNode', 20 | name, 21 | }) 22 | }, 23 | }) 24 | -------------------------------------------------------------------------------- /src/operation-node/json-operator-chain-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | import { OperatorNode } from './operator-node.js' 4 | import { ValueNode } from './value-node.js' 5 | 6 | export interface JSONOperatorChainNode extends OperationNode { 7 | readonly kind: 'JSONOperatorChainNode' 8 | readonly operator: OperatorNode 9 | readonly values: readonly ValueNode[] 10 | } 11 | 12 | /** 13 | * @internal 14 | */ 15 | export const JSONOperatorChainNode = freeze({ 16 | is(node: OperationNode): node is JSONOperatorChainNode { 17 | return node.kind === 'JSONOperatorChainNode' 18 | }, 19 | 20 | create(operator: OperatorNode): JSONOperatorChainNode { 21 | return freeze({ 22 | kind: 'JSONOperatorChainNode', 23 | operator, 24 | values: freeze([]), 25 | }) 26 | }, 27 | 28 | cloneWithValue( 29 | node: JSONOperatorChainNode, 30 | value: ValueNode, 31 | ): JSONOperatorChainNode { 32 | return freeze({ 33 | ...node, 34 | values: freeze([...node.values, value]), 35 | }) 36 | }, 37 | }) 38 | -------------------------------------------------------------------------------- /src/operation-node/json-path-leg-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export type JSONPathLegType = 'Member' | 'ArrayLocation' 5 | 6 | export interface JSONPathLegNode extends OperationNode { 7 | readonly kind: 'JSONPathLegNode' 8 | readonly type: JSONPathLegType 9 | readonly value: string | number 10 | } 11 | 12 | /** 13 | * @internal 14 | */ 15 | export const JSONPathLegNode = freeze({ 16 | is(node: OperationNode): node is JSONPathLegNode { 17 | return node.kind === 'JSONPathLegNode' 18 | }, 19 | 20 | create(type: JSONPathLegType, value: string | number): JSONPathLegNode { 21 | return freeze({ 22 | kind: 'JSONPathLegNode', 23 | type, 24 | value, 25 | }) 26 | }, 27 | }) 28 | -------------------------------------------------------------------------------- /src/operation-node/json-path-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { JSONPathLegNode } from './json-path-leg-node.js' 3 | import { OperationNode } from './operation-node.js' 4 | import { OperatorNode } from './operator-node.js' 5 | 6 | export interface JSONPathNode extends OperationNode { 7 | readonly kind: 'JSONPathNode' 8 | readonly inOperator?: OperatorNode 9 | readonly pathLegs: ReadonlyArray 10 | } 11 | 12 | /** 13 | * @internal 14 | */ 15 | export const JSONPathNode = freeze({ 16 | is(node: OperationNode): node is JSONPathNode { 17 | return node.kind === 'JSONPathNode' 18 | }, 19 | 20 | create(inOperator?: OperatorNode): JSONPathNode { 21 | return freeze({ 22 | kind: 'JSONPathNode', 23 | inOperator, 24 | pathLegs: freeze([]), 25 | }) 26 | }, 27 | 28 | cloneWithLeg( 29 | jsonPathNode: JSONPathNode, 30 | pathLeg: JSONPathLegNode, 31 | ): JSONPathNode { 32 | return freeze({ 33 | ...jsonPathNode, 34 | pathLegs: freeze([...jsonPathNode.pathLegs, pathLeg]), 35 | }) 36 | }, 37 | }) 38 | -------------------------------------------------------------------------------- /src/operation-node/limit-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface LimitNode extends OperationNode { 5 | readonly kind: 'LimitNode' 6 | readonly limit: OperationNode 7 | } 8 | 9 | /** 10 | * @internal 11 | */ 12 | export const LimitNode = freeze({ 13 | is(node: OperationNode): node is LimitNode { 14 | return node.kind === 'LimitNode' 15 | }, 16 | 17 | create(limit: OperationNode): LimitNode { 18 | return freeze({ 19 | kind: 'LimitNode', 20 | limit, 21 | }) 22 | }, 23 | }) 24 | -------------------------------------------------------------------------------- /src/operation-node/list-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface ListNode extends OperationNode { 5 | readonly kind: 'ListNode' 6 | readonly items: ReadonlyArray 7 | } 8 | 9 | /** 10 | * @internal 11 | */ 12 | export const ListNode = freeze({ 13 | is(node: OperationNode): node is ListNode { 14 | return node.kind === 'ListNode' 15 | }, 16 | 17 | create(items: ReadonlyArray): ListNode { 18 | return freeze({ 19 | kind: 'ListNode', 20 | items: freeze(items), 21 | }) 22 | }, 23 | }) 24 | -------------------------------------------------------------------------------- /src/operation-node/matched-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface MatchedNode extends OperationNode { 5 | readonly kind: 'MatchedNode' 6 | readonly not: boolean 7 | readonly bySource: boolean 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const MatchedNode = freeze({ 14 | is(node: OperationNode): node is MatchedNode { 15 | return node.kind === 'MatchedNode' 16 | }, 17 | 18 | create(not: boolean, bySource: boolean = false): MatchedNode { 19 | return freeze({ 20 | kind: 'MatchedNode', 21 | not, 22 | bySource, 23 | }) 24 | }, 25 | }) 26 | -------------------------------------------------------------------------------- /src/operation-node/modify-column-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { ColumnDefinitionNode } from './column-definition-node.js' 3 | import { OperationNode } from './operation-node.js' 4 | 5 | export interface ModifyColumnNode extends OperationNode { 6 | readonly kind: 'ModifyColumnNode' 7 | readonly column: ColumnDefinitionNode 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const ModifyColumnNode = freeze({ 14 | is(node: OperationNode): node is ModifyColumnNode { 15 | return node.kind === 'ModifyColumnNode' 16 | }, 17 | 18 | create(column: ColumnDefinitionNode): ModifyColumnNode { 19 | return freeze({ 20 | kind: 'ModifyColumnNode', 21 | column, 22 | }) 23 | }, 24 | }) 25 | -------------------------------------------------------------------------------- /src/operation-node/offset-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface OffsetNode extends OperationNode { 5 | readonly kind: 'OffsetNode' 6 | readonly offset: OperationNode 7 | } 8 | 9 | /** 10 | * @internal 11 | */ 12 | export const OffsetNode = freeze({ 13 | is(node: OperationNode): node is OffsetNode { 14 | return node.kind === 'OffsetNode' 15 | }, 16 | 17 | create(offset: OperationNode): OffsetNode { 18 | return freeze({ 19 | kind: 'OffsetNode', 20 | offset, 21 | }) 22 | }, 23 | }) 24 | -------------------------------------------------------------------------------- /src/operation-node/on-duplicate-key-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { ColumnUpdateNode } from './column-update-node.js' 3 | import { OperationNode } from './operation-node.js' 4 | 5 | export type OnDuplicateKeyNodeProps = Omit 6 | 7 | export interface OnDuplicateKeyNode extends OperationNode { 8 | readonly kind: 'OnDuplicateKeyNode' 9 | readonly updates: ReadonlyArray 10 | } 11 | 12 | /** 13 | * @internal 14 | */ 15 | export const OnDuplicateKeyNode = freeze({ 16 | is(node: OperationNode): node is OnDuplicateKeyNode { 17 | return node.kind === 'OnDuplicateKeyNode' 18 | }, 19 | 20 | create(updates: ReadonlyArray): OnDuplicateKeyNode { 21 | return freeze({ 22 | kind: 'OnDuplicateKeyNode', 23 | updates, 24 | }) 25 | }, 26 | }) 27 | -------------------------------------------------------------------------------- /src/operation-node/on-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { AndNode } from './and-node.js' 3 | import { OperationNode } from './operation-node.js' 4 | import { OrNode } from './or-node.js' 5 | 6 | export interface OnNode extends OperationNode { 7 | readonly kind: 'OnNode' 8 | readonly on: OperationNode 9 | } 10 | 11 | /** 12 | * @internal 13 | */ 14 | export const OnNode = freeze({ 15 | is(node: OperationNode): node is OnNode { 16 | return node.kind === 'OnNode' 17 | }, 18 | 19 | create(filter: OperationNode): OnNode { 20 | return freeze({ 21 | kind: 'OnNode', 22 | on: filter, 23 | }) 24 | }, 25 | 26 | cloneWithOperation( 27 | onNode: OnNode, 28 | operator: 'And' | 'Or', 29 | operation: OperationNode, 30 | ): OnNode { 31 | return freeze({ 32 | ...onNode, 33 | on: 34 | operator === 'And' 35 | ? AndNode.create(onNode.on, operation) 36 | : OrNode.create(onNode.on, operation), 37 | }) 38 | }, 39 | }) 40 | -------------------------------------------------------------------------------- /src/operation-node/operation-node-source.ts: -------------------------------------------------------------------------------- 1 | import { isFunction, isObject } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface OperationNodeSource { 5 | toOperationNode(): OperationNode 6 | } 7 | 8 | export function isOperationNodeSource( 9 | obj: unknown, 10 | ): obj is OperationNodeSource { 11 | return isObject(obj) && isFunction(obj.toOperationNode) 12 | } 13 | -------------------------------------------------------------------------------- /src/operation-node/or-action-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface OrActionNode extends OperationNode { 5 | readonly kind: 'OrActionNode' 6 | readonly action: string 7 | } 8 | 9 | /** 10 | * @internal 11 | */ 12 | export const OrActionNode = freeze({ 13 | is(node: OperationNode): node is OrActionNode { 14 | return node.kind === 'OrActionNode' 15 | }, 16 | 17 | create(action: string): OrActionNode { 18 | return freeze({ 19 | kind: 'OrActionNode', 20 | action, 21 | }) 22 | }, 23 | }) 24 | -------------------------------------------------------------------------------- /src/operation-node/or-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface OrNode extends OperationNode { 5 | readonly kind: 'OrNode' 6 | readonly left: OperationNode 7 | readonly right: OperationNode 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const OrNode = freeze({ 14 | is(node: OperationNode): node is OrNode { 15 | return node.kind === 'OrNode' 16 | }, 17 | 18 | create(left: OperationNode, right: OperationNode): OrNode { 19 | return freeze({ 20 | kind: 'OrNode', 21 | left, 22 | right, 23 | }) 24 | }, 25 | }) 26 | -------------------------------------------------------------------------------- /src/operation-node/order-by-item-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { CollateNode } from './collate-node.js' 3 | import { OperationNode } from './operation-node.js' 4 | 5 | export type OrderByItemNodeProps = Omit 6 | 7 | export interface OrderByItemNode extends OperationNode { 8 | readonly kind: 'OrderByItemNode' 9 | readonly orderBy: OperationNode 10 | readonly direction?: OperationNode 11 | readonly nulls?: 'first' | 'last' 12 | readonly collation?: CollateNode 13 | } 14 | 15 | /** 16 | * @internal 17 | */ 18 | export const OrderByItemNode = freeze({ 19 | is(node: OperationNode): node is OrderByItemNode { 20 | return node.kind === 'OrderByItemNode' 21 | }, 22 | 23 | create(orderBy: OperationNode, direction?: OperationNode): OrderByItemNode { 24 | return freeze({ 25 | kind: 'OrderByItemNode', 26 | orderBy, 27 | direction, 28 | }) 29 | }, 30 | 31 | cloneWith( 32 | node: OrderByItemNode, 33 | props: OrderByItemNodeProps, 34 | ): OrderByItemNode { 35 | return freeze({ 36 | ...node, 37 | ...props, 38 | }) 39 | }, 40 | }) 41 | -------------------------------------------------------------------------------- /src/operation-node/order-by-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | import { OrderByItemNode } from './order-by-item-node.js' 4 | 5 | export interface OrderByNode extends OperationNode { 6 | readonly kind: 'OrderByNode' 7 | readonly items: ReadonlyArray 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const OrderByNode = freeze({ 14 | is(node: OperationNode): node is OrderByNode { 15 | return node.kind === 'OrderByNode' 16 | }, 17 | 18 | create(items: ReadonlyArray): OrderByNode { 19 | return freeze({ 20 | kind: 'OrderByNode', 21 | items: freeze([...items]), 22 | }) 23 | }, 24 | 25 | cloneWithItems( 26 | orderBy: OrderByNode, 27 | items: ReadonlyArray, 28 | ): OrderByNode { 29 | return freeze({ 30 | ...orderBy, 31 | items: freeze([...orderBy.items, ...items]), 32 | }) 33 | }, 34 | }) 35 | -------------------------------------------------------------------------------- /src/operation-node/output-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface OutputNode extends OperationNode { 5 | readonly kind: 'OutputNode' 6 | readonly selections: ReadonlyArray 7 | } 8 | 9 | /** 10 | * @internal 11 | */ 12 | export const OutputNode = freeze({ 13 | is(node: OperationNode): node is OutputNode { 14 | return node.kind === 'OutputNode' 15 | }, 16 | 17 | create(selections: ReadonlyArray): OutputNode { 18 | return freeze({ 19 | kind: 'OutputNode', 20 | selections: freeze(selections), 21 | }) 22 | }, 23 | 24 | cloneWithSelections( 25 | output: OutputNode, 26 | selections: ReadonlyArray, 27 | ): OutputNode { 28 | return freeze({ 29 | ...output, 30 | selections: output.selections 31 | ? freeze([...output.selections, ...selections]) 32 | : freeze(selections), 33 | }) 34 | }, 35 | }) 36 | -------------------------------------------------------------------------------- /src/operation-node/parens-node.ts: -------------------------------------------------------------------------------- 1 | import { OperationNode } from './operation-node.js' 2 | import { freeze } from '../util/object-utils.js' 3 | 4 | export interface ParensNode extends OperationNode { 5 | readonly kind: 'ParensNode' 6 | readonly node: OperationNode 7 | } 8 | 9 | /** 10 | * @internal 11 | */ 12 | export const ParensNode = freeze({ 13 | is(node: OperationNode): node is ParensNode { 14 | return node.kind === 'ParensNode' 15 | }, 16 | 17 | create(node: OperationNode): ParensNode { 18 | return freeze({ 19 | kind: 'ParensNode', 20 | node, 21 | }) 22 | }, 23 | }) 24 | -------------------------------------------------------------------------------- /src/operation-node/partition-by-item-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | import { SimpleReferenceExpressionNode } from './simple-reference-expression-node.js' 4 | 5 | export interface PartitionByItemNode extends OperationNode { 6 | readonly kind: 'PartitionByItemNode' 7 | readonly partitionBy: SimpleReferenceExpressionNode 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const PartitionByItemNode = freeze({ 14 | is(node: OperationNode): node is PartitionByItemNode { 15 | return node.kind === 'PartitionByItemNode' 16 | }, 17 | 18 | create(partitionBy: SimpleReferenceExpressionNode): PartitionByItemNode { 19 | return freeze({ 20 | kind: 'PartitionByItemNode', 21 | partitionBy, 22 | }) 23 | }, 24 | }) 25 | -------------------------------------------------------------------------------- /src/operation-node/partition-by-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { PartitionByItemNode } from './partition-by-item-node.js' 3 | import { OperationNode } from './operation-node.js' 4 | 5 | export interface PartitionByNode extends OperationNode { 6 | readonly kind: 'PartitionByNode' 7 | readonly items: ReadonlyArray 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const PartitionByNode = freeze({ 14 | is(node: OperationNode): node is PartitionByNode { 15 | return node.kind === 'PartitionByNode' 16 | }, 17 | 18 | create(items: ReadonlyArray): PartitionByNode { 19 | return freeze({ 20 | kind: 'PartitionByNode', 21 | items: freeze(items), 22 | }) 23 | }, 24 | 25 | cloneWithItems( 26 | partitionBy: PartitionByNode, 27 | items: ReadonlyArray, 28 | ): PartitionByNode { 29 | return freeze({ 30 | ...partitionBy, 31 | items: freeze([...partitionBy.items, ...items]), 32 | }) 33 | }, 34 | }) 35 | -------------------------------------------------------------------------------- /src/operation-node/primitive-value-list-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | /** 5 | * This node is basically just a performance optimization over the normal ValueListNode. 6 | * The queries often contain large arrays of primitive values (for example in a `where in` list) 7 | * and we don't want to create a ValueNode for each item in those lists. 8 | */ 9 | export interface PrimitiveValueListNode extends OperationNode { 10 | readonly kind: 'PrimitiveValueListNode' 11 | readonly values: ReadonlyArray 12 | } 13 | 14 | /** 15 | * @internal 16 | */ 17 | export const PrimitiveValueListNode = freeze({ 18 | is(node: OperationNode): node is PrimitiveValueListNode { 19 | return node.kind === 'PrimitiveValueListNode' 20 | }, 21 | 22 | create(values: ReadonlyArray): PrimitiveValueListNode { 23 | return freeze({ 24 | kind: 'PrimitiveValueListNode', 25 | values: freeze([...values]), 26 | }) 27 | }, 28 | }) 29 | -------------------------------------------------------------------------------- /src/operation-node/raw-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface RawNode extends OperationNode { 5 | readonly kind: 'RawNode' 6 | readonly sqlFragments: ReadonlyArray 7 | readonly parameters: ReadonlyArray 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const RawNode = freeze({ 14 | is(node: OperationNode): node is RawNode { 15 | return node.kind === 'RawNode' 16 | }, 17 | 18 | create( 19 | sqlFragments: ReadonlyArray, 20 | parameters: ReadonlyArray, 21 | ): RawNode { 22 | return freeze({ 23 | kind: 'RawNode', 24 | sqlFragments: freeze(sqlFragments), 25 | parameters: freeze(parameters), 26 | }) 27 | }, 28 | 29 | createWithSql(sql: string): RawNode { 30 | return RawNode.create([sql], []) 31 | }, 32 | 33 | createWithChild(child: OperationNode): RawNode { 34 | return RawNode.create(['', ''], [child]) 35 | }, 36 | 37 | createWithChildren(children: ReadonlyArray): RawNode { 38 | return RawNode.create(new Array(children.length + 1).fill(''), children) 39 | }, 40 | }) 41 | -------------------------------------------------------------------------------- /src/operation-node/reference-node.ts: -------------------------------------------------------------------------------- 1 | import { OperationNode } from './operation-node.js' 2 | import { ColumnNode } from './column-node.js' 3 | import { TableNode } from './table-node.js' 4 | import { SelectAllNode } from './select-all-node.js' 5 | import { freeze } from '../util/object-utils.js' 6 | 7 | export interface ReferenceNode extends OperationNode { 8 | readonly kind: 'ReferenceNode' 9 | readonly column: ColumnNode | SelectAllNode 10 | readonly table?: TableNode 11 | } 12 | 13 | /** 14 | * @internal 15 | */ 16 | export const ReferenceNode = freeze({ 17 | is(node: OperationNode): node is ReferenceNode { 18 | return node.kind === 'ReferenceNode' 19 | }, 20 | 21 | create(column: ColumnNode, table?: TableNode): ReferenceNode { 22 | return freeze({ 23 | kind: 'ReferenceNode', 24 | table, 25 | column, 26 | }) 27 | }, 28 | 29 | createSelectAll(table: TableNode): ReferenceNode { 30 | return freeze({ 31 | kind: 'ReferenceNode', 32 | table, 33 | column: SelectAllNode.create(), 34 | }) 35 | }, 36 | }) 37 | -------------------------------------------------------------------------------- /src/operation-node/rename-column-node.ts: -------------------------------------------------------------------------------- 1 | import { OperationNode } from './operation-node.js' 2 | import { freeze } from '../util/object-utils.js' 3 | import { ColumnNode } from './column-node.js' 4 | 5 | export interface RenameColumnNode extends OperationNode { 6 | readonly kind: 'RenameColumnNode' 7 | readonly column: ColumnNode 8 | readonly renameTo: ColumnNode 9 | } 10 | 11 | /** 12 | * @internal 13 | */ 14 | export const RenameColumnNode = freeze({ 15 | is(node: OperationNode): node is RenameColumnNode { 16 | return node.kind === 'RenameColumnNode' 17 | }, 18 | 19 | create(column: string, newColumn: string): RenameColumnNode { 20 | return freeze({ 21 | kind: 'RenameColumnNode', 22 | column: ColumnNode.create(column), 23 | renameTo: ColumnNode.create(newColumn), 24 | }) 25 | }, 26 | }) 27 | -------------------------------------------------------------------------------- /src/operation-node/rename-constraint-node.ts: -------------------------------------------------------------------------------- 1 | import { OperationNode } from './operation-node.js' 2 | import { freeze } from '../util/object-utils.js' 3 | import { IdentifierNode } from './identifier-node.js' 4 | 5 | export interface RenameConstraintNode extends OperationNode { 6 | readonly kind: 'RenameConstraintNode' 7 | readonly oldName: IdentifierNode 8 | readonly newName: IdentifierNode 9 | } 10 | 11 | /** 12 | * @internal 13 | */ 14 | export const RenameConstraintNode = freeze({ 15 | is(node: OperationNode): node is RenameConstraintNode { 16 | return node.kind === 'RenameConstraintNode' 17 | }, 18 | 19 | create(oldName: string, newName: string): RenameConstraintNode { 20 | return freeze({ 21 | kind: 'RenameConstraintNode', 22 | oldName: IdentifierNode.create(oldName), 23 | newName: IdentifierNode.create(newName), 24 | }) 25 | }, 26 | }) 27 | -------------------------------------------------------------------------------- /src/operation-node/returning-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | import { SelectionNode } from './selection-node.js' 4 | 5 | export interface ReturningNode extends OperationNode { 6 | readonly kind: 'ReturningNode' 7 | readonly selections: ReadonlyArray 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const ReturningNode = freeze({ 14 | is(node: OperationNode): node is ReturningNode { 15 | return node.kind === 'ReturningNode' 16 | }, 17 | 18 | create(selections: ReadonlyArray): ReturningNode { 19 | return freeze({ 20 | kind: 'ReturningNode', 21 | selections: freeze(selections), 22 | }) 23 | }, 24 | 25 | cloneWithSelections( 26 | returning: ReturningNode, 27 | selections: ReadonlyArray, 28 | ): ReturningNode { 29 | return freeze({ 30 | ...returning, 31 | selections: returning.selections 32 | ? freeze([...returning.selections, ...selections]) 33 | : freeze(selections), 34 | }) 35 | }, 36 | }) 37 | -------------------------------------------------------------------------------- /src/operation-node/schemable-identifier-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { IdentifierNode } from './identifier-node.js' 3 | import { OperationNode } from './operation-node.js' 4 | 5 | export interface SchemableIdentifierNode extends OperationNode { 6 | readonly kind: 'SchemableIdentifierNode' 7 | readonly schema?: IdentifierNode 8 | readonly identifier: IdentifierNode 9 | } 10 | 11 | /** 12 | * @internal 13 | */ 14 | export const SchemableIdentifierNode = freeze({ 15 | is(node: OperationNode): node is SchemableIdentifierNode { 16 | return node.kind === 'SchemableIdentifierNode' 17 | }, 18 | 19 | create(identifier: string): SchemableIdentifierNode { 20 | return freeze({ 21 | kind: 'SchemableIdentifierNode', 22 | identifier: IdentifierNode.create(identifier), 23 | }) 24 | }, 25 | 26 | createWithSchema( 27 | schema: string, 28 | identifier: string, 29 | ): SchemableIdentifierNode { 30 | return freeze({ 31 | kind: 'SchemableIdentifierNode', 32 | schema: IdentifierNode.create(schema), 33 | identifier: IdentifierNode.create(identifier), 34 | }) 35 | }, 36 | }) 37 | -------------------------------------------------------------------------------- /src/operation-node/select-all-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface SelectAllNode extends OperationNode { 5 | readonly kind: 'SelectAllNode' 6 | } 7 | 8 | /** 9 | * @internal 10 | */ 11 | export const SelectAllNode = freeze({ 12 | is(node: OperationNode): node is SelectAllNode { 13 | return node.kind === 'SelectAllNode' 14 | }, 15 | 16 | create(): SelectAllNode { 17 | return freeze({ 18 | kind: 'SelectAllNode', 19 | }) 20 | }, 21 | }) 22 | -------------------------------------------------------------------------------- /src/operation-node/set-operation-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export type SetOperator = 'union' | 'intersect' | 'except' 5 | 6 | export interface SetOperationNode extends OperationNode { 7 | kind: 'SetOperationNode' 8 | operator: SetOperator 9 | expression: OperationNode 10 | all: boolean 11 | } 12 | 13 | /** 14 | * @internal 15 | */ 16 | export const SetOperationNode = freeze({ 17 | is(node: OperationNode): node is SetOperationNode { 18 | return node.kind === 'SetOperationNode' 19 | }, 20 | 21 | create( 22 | operator: SetOperator, 23 | expression: OperationNode, 24 | all: boolean, 25 | ): SetOperationNode { 26 | return freeze({ 27 | kind: 'SetOperationNode', 28 | operator, 29 | expression, 30 | all, 31 | }) 32 | }, 33 | }) 34 | -------------------------------------------------------------------------------- /src/operation-node/simple-reference-expression-node.ts: -------------------------------------------------------------------------------- 1 | import { ColumnNode } from './column-node.js' 2 | import { ReferenceNode } from './reference-node.js' 3 | 4 | export type SimpleReferenceExpressionNode = ColumnNode | ReferenceNode 5 | -------------------------------------------------------------------------------- /src/operation-node/table-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | import { SchemableIdentifierNode } from './schemable-identifier-node.js' 4 | 5 | export interface TableNode extends OperationNode { 6 | readonly kind: 'TableNode' 7 | readonly table: SchemableIdentifierNode 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const TableNode = freeze({ 14 | is(node: OperationNode): node is TableNode { 15 | return node.kind === 'TableNode' 16 | }, 17 | 18 | create(table: string): TableNode { 19 | return freeze({ 20 | kind: 'TableNode', 21 | table: SchemableIdentifierNode.create(table), 22 | }) 23 | }, 24 | 25 | createWithSchema(schema: string, table: string): TableNode { 26 | return freeze({ 27 | kind: 'TableNode', 28 | table: SchemableIdentifierNode.createWithSchema(schema, table), 29 | }) 30 | }, 31 | }) 32 | -------------------------------------------------------------------------------- /src/operation-node/top-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export type TopModifier = 'percent' | 'with ties' | 'percent with ties' 5 | 6 | export interface TopNode extends OperationNode { 7 | readonly kind: 'TopNode' 8 | readonly expression: number | bigint 9 | readonly modifiers?: TopModifier 10 | } 11 | 12 | /** 13 | * @internal 14 | */ 15 | export const TopNode = freeze({ 16 | is(node: OperationNode): node is TopNode { 17 | return node.kind === 'TopNode' 18 | }, 19 | 20 | create(expression: number | bigint, modifiers?: TopModifier): TopNode { 21 | return freeze({ 22 | kind: 'TopNode', 23 | expression, 24 | modifiers, 25 | }) 26 | }, 27 | }) 28 | -------------------------------------------------------------------------------- /src/operation-node/tuple-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface TupleNode extends OperationNode { 5 | readonly kind: 'TupleNode' 6 | readonly values: ReadonlyArray 7 | } 8 | 9 | /** 10 | * @internal 11 | */ 12 | export const TupleNode = freeze({ 13 | is(node: OperationNode): node is TupleNode { 14 | return node.kind === 'TupleNode' 15 | }, 16 | 17 | create(values: ReadonlyArray): TupleNode { 18 | return freeze({ 19 | kind: 'TupleNode', 20 | values: freeze(values), 21 | }) 22 | }, 23 | }) 24 | -------------------------------------------------------------------------------- /src/operation-node/unary-operation-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface UnaryOperationNode extends OperationNode { 5 | readonly kind: 'UnaryOperationNode' 6 | readonly operator: OperationNode 7 | readonly operand: OperationNode 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const UnaryOperationNode = freeze({ 14 | is(node: OperationNode): node is UnaryOperationNode { 15 | return node.kind === 'UnaryOperationNode' 16 | }, 17 | 18 | create(operator: OperationNode, operand: OperationNode): UnaryOperationNode { 19 | return freeze({ 20 | kind: 'UnaryOperationNode', 21 | operator, 22 | operand, 23 | }) 24 | }, 25 | }) 26 | -------------------------------------------------------------------------------- /src/operation-node/using-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface UsingNode extends OperationNode { 5 | readonly kind: 'UsingNode' 6 | readonly tables: ReadonlyArray 7 | } 8 | 9 | /** 10 | * @internal 11 | */ 12 | export const UsingNode = freeze({ 13 | is(node: OperationNode): node is UsingNode { 14 | return node.kind === 'UsingNode' 15 | }, 16 | 17 | create(tables: ReadonlyArray): UsingNode { 18 | return freeze({ 19 | kind: 'UsingNode', 20 | tables: freeze(tables), 21 | }) 22 | }, 23 | 24 | cloneWithTables( 25 | using: UsingNode, 26 | tables: ReadonlyArray, 27 | ): UsingNode { 28 | return freeze({ 29 | ...using, 30 | tables: freeze([...using.tables, ...tables]), 31 | }) 32 | }, 33 | }) 34 | -------------------------------------------------------------------------------- /src/operation-node/value-list-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface ValueListNode extends OperationNode { 5 | readonly kind: 'ValueListNode' 6 | readonly values: ReadonlyArray 7 | } 8 | 9 | /** 10 | * @internal 11 | */ 12 | export const ValueListNode = freeze({ 13 | is(node: OperationNode): node is ValueListNode { 14 | return node.kind === 'ValueListNode' 15 | }, 16 | 17 | create(values: ReadonlyArray): ValueListNode { 18 | return freeze({ 19 | kind: 'ValueListNode', 20 | values: freeze(values), 21 | }) 22 | }, 23 | }) 24 | -------------------------------------------------------------------------------- /src/operation-node/value-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface ValueNode extends OperationNode { 5 | readonly kind: 'ValueNode' 6 | readonly value: unknown 7 | readonly immediate?: boolean 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const ValueNode = freeze({ 14 | is(node: OperationNode): node is ValueNode { 15 | return node.kind === 'ValueNode' 16 | }, 17 | 18 | create(value: unknown): ValueNode { 19 | return freeze({ 20 | kind: 'ValueNode', 21 | value, 22 | }) 23 | }, 24 | 25 | createImmediate(value: unknown): ValueNode { 26 | return freeze({ 27 | kind: 'ValueNode', 28 | value, 29 | immediate: true, 30 | }) 31 | }, 32 | }) 33 | -------------------------------------------------------------------------------- /src/operation-node/values-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | import { PrimitiveValueListNode } from './primitive-value-list-node.js' 4 | import { ValueListNode } from './value-list-node.js' 5 | 6 | export type ValuesItemNode = ValueListNode | PrimitiveValueListNode 7 | 8 | export interface ValuesNode extends OperationNode { 9 | readonly kind: 'ValuesNode' 10 | readonly values: ReadonlyArray 11 | } 12 | 13 | /** 14 | * @internal 15 | */ 16 | export const ValuesNode = freeze({ 17 | is(node: OperationNode): node is ValuesNode { 18 | return node.kind === 'ValuesNode' 19 | }, 20 | 21 | create(values: ReadonlyArray): ValuesNode { 22 | return freeze({ 23 | kind: 'ValuesNode', 24 | values: freeze(values), 25 | }) 26 | }, 27 | }) 28 | -------------------------------------------------------------------------------- /src/operation-node/when-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | 4 | export interface WhenNode extends OperationNode { 5 | readonly kind: 'WhenNode' 6 | readonly condition: OperationNode 7 | readonly result?: OperationNode 8 | } 9 | 10 | /** 11 | * @internal 12 | */ 13 | export const WhenNode = freeze({ 14 | is(node: OperationNode): node is WhenNode { 15 | return node.kind === 'WhenNode' 16 | }, 17 | 18 | create(condition: OperationNode): WhenNode { 19 | return freeze({ 20 | kind: 'WhenNode', 21 | condition, 22 | }) 23 | }, 24 | 25 | cloneWithResult(whenNode: WhenNode, result: OperationNode): WhenNode { 26 | return freeze({ 27 | ...whenNode, 28 | result, 29 | }) 30 | }, 31 | }) 32 | -------------------------------------------------------------------------------- /src/operation-node/where-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { AndNode } from './and-node.js' 3 | import { OperationNode } from './operation-node.js' 4 | import { OrNode } from './or-node.js' 5 | 6 | export interface WhereNode extends OperationNode { 7 | readonly kind: 'WhereNode' 8 | readonly where: OperationNode 9 | } 10 | 11 | /** 12 | * @internal 13 | */ 14 | export const WhereNode = freeze({ 15 | is(node: OperationNode): node is WhereNode { 16 | return node.kind === 'WhereNode' 17 | }, 18 | 19 | create(filter: OperationNode): WhereNode { 20 | return freeze({ 21 | kind: 'WhereNode', 22 | where: filter, 23 | }) 24 | }, 25 | 26 | cloneWithOperation( 27 | whereNode: WhereNode, 28 | operator: 'And' | 'Or', 29 | operation: OperationNode, 30 | ): WhereNode { 31 | return freeze({ 32 | ...whereNode, 33 | where: 34 | operator === 'And' 35 | ? AndNode.create(whereNode.where, operation) 36 | : OrNode.create(whereNode.where, operation), 37 | }) 38 | }, 39 | }) 40 | -------------------------------------------------------------------------------- /src/operation-node/with-node.ts: -------------------------------------------------------------------------------- 1 | import { freeze } from '../util/object-utils.js' 2 | import { OperationNode } from './operation-node.js' 3 | import { CommonTableExpressionNode } from './common-table-expression-node.js' 4 | 5 | export type WithNodeParams = Omit 6 | 7 | export interface WithNode extends OperationNode { 8 | readonly kind: 'WithNode' 9 | readonly expressions: ReadonlyArray 10 | readonly recursive?: boolean 11 | } 12 | 13 | /** 14 | * @internal 15 | */ 16 | export const WithNode = freeze({ 17 | is(node: OperationNode): node is WithNode { 18 | return node.kind === 'WithNode' 19 | }, 20 | 21 | create( 22 | expression: CommonTableExpressionNode, 23 | params?: WithNodeParams, 24 | ): WithNode { 25 | return freeze({ 26 | kind: 'WithNode', 27 | expressions: freeze([expression]), 28 | ...params, 29 | }) 30 | }, 31 | 32 | cloneWithExpression( 33 | withNode: WithNode, 34 | expression: CommonTableExpressionNode, 35 | ): WithNode { 36 | return freeze({ 37 | ...withNode, 38 | expressions: freeze([...withNode.expressions, expression]), 39 | }) 40 | }, 41 | }) 42 | -------------------------------------------------------------------------------- /src/parser/collate-parser.ts: -------------------------------------------------------------------------------- 1 | export type Collation = 2 | // anything super common or simple should be added here. 3 | // https://sqlite.org/datatype3.html#collating_sequences 4 | | 'nocase' 5 | | 'binary' 6 | | 'rtrim' 7 | // otherwise, allow any string, while still providing autocompletion. 8 | | (string & {}) 9 | -------------------------------------------------------------------------------- /src/parser/data-type-parser.ts: -------------------------------------------------------------------------------- 1 | import { Expression } from '../expression/expression.js' 2 | import { 3 | ColumnDataType, 4 | DataTypeNode, 5 | isColumnDataType, 6 | } from '../operation-node/data-type-node.js' 7 | import { isOperationNodeSource } from '../operation-node/operation-node-source.js' 8 | import { OperationNode } from '../operation-node/operation-node.js' 9 | 10 | export type DataTypeExpression = ColumnDataType | Expression 11 | 12 | export function parseDataTypeExpression( 13 | dataType: DataTypeExpression, 14 | ): OperationNode { 15 | if (isOperationNodeSource(dataType)) { 16 | return dataType.toOperationNode() 17 | } 18 | 19 | if (isColumnDataType(dataType)) { 20 | return DataTypeNode.create(dataType) 21 | } 22 | 23 | throw new Error(`invalid column data type ${JSON.stringify(dataType)}`) 24 | } 25 | -------------------------------------------------------------------------------- /src/parser/default-value-parser.ts: -------------------------------------------------------------------------------- 1 | import { Expression } from '../expression/expression.js' 2 | import { isOperationNodeSource } from '../operation-node/operation-node-source.js' 3 | import { OperationNode } from '../operation-node/operation-node.js' 4 | import { ValueNode } from '../operation-node/value-node.js' 5 | 6 | export type DefaultValueExpression = unknown | Expression 7 | 8 | export function parseDefaultValueExpression( 9 | value: DefaultValueExpression, 10 | ): OperationNode { 11 | return isOperationNodeSource(value) 12 | ? value.toOperationNode() 13 | : ValueNode.createImmediate(value) 14 | } 15 | -------------------------------------------------------------------------------- /src/parser/fetch-parser.ts: -------------------------------------------------------------------------------- 1 | import { FetchModifier, FetchNode } from '../operation-node/fetch-node.js' 2 | import { isBigInt, isNumber } from '../util/object-utils.js' 3 | 4 | export function parseFetch( 5 | rowCount: number | bigint, 6 | modifier: FetchModifier, 7 | ): FetchNode { 8 | if (!isNumber(rowCount) && !isBigInt(rowCount)) { 9 | throw new Error(`Invalid fetch row count: ${rowCount}`) 10 | } 11 | 12 | if (!isFetchModifier(modifier)) { 13 | throw new Error(`Invalid fetch modifier: ${modifier}`) 14 | } 15 | 16 | return FetchNode.create(rowCount, modifier) 17 | } 18 | 19 | function isFetchModifier(value: any): value is FetchModifier { 20 | return value === 'only' || value === 'with ties' 21 | } 22 | -------------------------------------------------------------------------------- /src/parser/group-by-parser.ts: -------------------------------------------------------------------------------- 1 | import { GroupByItemNode } from '../operation-node/group-by-item-node.js' 2 | import { 3 | expressionBuilder, 4 | ExpressionBuilder, 5 | } from '../expression/expression-builder.js' 6 | import { isFunction } from '../util/object-utils.js' 7 | import { 8 | parseReferenceExpressionOrList, 9 | ReferenceExpression, 10 | } from './reference-parser.js' 11 | 12 | export type GroupByExpression = 13 | | ReferenceExpression 14 | | (keyof O & string) 15 | 16 | export type GroupByArg = 17 | | GroupByExpression 18 | | ReadonlyArray> 19 | | (( 20 | eb: ExpressionBuilder, 21 | ) => ReadonlyArray>) 22 | 23 | export function parseGroupBy( 24 | groupBy: GroupByArg, 25 | ): GroupByItemNode[] { 26 | groupBy = isFunction(groupBy) ? groupBy(expressionBuilder()) : groupBy 27 | return parseReferenceExpressionOrList(groupBy).map(GroupByItemNode.create) 28 | } 29 | -------------------------------------------------------------------------------- /src/parser/identifier-parser.ts: -------------------------------------------------------------------------------- 1 | import { SchemableIdentifierNode } from '../operation-node/schemable-identifier-node.js' 2 | 3 | export function parseSchemableIdentifier(id: string): SchemableIdentifierNode { 4 | const SCHEMA_SEPARATOR = '.' 5 | 6 | if (id.includes(SCHEMA_SEPARATOR)) { 7 | const parts = id.split(SCHEMA_SEPARATOR).map(trim) 8 | 9 | if (parts.length === 2) { 10 | return SchemableIdentifierNode.createWithSchema(parts[0], parts[1]) 11 | } else { 12 | throw new Error(`invalid schemable identifier ${id}`) 13 | } 14 | } else { 15 | return SchemableIdentifierNode.create(id) 16 | } 17 | } 18 | 19 | function trim(str: string): string { 20 | return str.trim() 21 | } 22 | -------------------------------------------------------------------------------- /src/parser/merge-into-parser.ts: -------------------------------------------------------------------------------- 1 | import type { MergeQueryBuilder } from '../query-builder/merge-query-builder.js' 2 | import type { MergeResult } from '../query-builder/merge-result.js' 3 | import type { ShallowRecord } from '../util/type-utils.js' 4 | import type { ExtractTableAlias, SimpleTableReference } from './table-parser.js' 5 | 6 | export type MergeInto< 7 | DB, 8 | TE extends SimpleTableReference, 9 | > = TE extends keyof DB & string 10 | ? MergeQueryBuilder, MergeResult> 11 | : TE extends `${infer T} as ${infer A}` 12 | ? T extends keyof DB 13 | ? MergeQueryBuilder, A, MergeResult> 14 | : never 15 | : never 16 | -------------------------------------------------------------------------------- /src/parser/on-commit-action-parse.ts: -------------------------------------------------------------------------------- 1 | import { 2 | OnCommitAction, 3 | ON_COMMIT_ACTIONS, 4 | } from '../operation-node/create-table-node.js' 5 | 6 | export function parseOnCommitAction(action: OnCommitAction): OnCommitAction { 7 | if (ON_COMMIT_ACTIONS.includes(action)) { 8 | return action 9 | } 10 | 11 | throw new Error(`invalid OnCommitAction ${action}`) 12 | } 13 | -------------------------------------------------------------------------------- /src/parser/on-modify-action-parser.ts: -------------------------------------------------------------------------------- 1 | import { 2 | OnModifyForeignAction, 3 | ON_MODIFY_FOREIGN_ACTIONS, 4 | } from '../operation-node/references-node.js' 5 | 6 | export function parseOnModifyForeignAction( 7 | action: OnModifyForeignAction, 8 | ): OnModifyForeignAction { 9 | if (ON_MODIFY_FOREIGN_ACTIONS.includes(action)) { 10 | return action 11 | } 12 | 13 | throw new Error(`invalid OnModifyForeignAction ${action}`) 14 | } 15 | -------------------------------------------------------------------------------- /src/parser/partition-by-parser.ts: -------------------------------------------------------------------------------- 1 | import { DynamicReferenceBuilder } from '../dynamic/dynamic-reference-builder.js' 2 | import { PartitionByItemNode } from '../operation-node/partition-by-item-node.js' 3 | import { SimpleReferenceExpressionNode } from '../operation-node/simple-reference-expression-node.js' 4 | import { 5 | parseReferenceExpressionOrList, 6 | StringReference, 7 | } from './reference-parser.js' 8 | 9 | export type PartitionByExpression = 10 | | StringReference 11 | | DynamicReferenceBuilder 12 | 13 | export type PartitionByExpressionOrList = 14 | | ReadonlyArray> 15 | | PartitionByExpression 16 | 17 | export function parsePartitionBy( 18 | partitionBy: PartitionByExpressionOrList, 19 | ): PartitionByItemNode[] { 20 | return ( 21 | parseReferenceExpressionOrList( 22 | partitionBy, 23 | ) as SimpleReferenceExpressionNode[] 24 | ).map(PartitionByItemNode.create) 25 | } 26 | -------------------------------------------------------------------------------- /src/parser/returning-parser.ts: -------------------------------------------------------------------------------- 1 | import { DeleteResult } from '../query-builder/delete-result.js' 2 | import { InsertResult } from '../query-builder/insert-result.js' 3 | import { MergeResult } from '../query-builder/merge-result.js' 4 | import { UpdateResult } from '../query-builder/update-result.js' 5 | import { Selection, AllSelection, CallbackSelection } from './select-parser.js' 6 | 7 | export type ReturningRow = O extends 8 | | InsertResult 9 | | DeleteResult 10 | | UpdateResult 11 | | MergeResult 12 | ? Selection 13 | : O & Selection 14 | 15 | export type ReturningCallbackRow = O extends 16 | | InsertResult 17 | | DeleteResult 18 | | UpdateResult 19 | | MergeResult 20 | ? CallbackSelection 21 | : O & CallbackSelection 22 | 23 | export type ReturningAllRow = O extends 24 | | InsertResult 25 | | DeleteResult 26 | | UpdateResult 27 | | MergeResult 28 | ? AllSelection 29 | : O & AllSelection 30 | -------------------------------------------------------------------------------- /src/parser/savepoint-parser.ts: -------------------------------------------------------------------------------- 1 | import { IdentifierNode } from '../operation-node/identifier-node.js' 2 | import { RawNode } from '../operation-node/raw-node.js' 3 | 4 | export type RollbackToSavepoint< 5 | S extends string[], 6 | SN extends S[number], 7 | > = S extends [...infer L, infer R] 8 | ? R extends SN 9 | ? S 10 | : RollbackToSavepoint 11 | : never 12 | 13 | export type ReleaseSavepoint< 14 | S extends string[], 15 | SN extends S[number], 16 | > = S extends [...infer L, infer R] 17 | ? R extends SN 18 | ? L 19 | : ReleaseSavepoint 20 | : never 21 | 22 | export function parseSavepointCommand( 23 | command: string, 24 | savepointName: string, 25 | ): RawNode { 26 | return RawNode.createWithChildren([ 27 | RawNode.createWithSql(`${command} `), 28 | IdentifierNode.create(savepointName), // ensures savepointName gets sanitized 29 | ]) 30 | } 31 | -------------------------------------------------------------------------------- /src/parser/set-operation-parser.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ExpressionBuilder, 3 | createExpressionBuilder, 4 | } from '../expression/expression-builder.js' 5 | import { Expression } from '../expression/expression.js' 6 | import { 7 | SetOperator, 8 | SetOperationNode, 9 | } from '../operation-node/set-operation-node.js' 10 | import { isFunction, isReadonlyArray } from '../util/object-utils.js' 11 | import { parseExpression } from './expression-parser.js' 12 | 13 | export type SetOperandExpression = 14 | | Expression 15 | | ReadonlyArray> 16 | | (( 17 | eb: ExpressionBuilder, 18 | ) => Expression | ReadonlyArray>) 19 | 20 | export function parseSetOperations( 21 | operator: SetOperator, 22 | expression: SetOperandExpression, 23 | all: boolean, 24 | ) { 25 | if (isFunction(expression)) { 26 | expression = expression(createExpressionBuilder()) 27 | } 28 | 29 | if (!isReadonlyArray(expression)) { 30 | expression = [expression] 31 | } 32 | 33 | return expression.map((expr) => 34 | SetOperationNode.create(operator, parseExpression(expr), all), 35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /src/parser/top-parser.ts: -------------------------------------------------------------------------------- 1 | import { TopModifier, TopNode } from '../operation-node/top-node.js' 2 | import { isBigInt, isNumber, isUndefined } from '../util/object-utils.js' 3 | 4 | export function parseTop( 5 | expression: number | bigint, 6 | modifiers?: TopModifier, 7 | ): TopNode { 8 | if (!isNumber(expression) && !isBigInt(expression)) { 9 | throw new Error(`Invalid top expression: ${expression}`) 10 | } 11 | 12 | if (!isUndefined(modifiers) && !isTopModifiers(modifiers)) { 13 | throw new Error(`Invalid top modifiers: ${modifiers}`) 14 | } 15 | 16 | return TopNode.create(expression, modifiers) 17 | } 18 | 19 | function isTopModifiers(modifiers: string): modifiers is TopModifier { 20 | return ( 21 | modifiers === 'percent' || 22 | modifiers === 'with ties' || 23 | modifiers === 'percent with ties' 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /src/parser/unary-operation-parser.ts: -------------------------------------------------------------------------------- 1 | import { OperatorNode, UnaryOperator } from '../operation-node/operator-node.js' 2 | import { UnaryOperationNode } from '../operation-node/unary-operation-node.js' 3 | import { ExpressionOrFactory } from './expression-parser.js' 4 | import { 5 | parseReferenceExpression, 6 | ReferenceExpression, 7 | } from './reference-parser.js' 8 | 9 | export type ExistsExpression = ExpressionOrFactory< 10 | DB, 11 | TB, 12 | any 13 | > 14 | 15 | export function parseExists( 16 | operand: ExistsExpression, 17 | ): UnaryOperationNode { 18 | return parseUnaryOperation('exists', operand) 19 | } 20 | 21 | export function parseNotExists( 22 | operand: ExistsExpression, 23 | ): UnaryOperationNode { 24 | return parseUnaryOperation('not exists', operand) 25 | } 26 | 27 | export function parseUnaryOperation( 28 | operator: UnaryOperator, 29 | operand: ReferenceExpression, 30 | ): UnaryOperationNode { 31 | return UnaryOperationNode.create( 32 | OperatorNode.create(operator), 33 | parseReferenceExpression(operand), 34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /src/plugin/camel-case/camel-case-transformer.ts: -------------------------------------------------------------------------------- 1 | import { IdentifierNode } from '../../operation-node/identifier-node.js' 2 | import { OperationNodeTransformer } from '../../operation-node/operation-node-transformer.js' 3 | import { QueryId } from '../../util/query-id.js' 4 | import { StringMapper } from './camel-case.js' 5 | 6 | export class SnakeCaseTransformer extends OperationNodeTransformer { 7 | readonly #snakeCase: StringMapper 8 | 9 | constructor(snakeCase: StringMapper) { 10 | super() 11 | this.#snakeCase = snakeCase 12 | } 13 | 14 | protected override transformIdentifier( 15 | node: IdentifierNode, 16 | queryId: QueryId, 17 | ): IdentifierNode { 18 | node = super.transformIdentifier(node, queryId) 19 | 20 | return { 21 | ...node, 22 | name: this.#snakeCase(node.name), 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/plugin/deduplicate-joins/deduplicate-joins-plugin.ts: -------------------------------------------------------------------------------- 1 | import { QueryResult } from '../../driver/database-connection.js' 2 | import { RootOperationNode } from '../../query-compiler/query-compiler.js' 3 | import { UnknownRow } from '../../util/type-utils.js' 4 | import { 5 | KyselyPlugin, 6 | PluginTransformQueryArgs, 7 | PluginTransformResultArgs, 8 | } from '../kysely-plugin.js' 9 | import { DeduplicateJoinsTransformer } from './deduplicate-joins-transformer.js' 10 | 11 | /** 12 | * Plugin that removes duplicate joins from queries. 13 | * 14 | * See [this recipe](https://github.com/kysely-org/kysely/blob/master/site/docs/recipes/0008-deduplicate-joins.md) 15 | */ 16 | export class DeduplicateJoinsPlugin implements KyselyPlugin { 17 | readonly #transformer = new DeduplicateJoinsTransformer() 18 | 19 | transformQuery(args: PluginTransformQueryArgs): RootOperationNode { 20 | return this.#transformer.transformNode(args.node, args.queryId) 21 | } 22 | 23 | transformResult( 24 | args: PluginTransformResultArgs, 25 | ): Promise> { 26 | return Promise.resolve(args.result) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/plugin/immediate-value/immediate-value-plugin.ts: -------------------------------------------------------------------------------- 1 | import { QueryResult } from '../../driver/database-connection.js' 2 | import { RootOperationNode } from '../../query-compiler/query-compiler.js' 3 | import { UnknownRow } from '../../util/type-utils.js' 4 | import { 5 | KyselyPlugin, 6 | PluginTransformQueryArgs, 7 | PluginTransformResultArgs, 8 | } from '../kysely-plugin.js' 9 | import { ImmediateValueTransformer } from './immediate-value-transformer.js' 10 | 11 | /** 12 | * Transforms all ValueNodes to immediate. 13 | * 14 | * WARNING! This should never be part of the public API. Users should never use this. 15 | * This is an internal helper. 16 | * 17 | * @internal 18 | */ 19 | export class ImmediateValuePlugin implements KyselyPlugin { 20 | readonly #transformer = new ImmediateValueTransformer() 21 | 22 | transformQuery(args: PluginTransformQueryArgs): RootOperationNode { 23 | return this.#transformer.transformNode(args.node, args.queryId) 24 | } 25 | 26 | transformResult( 27 | args: PluginTransformResultArgs, 28 | ): Promise> { 29 | return Promise.resolve(args.result) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/plugin/immediate-value/immediate-value-transformer.ts: -------------------------------------------------------------------------------- 1 | import { OperationNodeTransformer } from '../../operation-node/operation-node-transformer.js' 2 | import { PrimitiveValueListNode } from '../../operation-node/primitive-value-list-node.js' 3 | import { ValueListNode } from '../../operation-node/value-list-node.js' 4 | import { ValueNode } from '../../operation-node/value-node.js' 5 | 6 | /** 7 | * Transforms all ValueNodes to immediate. 8 | * 9 | * WARNING! This should never be part of the public API. Users should never use this. 10 | * This is an internal helper. 11 | * 12 | * @internal 13 | */ 14 | export class ImmediateValueTransformer extends OperationNodeTransformer { 15 | override transformPrimitiveValueList( 16 | node: PrimitiveValueListNode, 17 | ): PrimitiveValueListNode { 18 | return ValueListNode.create( 19 | node.values.map(ValueNode.createImmediate), 20 | ) as any 21 | } 22 | 23 | override transformValue(node: ValueNode): ValueNode { 24 | return ValueNode.createImmediate(node.value) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/plugin/noop-plugin.ts: -------------------------------------------------------------------------------- 1 | import { QueryResult } from '../driver/database-connection.js' 2 | import { RootOperationNode } from '../query-compiler/query-compiler.js' 3 | import { UnknownRow } from '../util/type-utils.js' 4 | import { 5 | KyselyPlugin, 6 | PluginTransformQueryArgs, 7 | PluginTransformResultArgs, 8 | } from './kysely-plugin.js' 9 | 10 | export class NoopPlugin implements KyselyPlugin { 11 | transformQuery(args: PluginTransformQueryArgs): RootOperationNode { 12 | return args.node 13 | } 14 | 15 | async transformResult( 16 | args: PluginTransformResultArgs, 17 | ): Promise> { 18 | return args.result 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/plugin/with-schema/with-schema-plugin.ts: -------------------------------------------------------------------------------- 1 | import { QueryResult } from '../../driver/database-connection.js' 2 | import { RootOperationNode } from '../../query-compiler/query-compiler.js' 3 | import { WithSchemaTransformer } from './with-schema-transformer.js' 4 | import { 5 | KyselyPlugin, 6 | PluginTransformQueryArgs, 7 | PluginTransformResultArgs, 8 | } from '../kysely-plugin.js' 9 | import { UnknownRow } from '../../util/type-utils.js' 10 | 11 | export class WithSchemaPlugin implements KyselyPlugin { 12 | readonly #transformer: WithSchemaTransformer 13 | 14 | constructor(schema: string) { 15 | this.#transformer = new WithSchemaTransformer(schema) 16 | } 17 | 18 | transformQuery(args: PluginTransformQueryArgs): RootOperationNode { 19 | return this.#transformer.transformNode(args.node, args.queryId) 20 | } 21 | 22 | async transformResult( 23 | args: PluginTransformResultArgs, 24 | ): Promise> { 25 | return args.result 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/query-builder/delete-result.ts: -------------------------------------------------------------------------------- 1 | export class DeleteResult { 2 | readonly numDeletedRows: bigint 3 | 4 | constructor(numDeletedRows: bigint) { 5 | this.numDeletedRows = numDeletedRows 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/query-builder/merge-result.ts: -------------------------------------------------------------------------------- 1 | export class MergeResult { 2 | readonly numChangedRows: bigint | undefined 3 | 4 | constructor(numChangedRows: bigint | undefined) { 5 | this.numChangedRows = numChangedRows 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/query-builder/no-result-error.ts: -------------------------------------------------------------------------------- 1 | import { QueryNode } from '../operation-node/query-node.js' 2 | 3 | export type NoResultErrorConstructor = new (node: QueryNode) => Error 4 | 5 | export class NoResultError extends Error { 6 | /** 7 | * The operation node tree of the query that was executed. 8 | */ 9 | readonly node: QueryNode 10 | 11 | constructor(node: QueryNode) { 12 | super('no result') 13 | this.node = node 14 | } 15 | } 16 | 17 | export function isNoResultErrorConstructor( 18 | fn: NoResultErrorConstructor | ((node: QueryNode) => Error), 19 | ): fn is NoResultErrorConstructor { 20 | return Object.prototype.hasOwnProperty.call(fn, 'prototype') 21 | } 22 | -------------------------------------------------------------------------------- /src/query-builder/select-query-builder-expression.ts: -------------------------------------------------------------------------------- 1 | import { AliasableExpression } from '../expression/expression.js' 2 | import { SelectQueryNode } from '../operation-node/select-query-node.js' 3 | 4 | export interface SelectQueryBuilderExpression 5 | extends AliasableExpression { 6 | get isSelectQueryBuilder(): true 7 | toOperationNode(): SelectQueryNode 8 | } 9 | -------------------------------------------------------------------------------- /src/query-builder/update-result.ts: -------------------------------------------------------------------------------- 1 | export class UpdateResult { 2 | /** 3 | * The number of rows the update query updated (even if not changed). 4 | */ 5 | readonly numUpdatedRows: bigint 6 | 7 | /** 8 | * The number of rows the update query changed. 9 | * 10 | * This is **optional** and only supported in dialects such as MySQL. 11 | * You would probably use {@link numUpdatedRows} in most cases. 12 | */ 13 | readonly numChangedRows?: bigint 14 | 15 | constructor(numUpdatedRows: bigint, numChangedRows: bigint | undefined) { 16 | this.numUpdatedRows = numUpdatedRows 17 | this.numChangedRows = numChangedRows 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/query-compiler/compiled-query.ts: -------------------------------------------------------------------------------- 1 | import { RawNode } from '../operation-node/raw-node.js' 2 | import { freeze } from '../util/object-utils.js' 3 | import { createQueryId, QueryId } from '../util/query-id.js' 4 | import { RootOperationNode } from './query-compiler.js' 5 | 6 | export interface CompiledQuery { 7 | readonly query: RootOperationNode 8 | readonly queryId: QueryId 9 | readonly sql: string 10 | readonly parameters: ReadonlyArray 11 | } 12 | 13 | export const CompiledQuery = freeze({ 14 | raw(sql: string, parameters: unknown[] = []): CompiledQuery { 15 | return freeze({ 16 | sql, 17 | query: RawNode.createWithSql(sql), 18 | parameters: freeze(parameters), 19 | queryId: createQueryId(), 20 | }) 21 | }, 22 | }) 23 | -------------------------------------------------------------------------------- /src/query-executor/query-executor-provider.ts: -------------------------------------------------------------------------------- 1 | import { QueryExecutor } from './query-executor.js' 2 | 3 | /** 4 | * @internal 5 | * @private 6 | */ 7 | export interface QueryExecutorProvider { 8 | getExecutor(): QueryExecutor 9 | } 10 | -------------------------------------------------------------------------------- /src/schema/check-constraint-builder.ts: -------------------------------------------------------------------------------- 1 | import { OperationNodeSource } from '../operation-node/operation-node-source.js' 2 | import { CheckConstraintNode } from '../operation-node/check-constraint-node.js' 3 | 4 | export class CheckConstraintBuilder implements OperationNodeSource { 5 | readonly #node: CheckConstraintNode 6 | 7 | constructor(node: CheckConstraintNode) { 8 | this.#node = node 9 | } 10 | 11 | /** 12 | * Simply calls the provided function passing `this` as the only argument. `$call` returns 13 | * what the provided function returns. 14 | */ 15 | $call(func: (qb: this) => T): T { 16 | return func(this) 17 | } 18 | 19 | toOperationNode(): CheckConstraintNode { 20 | return this.#node 21 | } 22 | } 23 | 24 | export type CheckConstraintBuilderCallback = ( 25 | builder: CheckConstraintBuilder, 26 | ) => CheckConstraintBuilder 27 | -------------------------------------------------------------------------------- /src/util/assert.ts: -------------------------------------------------------------------------------- 1 | export function assertNotNullOrUndefined( 2 | value: T, 3 | ): asserts value is NonNullable { 4 | if (value === null || value === undefined) { 5 | throw new Error(`${value} must not be null or undefined`) 6 | } 7 | } 8 | 9 | export function assertIsString(value: any): asserts value is string { 10 | if (typeof value !== 'string') { 11 | throw new Error(`${value} must be a string`) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/util/compilable.ts: -------------------------------------------------------------------------------- 1 | import { CompiledQuery } from '../query-compiler/compiled-query.js' 2 | import { isFunction, isObject } from './object-utils.js' 3 | 4 | export interface Compilable { 5 | compile(): CompiledQuery 6 | } 7 | 8 | export function isCompilable(value: unknown): value is Compilable { 9 | return isObject(value) && isFunction(value.compile) 10 | } 11 | -------------------------------------------------------------------------------- /src/util/deferred.ts: -------------------------------------------------------------------------------- 1 | export class Deferred { 2 | readonly #promise: Promise 3 | 4 | #resolve?: (value: T | PromiseLike) => void 5 | #reject?: (reason?: any) => void 6 | 7 | constructor() { 8 | this.#promise = new Promise((resolve, reject) => { 9 | this.#reject = reject 10 | this.#resolve = resolve 11 | }) 12 | } 13 | 14 | get promise(): Promise { 15 | return this.#promise 16 | } 17 | 18 | resolve = (value: T | PromiseLike): void => { 19 | if (this.#resolve) { 20 | this.#resolve(value) 21 | } 22 | } 23 | 24 | reject = (reason?: any): void => { 25 | if (this.#reject) { 26 | this.#reject(reason) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/util/log-once.ts: -------------------------------------------------------------------------------- 1 | const LOGGED_MESSAGES: Set = new Set() 2 | 3 | /** 4 | * Use for system-level logging, such as deprecation messages. 5 | * Logs a message and ensures it won't be logged again. 6 | */ 7 | export function logOnce(message: string): void { 8 | if (LOGGED_MESSAGES.has(message)) { 9 | return 10 | } 11 | 12 | LOGGED_MESSAGES.add(message) 13 | console.log(message) 14 | } 15 | -------------------------------------------------------------------------------- /src/util/performance-now.ts: -------------------------------------------------------------------------------- 1 | import { isFunction } from './object-utils.js' 2 | 3 | export function performanceNow() { 4 | if (typeof performance !== 'undefined' && isFunction(performance.now)) { 5 | return performance.now() 6 | } else { 7 | return Date.now() 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/util/query-id.ts: -------------------------------------------------------------------------------- 1 | import { randomString } from './random-string.js' 2 | 3 | export interface QueryId { 4 | readonly queryId: string 5 | } 6 | 7 | export function createQueryId(): QueryId { 8 | return new LazyQueryId() 9 | } 10 | 11 | class LazyQueryId implements QueryId { 12 | #queryId: string | undefined 13 | 14 | get queryId(): string { 15 | if (this.#queryId === undefined) { 16 | this.#queryId = randomString(8) 17 | } 18 | 19 | return this.#queryId 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/util/random-string.ts: -------------------------------------------------------------------------------- 1 | const CHARS = [ 2 | 'A', 3 | 'B', 4 | 'C', 5 | 'D', 6 | 'E', 7 | 'F', 8 | 'G', 9 | 'H', 10 | 'I', 11 | 'J', 12 | 'K', 13 | 'L', 14 | 'M', 15 | 'N', 16 | 'O', 17 | 'P', 18 | 'Q', 19 | 'R', 20 | 'S', 21 | 'T', 22 | 'U', 23 | 'V', 24 | 'W', 25 | 'X', 26 | 'Y', 27 | 'Z', 28 | 'a', 29 | 'b', 30 | 'c', 31 | 'd', 32 | 'e', 33 | 'f', 34 | 'g', 35 | 'h', 36 | 'i', 37 | 'j', 38 | 'k', 39 | 'l', 40 | 'm', 41 | 'n', 42 | 'o', 43 | 'p', 44 | 'q', 45 | 'r', 46 | 's', 47 | 't', 48 | 'u', 49 | 'v', 50 | 'w', 51 | 'x', 52 | 'y', 53 | 'z', 54 | '0', 55 | '1', 56 | '2', 57 | '3', 58 | '4', 59 | '5', 60 | '6', 61 | '7', 62 | '8', 63 | '9', 64 | ] 65 | 66 | export function randomString(length: number): string { 67 | let chars = '' 68 | 69 | for (let i = 0; i < length; ++i) { 70 | chars += randomChar() 71 | } 72 | 73 | return chars 74 | } 75 | 76 | function randomChar() { 77 | return CHARS[~~(Math.random() * CHARS.length)] 78 | } 79 | -------------------------------------------------------------------------------- /src/util/stack-trace-utils.ts: -------------------------------------------------------------------------------- 1 | import { isObject, isString } from './object-utils.js' 2 | 3 | export function extendStackTrace(err: unknown, stackError: Error): unknown { 4 | if (isStackHolder(err) && stackError.stack) { 5 | // Remove the first line that just says `Error`. 6 | const stackExtension = stackError.stack.split('\n').slice(1).join('\n') 7 | 8 | err.stack += `\n${stackExtension}` 9 | return err 10 | } 11 | 12 | return err 13 | } 14 | 15 | interface StackHolder { 16 | stack: string 17 | } 18 | 19 | function isStackHolder(obj: unknown): obj is StackHolder { 20 | return isObject(obj) && isString(obj.stack) 21 | } 22 | -------------------------------------------------------------------------------- /src/util/streamable.ts: -------------------------------------------------------------------------------- 1 | export interface Streamable { 2 | /** 3 | * Executes the query and streams the rows. 4 | * 5 | * The optional argument `chunkSize` defines how many rows to fetch from the database 6 | * at a time. It only affects some dialects like PostgreSQL that support it. 7 | * 8 | * ### Examples 9 | * 10 | * ```ts 11 | * const stream = db 12 | * .selectFrom('person') 13 | * .select(['first_name', 'last_name']) 14 | * .where('gender', '=', 'other') 15 | * .stream() 16 | * 17 | * for await (const person of stream) { 18 | * console.log(person.first_name) 19 | * 20 | * if (person.last_name === 'Something') { 21 | * // Breaking or returning before the stream has ended will release 22 | * // the database connection and invalidate the stream. 23 | * break 24 | * } 25 | * } 26 | * ``` 27 | */ 28 | stream(chunkSize?: number): AsyncIterableIterator 29 | } 30 | -------------------------------------------------------------------------------- /src/util/type-error.ts: -------------------------------------------------------------------------------- 1 | export interface KyselyTypeError { 2 | readonly __kyselyTypeError__: E 3 | } 4 | -------------------------------------------------------------------------------- /test/browser/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Kysely browser test 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/browser/main.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Kysely, 3 | Generated, 4 | DummyDriver, 5 | SqliteAdapter, 6 | SqliteIntrospector, 7 | SqliteQueryCompiler, 8 | } from '../..' 9 | 10 | interface Person { 11 | id: Generated 12 | first_name: string 13 | last_name: string | null 14 | } 15 | 16 | interface Database { 17 | person: Person 18 | } 19 | 20 | const db = new Kysely({ 21 | dialect: { 22 | createAdapter() { 23 | return new SqliteAdapter() 24 | }, 25 | createDriver() { 26 | return new DummyDriver() 27 | }, 28 | createIntrospector(db: Kysely) { 29 | return new SqliteIntrospector(db) 30 | }, 31 | createQueryCompiler() { 32 | return new SqliteQueryCompiler() 33 | }, 34 | }, 35 | }) 36 | 37 | window.addEventListener('load', () => { 38 | const sql = db.selectFrom('person').select('id').compile() 39 | 40 | const result = document.createElement('span') 41 | result.id = 'result' 42 | result.innerHTML = sql.sql 43 | 44 | document.body.appendChild(result) 45 | }) 46 | -------------------------------------------------------------------------------- /test/browser/test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Super simple smoke test that just opens an empty web page 3 | * and runs the `main.ts` script in it (bundled with esbuild). 4 | * The script builds a query and writes the result to a span 5 | * in the browser. 6 | */ 7 | 8 | const path = require('path') 9 | const { chromium } = require('playwright') 10 | 11 | const EXPECTED_SQL = 'select "id" from "person"' 12 | 13 | ;(async () => { 14 | let browser 15 | 16 | try { 17 | browser = await chromium.launch({ headless: true }) 18 | const page = await browser.newPage() 19 | 20 | await page.goto('file://' + path.join(__dirname, 'index.html')) 21 | // Wait until the main.ts script has finished and the result 22 | // span exists in the body. 23 | await page.waitForSelector('#result', { timeout: 5000 }) 24 | const sql = await page.$eval('#result', (el) => el.innerHTML) 25 | 26 | if (sql !== EXPECTED_SQL) { 27 | throw new Error(`failed to build a query`) 28 | } 29 | } catch (error) { 30 | console.error(error) 31 | process.exit(1) 32 | } finally { 33 | await browser?.close() 34 | } 35 | 36 | console.log('browser test passed') 37 | })() 38 | -------------------------------------------------------------------------------- /test/bun/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/test/bun/bun.lockb -------------------------------------------------------------------------------- /test/bun/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kysely-bun-test", 3 | "private": true, 4 | "scripts": { 5 | "test": "bun bun.test.ts" 6 | }, 7 | "dependencies": { 8 | "kysely": "link:kysely", 9 | "mysql2": "^3.11.0", 10 | "pg": "^8.12.0", 11 | "tarn": "^3.0.2", 12 | "tedious": "^19.0.0" 13 | }, 14 | "devDependencies": { 15 | "@types/bun": "^1.1.8", 16 | "typescript": "^5.5.4" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/cloudflare-workers/.dev.vars: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kysely-org/kysely/6333aeee019dd8ba4cc8f077d6a40203f54d9ae2/test/cloudflare-workers/.dev.vars -------------------------------------------------------------------------------- /test/cloudflare-workers/api.ts: -------------------------------------------------------------------------------- 1 | import { Pool } from 'pg' 2 | import { Hono } from 'hono' 3 | import { Generated, Kysely, PostgresDialect, sql } from '../../' 4 | 5 | interface Person { 6 | id: Generated 7 | first_name: string 8 | last_name: string | null 9 | } 10 | 11 | interface Database { 12 | person: Person 13 | } 14 | 15 | const db = new Kysely({ 16 | dialect: new PostgresDialect({ 17 | pool: new Pool({ 18 | database: 'kysely_test', 19 | host: 'localhost', 20 | user: 'kysely', 21 | port: 5434, 22 | }), 23 | }), 24 | }) 25 | 26 | const app = new Hono() 27 | 28 | app.get('/', async (c) => { 29 | if ( 30 | db.selectFrom('person').selectAll().compile().sql !== 31 | 'select * from "person"' 32 | ) { 33 | throw new Error('Unexpected SQL') 34 | } 35 | 36 | const { 37 | rows: [row], 38 | } = await sql`select 1 as ok`.execute(db) 39 | 40 | return c.json(row as object) 41 | }) 42 | 43 | export default app 44 | -------------------------------------------------------------------------------- /test/cloudflare-workers/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kysely-cloudflare-workers-test", 3 | "type": "module", 4 | "private": true, 5 | "scripts": { 6 | "test": "node --experimental-strip-types test.ts" 7 | }, 8 | "devDependencies": { 9 | "hono": "^4.5.8", 10 | "tsx": "^4.18.0", 11 | "wrangler": "^3.72.2" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/cloudflare-workers/test.ts: -------------------------------------------------------------------------------- 1 | import { unstable_dev } from 'wrangler' 2 | ;(async () => { 3 | const worker = await unstable_dev('./api.ts', { 4 | experimental: { disableExperimentalWarning: true }, 5 | local: true, 6 | nodeCompat: true, 7 | }) 8 | 9 | let exitCode = 0 10 | 11 | try { 12 | const response = await worker.fetch('/') 13 | 14 | if (!response.ok) { 15 | throw new Error(`Unexpected response: ${response.status}`) 16 | } 17 | 18 | console.log('test successful!') 19 | } catch (error) { 20 | exitCode = 1 21 | } finally { 22 | await worker.stop() 23 | process.exit(exitCode) 24 | } 25 | })() 26 | -------------------------------------------------------------------------------- /test/deno/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": { 3 | "kysely": "npm:kysely@^0.27.4", 4 | "mysql2": "npm:mysql2@^3.11.0", 5 | "pg": "npm:pg@^8.12.0", 6 | "pg-pool": "npm:pg-pool@^3.6.2" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/node/src/log-once.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import { createSandbox, SinonSpy } from 'sinon' 3 | import { logOnce } from '../../..' 4 | 5 | describe('logOnce', () => { 6 | let logSpy: SinonSpy 7 | const sandbox = createSandbox() 8 | 9 | before(() => { 10 | logSpy = sandbox.stub(console, 'log') 11 | }) 12 | 13 | after(() => { 14 | sandbox.restore() 15 | }) 16 | 17 | it('should log each message once.', () => { 18 | const message = 'Kysely is awesome!' 19 | const message2 = 'Type-safety is everything!' 20 | 21 | logOnce(message) 22 | logOnce(message) 23 | logOnce(message2) 24 | logOnce(message2) 25 | logOnce(message) 26 | 27 | expect(logSpy.calledTwice).to.be.true 28 | expect(logSpy.getCall(0).args[0]).to.equal(message) 29 | expect(logSpy.getCall(1).args[0]).to.equal(message2) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /test/node/src/object-util.test.ts: -------------------------------------------------------------------------------- 1 | import { isPlainObject } from '../../../dist/cjs/util/object-utils' 2 | 3 | import { expect } from './test-setup.js' 4 | 5 | describe('object util', () => { 6 | it('isPlainObject', async () => { 7 | class SomeClass {} 8 | 9 | for (const obj of [{ foo: 'bar' }, Object.create(null)]) { 10 | expect(isPlainObject(obj)).to.equal(true) 11 | } 12 | 13 | for (const obj of [ 14 | [], 15 | new Date(), 16 | Buffer.allocUnsafe(10), 17 | new ArrayBuffer(10), 18 | new Int32Array(10), 19 | new Float64Array(10), 20 | '', 21 | 42, 22 | false, 23 | null, 24 | undefined, 25 | new SomeClass(), 26 | ]) { 27 | expect(isPlainObject(obj)).to.equal(false) 28 | } 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /test/node/src/parse-json-results-plugin.test.ts: -------------------------------------------------------------------------------- 1 | import { ParseJSONResultsPlugin } from '../../..' 2 | import { createQueryId } from '../../../dist/cjs/util/query-id.js' 3 | 4 | describe('ParseJSONResultsPlugin', () => { 5 | describe("when `objectStrategy` is 'create'", () => { 6 | let plugin: ParseJSONResultsPlugin 7 | 8 | beforeEach(() => { 9 | plugin = new ParseJSONResultsPlugin({ objectStrategy: 'create' }) 10 | }) 11 | 12 | it('should parse JSON results that contain readonly arrays/objects', async () => { 13 | await plugin.transformResult({ 14 | queryId: createQueryId(), 15 | result: { 16 | rows: [ 17 | Object.freeze({ 18 | id: 1, 19 | carIds: Object.freeze([1, 2, 3]), 20 | metadata: JSON.stringify({ foo: 'bar' }), 21 | }), 22 | ], 23 | }, 24 | }) 25 | }) 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /test/node/src/test-migrations/migration1.ts: -------------------------------------------------------------------------------- 1 | import { Kysely } from '../../../../' 2 | 3 | export async function up(db: Kysely): Promise { 4 | await db.schema 5 | .createTable('test1') 6 | .addColumn('id', 'integer', (col) => col.primaryKey()) 7 | .execute() 8 | } 9 | 10 | export async function down(db: Kysely): Promise { 11 | await db.schema.dropTable('test1').execute() 12 | } 13 | -------------------------------------------------------------------------------- /test/node/src/test-migrations/migration2.ts: -------------------------------------------------------------------------------- 1 | import { Kysely } from '../../../../' 2 | 3 | export async function up(db: Kysely): Promise { 4 | await db.schema 5 | .createTable('test2') 6 | .addColumn('id', 'integer', (col) => col.primaryKey()) 7 | .addColumn('test1_id', 'integer', (col) => col.references('test1.id')) 8 | .execute() 9 | } 10 | 11 | // Down migration is missing on purpose. It's optional. 12 | -------------------------------------------------------------------------------- /test/node/tsconfig.json: -------------------------------------------------------------------------------- 1 | {"compilerOptions":{"target":"ES2022","lib":["ESNext"],"module":"CommonJS","outDir":"dist","skipLibCheck":true},"default":{"compilerOptions":{"target":"ES2022","lib":["ESNext"],"module":"CommonJS","outDir":"dist","skipLibCheck":true},"default":{"compilerOptions":{"target":"ES2022","lib":["ESNext"],"module":"CommonJS","outDir":"dist","skipLibCheck":true},"default":{"extends":"../../tsconfig-base.json","include":["src/**/*"],"compilerOptions":{"target":"ES2022","lib":["ESNext"],"module":"CommonJS","outDir":"dist","skipLibCheck":true}},"extends":"../../tsconfig-base.json","include":["src/**/*"],"exclude":["src/async-dispose.test.ts"]},"exclude":["src/async-dispose.test.ts"],"extends":"../../tsconfig-base.json","include":["src/**/*"]},"exclude":["src/async-dispose.test.ts","src/async-dispose.test.ts"],"extends":"../../tsconfig-base.json","include":["src/**/*"]} -------------------------------------------------------------------------------- /test/outdated-ts/outdated-ts.test.ts: -------------------------------------------------------------------------------- 1 | import { Kysely, RawBuilder, sql } from 'kysely' 2 | import { KyselyTypeError } from '../../src/util/type-error' 3 | 4 | function expectOutdatedTSError( 5 | _: KyselyTypeError<'The installed TypeScript version is outdated and cannot guarantee type-safety with Kysely. Please upgrade to version 4.6 or newer.'>, 6 | ): void {} 7 | 8 | expectOutdatedTSError(Kysely) 9 | expectOutdatedTSError(RawBuilder) 10 | expectOutdatedTSError(sql) 11 | -------------------------------------------------------------------------------- /test/outdated-ts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "outdated-ts", 3 | "private": true, 4 | "version": "1.0.0", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "tsc --noEmit" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "description": "", 13 | "dependencies": { 14 | "kysely": "file:../../" 15 | }, 16 | "devDependencies": { 17 | "typescript": "4.5.x" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/outdated-ts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "include": ["./**/*"], 4 | "compilerOptions": { 5 | "skipLibCheck": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/scripts/mysql-init.sql: -------------------------------------------------------------------------------- 1 | CREATE USER 'kysely'@'%' IDENTIFIED WITH mysql_native_password BY 'kysely'; 2 | GRANT ALL ON *.* TO 'kysely'@'%'; 3 | CREATE DATABASE kysely_test; -------------------------------------------------------------------------------- /test/ts-benchmarks/index.ts: -------------------------------------------------------------------------------- 1 | import './select-from.bench.ts' 2 | import './order-by.bench.ts' 3 | -------------------------------------------------------------------------------- /test/ts-benchmarks/package.json: -------------------------------------------------------------------------------- 1 | { "type": "module" } 2 | -------------------------------------------------------------------------------- /test/ts-benchmarks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "include": ["**/*.ts"], 4 | } 5 | -------------------------------------------------------------------------------- /test/typings/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from '../../' 2 | export * from '../../helpers/postgres' 3 | -------------------------------------------------------------------------------- /test/typings/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "types": "index.d.ts" 3 | } 4 | -------------------------------------------------------------------------------- /test/typings/test-d/select-no-from.test-d.ts: -------------------------------------------------------------------------------- 1 | import { Kysely, SqlBool, sql } from '..' 2 | import { Database } from '../shared' 3 | import { expectType } from 'tsd' 4 | 5 | async function testSelectNoFrom(db: Kysely) { 6 | const r1 = await db 7 | .selectNoFrom(sql<'bar'>`select 'bar'`.as('foo')) 8 | .executeTakeFirstOrThrow() 9 | expectType<{ foo: 'bar' }>(r1) 10 | 11 | const r2 = await db 12 | .selectNoFrom((eb) => eb(eb.val(1), '=', 1).as('very_useful')) 13 | .executeTakeFirstOrThrow() 14 | expectType<{ very_useful: SqlBool }>(r2) 15 | 16 | const r3 = await db 17 | .selectNoFrom([ 18 | sql<'bar'>`select 'bar'`.as('foo'), 19 | db.selectFrom('pet').select('id').limit(1).as('pet_id'), 20 | ]) 21 | .executeTakeFirstOrThrow() 22 | expectType<{ foo: 'bar'; pet_id: string | null }>(r3) 23 | 24 | const r4 = await db 25 | .selectNoFrom((eb) => [ 26 | eb(eb.val(1), '=', 1).as('very_useful'), 27 | eb.selectFrom('pet').select('id').limit(1).as('pet_id'), 28 | ]) 29 | .executeTakeFirstOrThrow() 30 | expectType<{ very_useful: SqlBool; pet_id: string | null }>(r4) 31 | } 32 | -------------------------------------------------------------------------------- /test/typings/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "include": ["./**/*"], 4 | "compilerOptions": { 5 | "exactOptionalPropertyTypes": true, 6 | "module": "CommonJS" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tsconfig-base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "Node", 4 | "target": "ESNext", 5 | "declaration": true, 6 | "strict": true, 7 | "noImplicitAny": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig-cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig-base.json", 3 | "include": ["src/**/*"], 4 | "compilerOptions": { 5 | "module": "CommonJS", 6 | "outDir": "dist/cjs" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig-base.json", 3 | "include": ["src/**/*"], 4 | "compilerOptions": { 5 | "module": "ESNext", 6 | "outDir": "dist/esm" 7 | } 8 | } 9 | --------------------------------------------------------------------------------