kysely
Version:
Type safe SQL query builder
298 lines (297 loc) • 11.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.QueryCreator = void 0;
const select_query_builder_js_1 = require("./query-builder/select-query-builder.js");
const insert_query_builder_js_1 = require("./query-builder/insert-query-builder.js");
const delete_query_builder_js_1 = require("./query-builder/delete-query-builder.js");
const update_query_builder_js_1 = require("./query-builder/update-query-builder.js");
const delete_query_node_js_1 = require("./operation-node/delete-query-node.js");
const insert_query_node_js_1 = require("./operation-node/insert-query-node.js");
const select_query_node_js_1 = require("./operation-node/select-query-node.js");
const update_query_node_js_1 = require("./operation-node/update-query-node.js");
const table_parser_js_1 = require("./parser/table-parser.js");
const with_parser_js_1 = require("./parser/with-parser.js");
const with_node_js_1 = require("./operation-node/with-node.js");
const query_id_js_1 = require("./util/query-id.js");
const with_schema_plugin_js_1 = require("./plugin/with-schema/with-schema-plugin.js");
const object_utils_js_1 = require("./util/object-utils.js");
const select_parser_js_1 = require("./parser/select-parser.js");
const merge_query_builder_js_1 = require("./query-builder/merge-query-builder.js");
const merge_query_node_js_1 = require("./operation-node/merge-query-node.js");
class QueryCreator {
#props;
constructor(props) {
this.#props = (0, object_utils_js_1.freeze)(props);
}
selectFrom(from) {
return (0, select_query_builder_js_1.createSelectQueryBuilder)({
queryId: (0, query_id_js_1.createQueryId)(),
executor: this.#props.executor,
queryNode: select_query_node_js_1.SelectQueryNode.createFrom((0, table_parser_js_1.parseTableExpressionOrList)(from), this.#props.withNode),
});
}
selectNoFrom(selection) {
return (0, select_query_builder_js_1.createSelectQueryBuilder)({
queryId: (0, query_id_js_1.createQueryId)(),
executor: this.#props.executor,
queryNode: select_query_node_js_1.SelectQueryNode.cloneWithSelections(select_query_node_js_1.SelectQueryNode.create(this.#props.withNode), (0, select_parser_js_1.parseSelectArg)(selection)),
});
}
/**
* 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(table) {
return new insert_query_builder_js_1.InsertQueryBuilder({
queryId: (0, query_id_js_1.createQueryId)(),
executor: this.#props.executor,
queryNode: insert_query_node_js_1.InsertQueryNode.create((0, table_parser_js_1.parseTable)(table), this.#props.withNode),
});
}
/**
* 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(table) {
return new insert_query_builder_js_1.InsertQueryBuilder({
queryId: (0, query_id_js_1.createQueryId)(),
executor: this.#props.executor,
queryNode: insert_query_node_js_1.InsertQueryNode.create((0, table_parser_js_1.parseTable)(table), this.#props.withNode, true),
});
}
deleteFrom(tables) {
return new delete_query_builder_js_1.DeleteQueryBuilder({
queryId: (0, query_id_js_1.createQueryId)(),
executor: this.#props.executor,
queryNode: delete_query_node_js_1.DeleteQueryNode.create((0, table_parser_js_1.parseTableExpressionOrList)(tables), this.#props.withNode),
});
}
updateTable(table) {
return new update_query_builder_js_1.UpdateQueryBuilder({
queryId: (0, query_id_js_1.createQueryId)(),
executor: this.#props.executor,
queryNode: update_query_node_js_1.UpdateQueryNode.create((0, table_parser_js_1.parseTableExpression)(table), this.#props.withNode),
});
}
mergeInto(targetTable) {
return new merge_query_builder_js_1.MergeQueryBuilder({
queryId: (0, query_id_js_1.createQueryId)(),
executor: this.#props.executor,
queryNode: merge_query_node_js_1.MergeQueryNode.create((0, table_parser_js_1.parseAliasedTable)(targetTable), this.#props.withNode),
});
}
/**
* 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(nameOrBuilder, expression) {
const cte = (0, with_parser_js_1.parseCommonTableExpression)(nameOrBuilder, expression);
return new QueryCreator({
...this.#props,
withNode: this.#props.withNode
? with_node_js_1.WithNode.cloneWithExpression(this.#props.withNode, cte)
: with_node_js_1.WithNode.create(cte),
});
}
/**
* 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(nameOrBuilder, expression) {
const cte = (0, with_parser_js_1.parseCommonTableExpression)(nameOrBuilder, expression);
return new QueryCreator({
...this.#props,
withNode: this.#props.withNode
? with_node_js_1.WithNode.cloneWithExpression(this.#props.withNode, cte)
: with_node_js_1.WithNode.create(cte, { recursive: true }),
});
}
/**
* Returns a copy of this query creator instance with the given plugin installed.
*/
withPlugin(plugin) {
return new QueryCreator({
...this.#props,
executor: this.#props.executor.withPlugin(plugin),
});
}
/**
* Returns a copy of this query creator instance without any plugins.
*/
withoutPlugins() {
return new QueryCreator({
...this.#props,
executor: this.#props.executor.withoutPlugins(),
});
}
/**
* 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) {
return new QueryCreator({
...this.#props,
executor: this.#props.executor.withPluginAtFront(new with_schema_plugin_js_1.WithSchemaPlugin(schema)),
});
}
}
exports.QueryCreator = QueryCreator;