UNPKG

kysely

Version:
494 lines (493 loc) 17.2 kB
import { SelectQueryBuilder } from './query-builder/select-query-builder.js'; import { InsertQueryBuilder } from './query-builder/insert-query-builder.js'; import { DeleteQueryBuilder } from './query-builder/delete-query-builder.js'; import { UpdateQueryBuilder } from './query-builder/update-query-builder.js'; import { TableExpression, From, FromTables, TableReference, ExtractTableAlias, AnyAliasedTable, PickTableWithAlias } from './parser/table-parser.js'; import { QueryExecutor } from './query-executor/query-executor.js'; import { CommonTableExpression, QueryCreatorWithCommonTableExpression, RecursiveCommonTableExpression } from './parser/with-parser.js'; import { WithNode } from './operation-node/with-node.js'; import { InsertResult } from './query-builder/insert-result.js'; import { DeleteResult } from './query-builder/delete-result.js'; import { UpdateResult } from './query-builder/update-result.js'; import { KyselyPlugin } from './plugin/kysely-plugin.js'; import { CTEBuilderCallback } from './query-builder/cte-builder.js'; import { CallbackSelection, SelectCallback, SelectExpression, Selection } from './parser/select-parser.js'; import { MergeQueryBuilder } from './query-builder/merge-query-builder.js'; import { MergeResult } from './query-builder/merge-result.js'; export declare class QueryCreator<DB> { #private; constructor(props: QueryCreatorProps); /** * Creates a `select` query builder for the given table or tables. * * The tables passed to this method are built as the query's `from` clause. * * ### Examples * * Create a select query for one table: * * ```ts * db.selectFrom('person').selectAll() * ``` * * The generated SQL (PostgreSQL): * * ```sql * select * from "person" * ``` * * Create a select query for one table with an alias: * * ```ts * const persons = await db.selectFrom('person as p') * .select(['p.id', 'first_name']) * .execute() * * console.log(persons[0].id) * ``` * * The generated SQL (PostgreSQL): * * ```sql * select "p"."id", "first_name" from "person" as "p" * ``` * * Create a select query from a subquery: * * ```ts * const persons = await db.selectFrom( * (eb) => eb.selectFrom('person').select('person.id as identifier').as('p') * ) * .select('p.identifier') * .execute() * * console.log(persons[0].identifier) * ``` * * The generated SQL (PostgreSQL): * * ```sql * select "p"."identifier", * from ( * select "person"."id" as "identifier" from "person" * ) as p * ``` * * Create a select query from raw sql: * * ```ts * import { sql } from 'kysely' * * const items = await db * .selectFrom(sql<{ one: number }>`(select 1 as one)`.as('q')) * .select('q.one') * .execute() * * console.log(items[0].one) * ``` * * The generated SQL (PostgreSQL): * * ```sql * select "q"."one", * from ( * select 1 as one * ) as q * ``` * * When you use the `sql` tag you need to also provide the result type of the * raw snippet / query so that Kysely can figure out what columns are * available for the rest of the query. * * The `selectFrom` method also accepts an array for multiple tables. All * the above examples can also be used in an array. * * ```ts * import { sql } from 'kysely' * * const items = await db.selectFrom([ * 'person as p', * db.selectFrom('pet').select('pet.species').as('a'), * sql<{ one: number }>`(select 1 as one)`.as('q') * ]) * .select(['p.id', 'a.species', 'q.one']) * .execute() * ``` * * The generated SQL (PostgreSQL): * * ```sql * select "p".id, "a"."species", "q"."one" * from * "person" as "p", * (select "pet"."species" from "pet") as a, * (select 1 as one) as "q" * ``` */ selectFrom<TE extends keyof DB & string>(from: TE[]): SelectQueryBuilder<DB, ExtractTableAlias<DB, TE>, {}>; selectFrom<TE extends TableExpression<DB, keyof DB>>(from: TE[]): SelectQueryBuilder<From<DB, TE>, FromTables<DB, never, TE>, {}>; selectFrom<TE extends keyof DB & string>(from: TE): SelectQueryBuilder<DB, ExtractTableAlias<DB, TE>, {}>; selectFrom<TE extends AnyAliasedTable<DB>>(from: TE): SelectQueryBuilder<DB & PickTableWithAlias<DB, TE>, ExtractTableAlias<DB & PickTableWithAlias<DB, TE>, TE>, {}>; selectFrom<TE extends TableExpression<DB, keyof DB>>(from: TE): SelectQueryBuilder<From<DB, TE>, FromTables<DB, never, TE>, {}>; /** * Creates a `select` query builder without a `from` clause. * * If you want to create a `select from` query, use the `selectFrom` method instead. * This one can be used to create a plain `select` statement without a `from` clause. * * This method accepts the same inputs as {@link SelectQueryBuilder.select}. See its * documentation for more examples. * * ### Examples * * ```ts * const result = db.selectNoFrom((eb) => [ * eb.selectFrom('person') * .select('id') * .where('first_name', '=', 'Jennifer') * .limit(1) * .as('jennifer_id'), * * eb.selectFrom('pet') * .select('id') * .where('name', '=', 'Doggo') * .limit(1) * .as('doggo_id') * ]) * .executeTakeFirstOrThrow() * * console.log(result.jennifer_id) * console.log(result.doggo_id) * ``` * * The generated SQL (PostgreSQL): * * ```sql * select ( * select "id" * from "person" * where "first_name" = $1 * limit $2 * ) as "jennifer_id", ( * select "id" * from "pet" * where "name" = $3 * limit $4 * ) as "doggo_id" * ``` */ selectNoFrom<SE extends SelectExpression<DB, never>>(selections: ReadonlyArray<SE>): SelectQueryBuilder<DB, never, Selection<DB, never, SE>>; selectNoFrom<CB extends SelectCallback<DB, never>>(callback: CB): SelectQueryBuilder<DB, never, CallbackSelection<DB, never, CB>>; selectNoFrom<SE extends SelectExpression<DB, never>>(selection: SE): SelectQueryBuilder<DB, never, Selection<DB, never, SE>>; /** * Creates an insert query. * * The return value of this query is an instance of {@link InsertResult}. {@link InsertResult} * has the {@link InsertResult.insertId | insertId} field that holds the auto incremented id of * the inserted row if the db returned one. * * See the {@link InsertQueryBuilder.values | values} method for more info and examples. Also see * the {@link ReturningInterface.returning | returning} method for a way to return columns * on supported databases like PostgreSQL. * * ### Examples * * ```ts * const result = await db * .insertInto('person') * .values({ * first_name: 'Jennifer', * last_name: 'Aniston' * }) * .executeTakeFirst() * * console.log(result.insertId) * ``` * * Some databases like PostgreSQL support the `returning` method: * * ```ts * const { id } = await db * .insertInto('person') * .values({ * first_name: 'Jennifer', * last_name: 'Aniston' * }) * .returning('id') * .executeTakeFirst() * ``` */ insertInto<T extends keyof DB & string>(table: T): InsertQueryBuilder<DB, T, InsertResult>; /** * Creates a replace query. * * A MySQL-only statement similar to {@link InsertQueryBuilder.onDuplicateKeyUpdate} * that deletes and inserts values on collision instead of updating existing rows. * * The return value of this query is an instance of {@link InsertResult}. {@link InsertResult} * has the {@link InsertResult.insertId | insertId} field that holds the auto incremented id of * the inserted row if the db returned one. * * See the {@link InsertQueryBuilder.values | values} method for more info and examples. * * ### Examples * * ```ts * const result = await db * .replaceInto('person') * .values({ * first_name: 'Jennifer', * last_name: 'Aniston' * }) * .executeTakeFirst() * * console.log(result.insertId) * ``` */ replaceInto<T extends keyof DB & string>(table: T): InsertQueryBuilder<DB, T, InsertResult>; /** * Creates a delete query. * * See the {@link DeleteQueryBuilder.where} method for examples on how to specify * a where clause for the delete operation. * * The return value of the query is an instance of {@link DeleteResult}. * * ### Examples * * <!-- siteExample("delete", "Single row", 10) --> * * Delete a single row: * * ```ts * const result = await db * .deleteFrom('person') * .where('person.id', '=', '1') * .executeTakeFirst() * * console.log(result.numDeletedRows) * ``` * * The generated SQL (PostgreSQL): * * ```sql * delete from "person" where "person"."id" = $1 * ``` * * Some databases such as MySQL support deleting from multiple tables: * * ```ts * const result = await db * .deleteFrom(['person', 'pet']) * .using('person') * .innerJoin('pet', 'pet.owner_id', '=', 'person.id') * .where('person.id', '=', 1) * .executeTakeFirst() * ``` * * The generated SQL (MySQL): * * ```sql * delete from `person`, `pet` * using `person` * inner join `pet` on `pet`.`owner_id` = `person`.`id` * where `person`.`id` = ? * ``` */ deleteFrom<TR extends keyof DB & string>(from: TR[]): DeleteQueryBuilder<DB, ExtractTableAlias<DB, TR>, DeleteResult>; deleteFrom<TR extends TableReference<DB>>(tables: TR[]): DeleteQueryBuilder<From<DB, TR>, FromTables<DB, never, TR>, DeleteResult>; deleteFrom<TR extends keyof DB & string>(from: TR): DeleteQueryBuilder<DB, ExtractTableAlias<DB, TR>, DeleteResult>; deleteFrom<TR extends TableReference<DB>>(table: TR): DeleteQueryBuilder<From<DB, TR>, FromTables<DB, never, TR>, DeleteResult>; /** * Creates an update query. * * See the {@link UpdateQueryBuilder.where} method for examples on how to specify * a where clause for the update operation. * * See the {@link UpdateQueryBuilder.set} method for examples on how to * specify the updates. * * The return value of the query is an {@link UpdateResult}. * * ### Examples * * ```ts * const result = await db * .updateTable('person') * .set({ first_name: 'Jennifer' }) * .where('person.id', '=', 1) * .executeTakeFirst() * * console.log(result.numUpdatedRows) * ``` */ updateTable<TR extends keyof DB & string>(table: TR): UpdateQueryBuilder<DB, ExtractTableAlias<DB, TR>, ExtractTableAlias<DB, TR>, UpdateResult>; updateTable<TR extends AnyAliasedTable<DB>>(table: TR): UpdateQueryBuilder<DB & PickTableWithAlias<DB, TR>, ExtractTableAlias<DB & PickTableWithAlias<DB, TR>, TR>, ExtractTableAlias<DB & PickTableWithAlias<DB, TR>, TR>, UpdateResult>; updateTable<TR extends TableReference<DB>>(table: TR): UpdateQueryBuilder<From<DB, TR>, FromTables<DB, never, TR>, FromTables<DB, never, TR>, UpdateResult>; /** * Creates a merge query. * * The return value of the query is a {@link MergeResult}. * * See the {@link MergeQueryBuilder.using} method for examples on how to specify * the other table. * * ### Examples * * ```ts * const result = await db * .mergeInto('person') * .using('pet', 'pet.owner_id', 'person.id') * .whenMatched((and) => and('has_pets', '!=', 'Y')) * .thenUpdateSet({ has_pets: 'Y' }) * .whenNotMatched() * .thenDoNothing() * .executeTakeFirstOrThrow() * * console.log(result.numChangedRows) * ``` * * The generated SQL (PostgreSQL): * * ```sql * merge into "person" * using "pet" on "pet"."owner_id" = "person"."id" * when matched and "has_pets" != $1 then * update set "has_pets" = $2 * when not matched then * do nothing * ``` */ mergeInto<TR extends keyof DB & string>(targetTable: TR): MergeQueryBuilder<DB, TR, MergeResult>; mergeInto<TR extends AnyAliasedTable<DB>>(targetTable: TR): MergeQueryBuilder<DB & PickTableWithAlias<DB, TR>, ExtractTableAlias<DB & PickTableWithAlias<DB, TR>, TR>, MergeResult>; /** * Creates a `with` query (Common Table Expression). * * ### Examples * * ```ts * await db * .with('jennifers', (db) => db * .selectFrom('person') * .where('first_name', '=', 'Jennifer') * .select(['id', 'age']) * ) * .with('adult_jennifers', (db) => db * .selectFrom('jennifers') * .where('age', '>', 18) * .select(['id', 'age']) * ) * .selectFrom('adult_jennifers') * .where('age', '<', 60) * .selectAll() * .execute() * ``` * * The CTE name can optionally specify column names in addition to * a name. In that case Kysely requires the expression to retun * rows with the same columns. * * ```ts * await db * .with('jennifers(id, age)', (db) => db * .selectFrom('person') * .where('first_name', '=', 'Jennifer') * // This is ok since we return columns with the same * // names as specified by `jennifers(id, age)`. * .select(['id', 'age']) * ) * .selectFrom('jennifers') * .selectAll() * .execute() * ``` * * The first argument can also be a callback. The callback is passed * a `CTEBuilder` instance that can be used to configure the CTE: * * ```ts * await db * .with( * (cte) => cte('jennifers').materialized(), * (db) => db * .selectFrom('person') * .where('first_name', '=', 'Jennifer') * .select(['id', 'age']) * ) * .selectFrom('jennifers') * .selectAll() * .execute() * ``` */ with<N extends string, E extends CommonTableExpression<DB, N>>(nameOrBuilder: N | CTEBuilderCallback<N>, expression: E): QueryCreatorWithCommonTableExpression<DB, N, E>; /** * Creates a recursive `with` query (Common Table Expression). * * Note that recursiveness is a property of the whole `with` statement. * You cannot have recursive and non-recursive CTEs in a same `with` statement. * Therefore the recursiveness is determined by the **first** `with` or * `withRecusive` call you make. * * See the {@link with} method for examples and more documentation. */ withRecursive<N extends string, E extends RecursiveCommonTableExpression<DB, N>>(nameOrBuilder: N | CTEBuilderCallback<N>, expression: E): QueryCreatorWithCommonTableExpression<DB, N, E>; /** * Returns a copy of this query creator instance with the given plugin installed. */ withPlugin(plugin: KyselyPlugin): QueryCreator<DB>; /** * Returns a copy of this query creator instance without any plugins. */ withoutPlugins(): QueryCreator<DB>; /** * Sets the schema to be used for all table references that don't explicitly * specify a schema. * * This only affects the query created through the builder returned from * this method and doesn't modify the `db` instance. * * See [this recipe](https://github.com/koskimas/kysely/tree/master/site/docs/recipes/schemas.md) * for a more detailed explanation. * * ### Examples * * ``` * await db * .withSchema('mammals') * .selectFrom('pet') * .selectAll() * .innerJoin('public.person', 'public.person.id', 'pet.owner_id') * .execute() * ``` * * The generated SQL (PostgreSQL): * * ```sql * select * from "mammals"."pet" * inner join "public"."person" * on "public"."person"."id" = "mammals"."pet"."owner_id" * ``` * * `withSchema` is smart enough to not add schema for aliases, * common table expressions or other places where the schema * doesn't belong to: * * ``` * await db * .withSchema('mammals') * .selectFrom('pet as p') * .select('p.name') * .execute() * ``` * * The generated SQL (PostgreSQL): * * ```sql * select "p"."name" from "mammals"."pet" as "p" * ``` */ withSchema(schema: string): QueryCreator<DB>; } export interface QueryCreatorProps { readonly executor: QueryExecutor; readonly withNode?: WithNode; }