Comparing version 0.1.2 to 0.1.3
@@ -21,3 +21,3 @@ "use strict"; | ||
const cfg = this.config; | ||
// Use the pg modules own pool. All drivers should use the | ||
// Use the `pg` module's own pool. All drivers should use the | ||
// pool provided by the database connector library if possible. | ||
@@ -75,4 +75,6 @@ this.#pgPool = new pg.Pool({ | ||
]); | ||
return result.rows; | ||
return result.command === 'UPDATE' || result.command === 'DELETE' | ||
? [result.rowCount] | ||
: result.rows; | ||
} | ||
} |
import { Connection } from './connection'; | ||
export interface ConnectionProvider { | ||
acquireConnection(): Promise<Connection>; | ||
releaseConnection(connection: Connection): Promise<void>; | ||
withConnection<T>(runner: (connection: Connection) => Promise<T>): Promise<T>; | ||
} |
import { CompiledQuery } from '../query-compiler/compiled-query'; | ||
export interface Connection { | ||
execute<R>(compiledQuery: CompiledQuery): Promise<R[]>; | ||
execute<R>(compiledQuery: CompiledQuery): Promise<R[] | number[]>; | ||
} |
@@ -9,4 +9,5 @@ /// <reference types="node" /> | ||
constructor(driver: Driver, transactions: AsyncLocalStorage<Connection>); | ||
acquireConnection(): Promise<Connection>; | ||
releaseConnection(connection: Connection): Promise<void>; | ||
withConnection<T>(runner: (connection: Connection) => Promise<T>): Promise<T>; | ||
private acquireConnection; | ||
private releaseConnection; | ||
} |
@@ -11,2 +11,11 @@ "use strict"; | ||
#transactions; | ||
async withConnection(runner) { | ||
const connection = await this.acquireConnection(); | ||
try { | ||
return await runner(connection); | ||
} | ||
finally { | ||
await this.releaseConnection(connection); | ||
} | ||
} | ||
async acquireConnection() { | ||
@@ -13,0 +22,0 @@ const transaction = this.#transactions.getStore(); |
@@ -6,1 +6,2 @@ export * from './kysely'; | ||
export * from './query-compiler/compiled-query'; | ||
export * from './schema/schema'; |
@@ -18,1 +18,2 @@ "use strict"; | ||
__exportStar(require("./query-compiler/compiled-query"), exports); | ||
__exportStar(require("./schema/schema"), exports); |
@@ -0,5 +1,9 @@ | ||
import { QueryBuilder } from './query-builder/query-builder'; | ||
import { RawBuilder } from './raw-builder/raw-builder'; | ||
import { TableArg, FromQueryBuilder } from './query-builder/methods/from-method'; | ||
import { TableExpression, QueryBuilderWithTable, TableReference } from './parser/table-parser'; | ||
import { DriverConfig } from './driver/driver-config'; | ||
import { Dialect } from './dialect/dialect'; | ||
import { Schema } from './schema/schema'; | ||
import { Dynamic } from './dynamic/dynamic'; | ||
import { DeleteResultTypeTag, InsertResultTypeTag, UpdateResultTypeTag } from './query-builder/type-utils'; | ||
/** | ||
@@ -42,17 +46,23 @@ * The main Kysely class. | ||
constructor(config: KyselyConfig); | ||
get schema(): Schema; | ||
get dynamic(): Dynamic; | ||
/** | ||
* Creates a query builder against the given table/tables. | ||
* Creates a `select` query builder against the given table/tables. | ||
* | ||
* The tables passed to this method are built as the query's `from` clause in case | ||
* of `select` and `delete` queries, `into` clause in case of `insert` queries and | ||
* `update` clause in case of `update` queries. | ||
* The tables passed to this method are built as the query's `from` clause. | ||
* | ||
* The tables must be either one of the keys of the `DB` type, aliased versions of | ||
* the keys of the `DB` type, queries or `raw` statements. See the examples. | ||
* The tables must be: | ||
* | ||
* - one of the keys of the `DB` type | ||
* - aliased versions of the keys of the `DB` type | ||
* - select queries | ||
* - `raw` statements. | ||
* | ||
* See the examples. | ||
* | ||
* @example | ||
* Create a select query from one table: | ||
* Create a select query for one table: | ||
* | ||
* ```ts | ||
* db.query('person').selectAll('person') | ||
* db.selectFrom('person').selectAll() | ||
* ``` | ||
@@ -63,10 +73,10 @@ * | ||
* ```sql | ||
* select "person".* from "person" | ||
* select * from "person" | ||
* ``` | ||
* | ||
* @example | ||
* Create a select query from one table with an alias: | ||
* Create a select query for one table with an alias: | ||
* | ||
* ```ts | ||
* const persons = await db.query('person as p') | ||
* const persons = await db.selectFrom('person as p') | ||
* .select(['p.id', 'p.first_name']) | ||
@@ -88,4 +98,4 @@ * .execute() | ||
* ```ts | ||
* const persons = await db.query( | ||
* db.query('person').select('person.id as identifier').as('p') | ||
* const persons = await db.selectFrom( | ||
* db.selectFrom('person').select('person.id as identifier').as('p') | ||
* ) | ||
@@ -111,3 +121,3 @@ * .select('p.identifier') | ||
* ```ts | ||
* const items = await db.query( | ||
* const items = await db.selectFrom( | ||
* db.raw<{ one: number }>('select 1 as one').as('q') | ||
@@ -135,10 +145,10 @@ * ) | ||
* @example | ||
* The `query` method also accepts an array for multiple tables. All | ||
* The `selectFrom` method also accepts an array for multiple tables. All | ||
* the above examples can also be used in an array. | ||
* | ||
* ```ts | ||
* const items = await db.query([ | ||
* const items = await db.selectFrom([ | ||
* 'person', | ||
* 'movie as m', | ||
* db.query('pet').select('pet.species').as('a'), | ||
* db.selectFrom('pet').select('pet.species').as('a'), | ||
* db.raw<{ one: number }>('select 1 as one').as('q') | ||
@@ -160,17 +170,76 @@ * ]) | ||
* ``` | ||
*/ | ||
selectFrom<F extends TableExpression<DB, keyof DB>>(from: F[]): QueryBuilderWithTable<DB, never, {}, F>; | ||
selectFrom<F extends TableExpression<DB, keyof DB>>(from: F): QueryBuilderWithTable<DB, never, {}, F>; | ||
/** | ||
* Creates an insert query. | ||
* | ||
* The return value of this query is `number | undefined` because of the differences | ||
* between database engines. Most engines (like Mysql) return the auto incrementing | ||
* primary key (if it exists), but some (like postgres) return nothing by default. | ||
* If you are running a database engine like `Mysql` that always returns the primary | ||
* key, you can safely use `!` or the {@link QueryBuilder.castTo | castTo} method | ||
* to cast away the `undefined` from the type. | ||
* | ||
* See the {@link QueryBuilder.values | values} method for more info and examples. Also see | ||
* the {@link QueryBuilder.returning | returning} method for a way to return columns | ||
* on supported databases like postgres. | ||
* | ||
* @example | ||
* With `insert`, `delete` and `update` you can only use existing tables. | ||
* You obviously can't insert rows to a subquery or delete rows from a random | ||
* raw statement (unless that raw statement is simply a table name). | ||
* ```ts | ||
* const maybePrimaryKey: number | undefined = await db | ||
* .insertInto('person') | ||
* .values({ | ||
* first_name: 'Jennifer', | ||
* last_name: 'Aniston' | ||
* }) | ||
* .executeTakeFirst() | ||
* ``` | ||
* | ||
* @example | ||
* Some databases like postgres support the `returning` method: | ||
* ```ts | ||
* db.query('person').insert(person) | ||
* db.query('person').delete().where('id', 'in', [1, 2, 3]) | ||
* db.query('person').update({ species: 'cat' }).where('id', 'in', [1, 2, 3]) | ||
* const { id } = await db | ||
* .insertInto('person') | ||
* .values({ | ||
* first_name: 'Jennifer', | ||
* last_name: 'Aniston' | ||
* }) | ||
* .returning('id') | ||
* .executeTakeFirst() | ||
* ``` | ||
*/ | ||
query<F extends TableArg<DB, keyof DB, {}>>(from: F[]): FromQueryBuilder<DB, never, {}, F>; | ||
query<F extends TableArg<DB, keyof DB, {}>>(from: F): FromQueryBuilder<DB, never, {}, F>; | ||
insertInto<T extends keyof DB & string>(table: T): QueryBuilder<DB, T, InsertResultTypeTag>; | ||
/** | ||
* Creates a delete query. | ||
* | ||
* See {@link QueryBuilder.where} for examples on how to specify the where | ||
* clauses for the delete operation. | ||
* | ||
* @example | ||
* ```ts | ||
* const numAffectedRows = await db | ||
* .deleteFrom('person') | ||
* .where('person.id', '=', 1) | ||
* .executeTakeFirst() | ||
* ``` | ||
*/ | ||
deleteFrom<TR extends TableReference<DB>>(table: TR): QueryBuilderWithTable<DB, never, DeleteResultTypeTag, TR>; | ||
/** | ||
* Creates an update query. | ||
* | ||
* See {@link QueryBuilder.where} for examples on how to specify the where | ||
* clauses for the update operation. | ||
* | ||
* @example | ||
* ```ts | ||
* const numAffectedRows = await db | ||
* .updateTable('person') | ||
* .set({ first_name: 'Jennifer' }) | ||
* .where('person.id', '=', 1) | ||
* .executeTakeFirst() | ||
* ``` | ||
*/ | ||
updateTable<TR extends TableReference<DB>>(table: TR): QueryBuilderWithTable<DB, never, UpdateResultTypeTag, TR>; | ||
/** | ||
* Provides a way to pass arbitrary SQL into your query and executing completely | ||
@@ -205,3 +274,3 @@ * raw queries. | ||
* ```ts | ||
* const [person] = await db.query('person') | ||
* const [person] = await db.selectFrom('person') | ||
* .select(db.raw<string>('concat(first_name, ' ', last_name)').as('name')) | ||
@@ -261,3 +330,3 @@ * .where('id', '=', 1) | ||
* function getPersonsOlderThan(ageLimit: number) { | ||
* return await db.query('person') | ||
* return await db.selectFrom('person') | ||
* .selectAll() | ||
@@ -304,3 +373,3 @@ * .where( | ||
* Any `kysely` query started inside the callback or any method called | ||
* by the callback will automatically use the save transaction. No need to | ||
* by the callback will automatically use the same transaction. No need to | ||
* pass around a transaction object. This is possible through node's async | ||
@@ -321,3 +390,3 @@ * hooks and specifically `AsyncLocalStorage`. | ||
* // for a shared `AsyncLocalStorage` inside `Kysely`. | ||
* await db.query('person').insert({ first_name: 'Jennifer' }).execute() | ||
* await db.selectFrom('person').insert({ first_name: 'Jennifer' }).execute() | ||
* | ||
@@ -328,6 +397,6 @@ * return doMoreStuff(); | ||
* function doMoreStuff(): Promise<void> { | ||
* // Even this is automatically uses the correct transaction even though | ||
* // Even this automatically uses the correct transaction even though | ||
* // we didn't `await` on the method. Node's async hooks work with all | ||
* // possible kinds of async events. | ||
* return db.query('pet').insert({ name: 'Fluffy' }).execute() | ||
* return db.selectFrom('pet').insert({ name: 'Fluffy' }).execute() | ||
* } | ||
@@ -334,0 +403,0 @@ * ``` |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Kysely = void 0; | ||
const query_node_1 = require("./operation-node/query-node"); | ||
const query_builder_1 = require("./query-builder/query-builder"); | ||
const raw_builder_1 = require("./raw-builder/raw-builder"); | ||
const from_method_1 = require("./query-builder/methods/from-method"); | ||
const table_parser_1 = require("./parser/table-parser"); | ||
const postgres_dialect_1 = require("./dialect/postgres/postgres-dialect"); | ||
const transactional_connection_provider_1 = require("./driver/transactional-connection-provider"); | ||
const async_hooks_1 = require("async_hooks"); | ||
const schema_1 = require("./schema/schema"); | ||
const select_query_node_1 = require("./operation-node/select-query-node"); | ||
const insert_query_node_1 = require("./operation-node/insert-query-node"); | ||
const delete_query_node_1 = require("./operation-node/delete-query-node"); | ||
const dynamic_1 = require("./dynamic/dynamic"); | ||
const update_query_node_1 = require("./operation-node/update-query-node"); | ||
/** | ||
@@ -51,2 +56,3 @@ * The main Kysely class. | ||
this.#compiler = dialect.createQueryCompiler(); | ||
this.#connectionProvider = new transactional_connection_provider_1.TransactionalConnectionProvider(this.#driver, this.#transactions); | ||
} | ||
@@ -56,12 +62,105 @@ #driver; | ||
#transactions; | ||
query(from) { | ||
const query = new query_builder_1.QueryBuilder({ queryNode: query_node_1.createQueryNode() }); | ||
const connectionProvider = new transactional_connection_provider_1.TransactionalConnectionProvider(this.#driver, this.#transactions); | ||
#connectionProvider; | ||
get schema() { | ||
return schema_1.createSchemaObject(this.#compiler, this.#connectionProvider); | ||
} | ||
get dynamic() { | ||
return dynamic_1.createDynamicObject(); | ||
} | ||
selectFrom(from) { | ||
return new query_builder_1.QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithFroms(query.toOperationNode(), from_method_1.parseFromArgs(query, from)), | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: select_query_node_1.createSelectQueryNodeWithFromItems(table_parser_1.parseTableExpressionOrList(from)), | ||
}); | ||
} | ||
/** | ||
* Creates an insert query. | ||
* | ||
* The return value of this query is `number | undefined` because of the differences | ||
* between database engines. Most engines (like Mysql) return the auto incrementing | ||
* primary key (if it exists), but some (like postgres) return nothing by default. | ||
* If you are running a database engine like `Mysql` that always returns the primary | ||
* key, you can safely use `!` or the {@link QueryBuilder.castTo | castTo} method | ||
* to cast away the `undefined` from the type. | ||
* | ||
* See the {@link QueryBuilder.values | values} method for more info and examples. Also see | ||
* the {@link QueryBuilder.returning | returning} method for a way to return columns | ||
* on supported databases like postgres. | ||
* | ||
* @example | ||
* ```ts | ||
* const maybePrimaryKey: number | undefined = await db | ||
* .insertInto('person') | ||
* .values({ | ||
* first_name: 'Jennifer', | ||
* last_name: 'Aniston' | ||
* }) | ||
* .executeTakeFirst() | ||
* ``` | ||
* | ||
* @example | ||
* Some databases like postgres 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 query_builder_1.QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: insert_query_node_1.createInsertQueryNodeWithTable(table_parser_1.parseTable(table)), | ||
}); | ||
} | ||
/** | ||
* Creates a delete query. | ||
* | ||
* See {@link QueryBuilder.where} for examples on how to specify the where | ||
* clauses for the delete operation. | ||
* | ||
* @example | ||
* ```ts | ||
* const numAffectedRows = await db | ||
* .deleteFrom('person') | ||
* .where('person.id', '=', 1) | ||
* .executeTakeFirst() | ||
* ``` | ||
*/ | ||
deleteFrom(table) { | ||
return new query_builder_1.QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: delete_query_node_1.createDeleteQueryNodeWithFromItem(table_parser_1.parseTableExpression(table)), | ||
}); | ||
} | ||
/** | ||
* Creates an update query. | ||
* | ||
* See {@link QueryBuilder.where} for examples on how to specify the where | ||
* clauses for the update operation. | ||
* | ||
* @example | ||
* ```ts | ||
* const numAffectedRows = await db | ||
* .updateTable('person') | ||
* .set({ first_name: 'Jennifer' }) | ||
* .where('person.id', '=', 1) | ||
* .executeTakeFirst() | ||
* ``` | ||
*/ | ||
updateTable(table) { | ||
return new query_builder_1.QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: update_query_node_1.createUpdateQueryNodeWithTable(table_parser_1.parseTableExpression(table)), | ||
}); | ||
} | ||
/** | ||
* Provides a way to pass arbitrary SQL into your query and executing completely | ||
@@ -96,3 +195,3 @@ * raw queries. | ||
* ```ts | ||
* const [person] = await db.query('person') | ||
* const [person] = await db.selectFrom('person') | ||
* .select(db.raw<string>('concat(first_name, ' ', last_name)').as('name')) | ||
@@ -152,3 +251,3 @@ * .where('id', '=', 1) | ||
* function getPersonsOlderThan(ageLimit: number) { | ||
* return await db.query('person') | ||
* return await db.selectFrom('person') | ||
* .selectAll() | ||
@@ -199,3 +298,3 @@ * .where( | ||
* Any `kysely` query started inside the callback or any method called | ||
* by the callback will automatically use the save transaction. No need to | ||
* by the callback will automatically use the same transaction. No need to | ||
* pass around a transaction object. This is possible through node's async | ||
@@ -216,3 +315,3 @@ * hooks and specifically `AsyncLocalStorage`. | ||
* // for a shared `AsyncLocalStorage` inside `Kysely`. | ||
* await db.query('person').insert({ first_name: 'Jennifer' }).execute() | ||
* await db.selectFrom('person').insert({ first_name: 'Jennifer' }).execute() | ||
* | ||
@@ -223,6 +322,6 @@ * return doMoreStuff(); | ||
* function doMoreStuff(): Promise<void> { | ||
* // Even this is automatically uses the correct transaction even though | ||
* // Even this automatically uses the correct transaction even though | ||
* // we didn't `await` on the method. Node's async hooks work with all | ||
* // possible kinds of async events. | ||
* return db.query('pet').insert({ name: 'Fluffy' }).execute() | ||
* return db.selectFrom('pet').insert({ name: 'Fluffy' }).execute() | ||
* } | ||
@@ -240,5 +339,7 @@ * ``` | ||
await connection.execute({ sql: 'BEGIN', bindings: [] }); | ||
return await this.#transactions.run(connection, () => { | ||
const result = await this.#transactions.run(connection, () => { | ||
return callback(); | ||
}); | ||
await connection.execute({ sql: 'COMMIT', bindings: [] }); | ||
return result; | ||
} | ||
@@ -245,0 +346,0 @@ catch (error) { |
import { ColumnNode } from './column-node'; | ||
import { IdentifierNode } from './identifier-node'; | ||
import { OperationNode } from './operation-node'; | ||
import { QueryNode } from './query-node'; | ||
import { RawNode } from './raw-node'; | ||
import { ReferenceNode } from './reference-node'; | ||
import { SelectQueryNode } from './select-query-node'; | ||
import { TableNode } from './table-node'; | ||
declare type AliasNodeChild = ReferenceNode | TableNode | RawNode | QueryNode | ColumnNode; | ||
declare type AliasNodeChild = ColumnNode | ReferenceNode | TableNode | RawNode | SelectQueryNode; | ||
export interface AliasNode extends OperationNode { | ||
@@ -10,0 +10,0 @@ readonly kind: 'AliasNode'; |
@@ -8,6 +8,6 @@ import { OperationNode } from './operation-node'; | ||
readonly kind: 'AndNode'; | ||
readonly lhs: AndNodeChildNode; | ||
readonly rhs: AndNodeChildNode; | ||
readonly left: AndNodeChildNode; | ||
readonly right: AndNodeChildNode; | ||
} | ||
export declare function isAndNode(node: OperationNode): node is AndNode; | ||
export declare function createAndNode(lhs: AndNodeChildNode, rhs: AndNodeChildNode): AndNode; | ||
export declare function createAndNode(left: AndNodeChildNode, right: AndNodeChildNode): AndNode; |
@@ -9,9 +9,9 @@ "use strict"; | ||
exports.isAndNode = isAndNode; | ||
function createAndNode(lhs, rhs) { | ||
function createAndNode(left, right) { | ||
return object_utils_1.freeze({ | ||
kind: 'AndNode', | ||
lhs, | ||
rhs, | ||
left, | ||
right, | ||
}); | ||
} | ||
exports.createAndNode = createAndNode; |
@@ -1,20 +0,13 @@ | ||
import { ColumnNode } from './column-node'; | ||
import { OperationNode } from './operation-node'; | ||
import { ReferenceExpressionNode, ValueExpressionNode } from './operation-node-utils'; | ||
import { OperatorNode } from './operator-node'; | ||
import { PrimitiveValueListNode } from './primitive-value-list-node'; | ||
import { QueryNode } from './query-node'; | ||
import { RawNode } from './raw-node'; | ||
import { ReferenceNode } from './reference-node'; | ||
import { ValueListNode } from './value-list-node'; | ||
import { ValueNode } from './value-node'; | ||
export declare type FilterNodeLhsNode = ColumnNode | ReferenceNode | QueryNode | RawNode; | ||
export declare type FilterOperatorNode = OperatorNode | RawNode; | ||
export declare type FilterNodeRhsNode = ValueNode | ValueListNode | PrimitiveValueListNode | FilterNodeLhsNode; | ||
export interface FilterNode extends OperationNode { | ||
readonly kind: 'FilterNode'; | ||
readonly lhs?: FilterNodeLhsNode; | ||
readonly left?: ReferenceExpressionNode; | ||
readonly op: OperatorNode | RawNode; | ||
readonly rhs: FilterNodeRhsNode; | ||
readonly right: ValueExpressionNode; | ||
} | ||
export declare function isFilterNode(node: OperationNode): node is FilterNode; | ||
export declare function createFilterNode(lhs: FilterNodeLhsNode | undefined, op: OperatorNode | RawNode, rhs: FilterNodeRhsNode): FilterNode; | ||
export declare function createFilterNode(left: ReferenceExpressionNode | undefined, op: OperatorNode | RawNode, right: ValueExpressionNode): FilterNode; |
@@ -9,10 +9,10 @@ "use strict"; | ||
exports.isFilterNode = isFilterNode; | ||
function createFilterNode(lhs, op, rhs) { | ||
function createFilterNode(left, op, right) { | ||
return object_utils_1.freeze({ | ||
kind: 'FilterNode', | ||
lhs, | ||
left, | ||
op, | ||
rhs, | ||
right, | ||
}); | ||
} | ||
exports.createFilterNode = createFilterNode; |
@@ -1,11 +0,9 @@ | ||
import { AliasNode } from './alias-node'; | ||
import { OperationNode } from './operation-node'; | ||
import { TableNode } from './table-node'; | ||
declare type FromNodeChild = TableNode | AliasNode; | ||
import { TableExpressionNode } from './operation-node-utils'; | ||
export interface FromNode extends OperationNode { | ||
readonly kind: 'FromNode'; | ||
readonly from: FromNodeChild; | ||
readonly froms: ReadonlyArray<TableExpressionNode>; | ||
} | ||
export declare function isFromNode(node: OperationNode): node is FromNode; | ||
export declare function createFromNode(from: FromNodeChild): FromNode; | ||
export {}; | ||
export declare function createFromNodeWithItems(froms: ReadonlyArray<TableExpressionNode>): FromNode; | ||
export declare function cloneFromNodeWithItems(from: FromNode, items: ReadonlyArray<TableExpressionNode>): FromNode; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.createFromNode = exports.isFromNode = void 0; | ||
exports.cloneFromNodeWithItems = exports.createFromNodeWithItems = exports.isFromNode = void 0; | ||
const object_utils_1 = require("../utils/object-utils"); | ||
@@ -9,8 +9,15 @@ function isFromNode(node) { | ||
exports.isFromNode = isFromNode; | ||
function createFromNode(from) { | ||
function createFromNodeWithItems(froms) { | ||
return object_utils_1.freeze({ | ||
kind: 'FromNode', | ||
from, | ||
froms: object_utils_1.freeze(froms), | ||
}); | ||
} | ||
exports.createFromNode = createFromNode; | ||
exports.createFromNodeWithItems = createFromNodeWithItems; | ||
function cloneFromNodeWithItems(from, items) { | ||
return object_utils_1.freeze({ | ||
...from, | ||
froms: object_utils_1.freeze([...from.froms, ...items]), | ||
}); | ||
} | ||
exports.cloneFromNodeWithItems = cloneFromNodeWithItems; |
@@ -0,7 +1,9 @@ | ||
import { AliasNode } from './alias-node'; | ||
import { AndNode } from './and-node'; | ||
import { FilterNode } from './filter-node'; | ||
import { FromNode } from './from-node'; | ||
import { OperationNode } from './operation-node'; | ||
import { OrNode } from './or-node'; | ||
import { ParensNode } from './parens-node'; | ||
import { TableNode } from './table-node'; | ||
export declare type JoinTableNode = TableNode | AliasNode; | ||
export declare type JoinType = 'InnerJoin' | 'LeftJoin' | 'RightJoin' | 'FullJoin'; | ||
@@ -12,7 +14,7 @@ export declare type JoinNodeOnNode = FilterNode | AndNode | OrNode | ParensNode; | ||
readonly joinType: JoinType; | ||
readonly table: FromNode; | ||
readonly table: JoinTableNode; | ||
readonly on?: JoinNodeOnNode; | ||
} | ||
export declare function isJoinNode(node: OperationNode): node is JoinNode; | ||
export declare function createJoinNode(joinType: JoinType, table: FromNode): JoinNode; | ||
export declare function createJoinNode(joinType: JoinType, table: JoinTableNode): JoinNode; | ||
export declare function cloneJoinNodeWithOn(joinNode: JoinNode, op: 'and' | 'or', on: JoinNodeOnNode): JoinNode; |
import { AliasNode } from '../operation-node/alias-node'; | ||
import { ColumnNode } from '../operation-node/column-node'; | ||
import { FromNode } from '../operation-node/from-node'; | ||
import { IdentifierNode } from '../operation-node/identifier-node'; | ||
@@ -15,5 +14,4 @@ import { OperationNode } from '../operation-node/operation-node'; | ||
import { PrimitiveValueListNode } from './primitive-value-list-node'; | ||
import { QueryNode } from './query-node'; | ||
import { RawNode } from './raw-node'; | ||
import { SelectNode } from './select-node'; | ||
import { SelectQueryNode } from './select-query-node'; | ||
import { ValueListNode } from './value-list-node'; | ||
@@ -23,7 +21,21 @@ import { ValueNode } from './value-node'; | ||
import { OperatorNode } from './operator-node'; | ||
import { FromNode } from './from-node'; | ||
import { WhereNode } from './where-node'; | ||
import { InsertQueryNode } from './insert-query-node'; | ||
import { DeleteQueryNode } from './delete-query-node'; | ||
import { ReturningNode } from './returning-node'; | ||
import { CreateTableNode } from './create-table-node'; | ||
import { ColumnDefinitionNode } from './column-definition-node'; | ||
import { DropTableNode } from './drop-table-node'; | ||
import { DataTypeNode } from './data-type-node'; | ||
import { OrderByNode } from './order-by-node'; | ||
import { OrderByItemNode } from './order-by-item-node'; | ||
import { GroupByNode } from './group-by-node'; | ||
import { GroupByItemNode } from './group-by-item-node'; | ||
import { UpdateQueryNode } from './update-query-node'; | ||
import { ColumnUpdateNode } from './column-update-node'; | ||
export declare class OperationNodeVisitor { | ||
#private; | ||
readonly visitNode: (node: OperationNode) => void; | ||
protected visitQuery(node: QueryNode): void; | ||
protected visitSelect(node: SelectNode): void; | ||
protected visitSelectQuery(node: SelectQueryNode): void; | ||
protected visitSelection(node: SelectionNode): void; | ||
@@ -42,2 +54,16 @@ protected visitColumn(node: ColumnNode): void; | ||
protected visitRaw(node: RawNode): void; | ||
protected visitWhere(node: WhereNode): void; | ||
protected visitInsertQuery(node: InsertQueryNode): void; | ||
protected visitDeleteQuery(node: DeleteQueryNode): void; | ||
protected visitReturning(node: ReturningNode): void; | ||
protected visitCreateTable(node: CreateTableNode): void; | ||
protected visitColumnDefinition(node: ColumnDefinitionNode): void; | ||
protected visitDropTable(node: DropTableNode): void; | ||
protected visitOrderBy(node: OrderByNode): void; | ||
protected visitOrderByItem(node: OrderByItemNode): void; | ||
protected visitGroupBy(node: GroupByNode): void; | ||
protected visitGroupByItem(node: GroupByItemNode): void; | ||
protected visitUpdateQuery(node: UpdateQueryNode): void; | ||
protected visitColumnUpdate(node: ColumnUpdateNode): void; | ||
protected visitDataType(node: DataTypeNode): void; | ||
protected visitSelectAll(_: SelectAllNode): void; | ||
@@ -44,0 +70,0 @@ protected visitIdentifier(_: IdentifierNode): void; |
@@ -10,6 +10,5 @@ "use strict"; | ||
IdentifierNode: this.visitIdentifier.bind(this), | ||
QueryNode: this.visitQuery.bind(this), | ||
RawNode: this.visitRaw.bind(this), | ||
ReferenceNode: this.visitReference.bind(this), | ||
SelectNode: this.visitSelect.bind(this), | ||
SelectQueryNode: this.visitSelectQuery.bind(this), | ||
SelectionNode: this.visitSelection.bind(this), | ||
@@ -28,2 +27,16 @@ TableNode: this.visitTable.bind(this), | ||
OperatorNode: this.visitOperator.bind(this), | ||
WhereNode: this.visitWhere.bind(this), | ||
InsertQueryNode: this.visitInsertQuery.bind(this), | ||
DeleteQueryNode: this.visitDeleteQuery.bind(this), | ||
ReturningNode: this.visitReturning.bind(this), | ||
CreateTableNode: this.visitCreateTable.bind(this), | ||
ColumnDefinitionNode: this.visitColumnDefinition.bind(this), | ||
DropTableNode: this.visitDropTable.bind(this), | ||
DataTypeNode: this.visitDataType.bind(this), | ||
OrderByNode: this.visitOrderBy.bind(this), | ||
OrderByItemNode: this.visitOrderByItem.bind(this), | ||
GroupByNode: this.visitGroupBy.bind(this), | ||
GroupByItemNode: this.visitGroupByItem.bind(this), | ||
UpdateQueryNode: this.visitUpdateQuery.bind(this), | ||
ColumnUpdateNode: this.visitColumnUpdate.bind(this), | ||
}; | ||
@@ -35,15 +48,22 @@ this.visitNode = (node) => { | ||
#visitors; | ||
visitQuery(node) { | ||
node.from.forEach(this.visitNode); | ||
if (node.select) { | ||
this.visitNode(node.select); | ||
visitSelectQuery(node) { | ||
if (node.selections) { | ||
node.selections.forEach(this.visitNode); | ||
} | ||
if (node.distinctOnSelections) { | ||
node.distinctOnSelections.forEach(this.visitNode); | ||
} | ||
if (node.from) { | ||
this.visitNode(node.from); | ||
} | ||
if (node.joins) { | ||
node.joins.forEach(this.visitNode); | ||
} | ||
if (node.where) { | ||
this.visitNode(node.where); | ||
} | ||
if (node.orderBy) { | ||
this.visitNode(node.orderBy); | ||
} | ||
} | ||
visitSelect(node) { | ||
node.selections.forEach(this.visitNode); | ||
node.distinctOnSelections.forEach(this.visitNode); | ||
} | ||
visitSelection(node) { | ||
@@ -65,3 +85,3 @@ this.visitNode(node.selection); | ||
visitFrom(node) { | ||
this.visitNode(node.from); | ||
node.froms.forEach(this.visitNode); | ||
} | ||
@@ -73,15 +93,15 @@ visitReference(node) { | ||
visitFilter(node) { | ||
if (node.lhs) { | ||
this.visitNode(node.lhs); | ||
if (node.left) { | ||
this.visitNode(node.left); | ||
} | ||
this.visitNode(node.op); | ||
this.visitNode(node.rhs); | ||
this.visitNode(node.right); | ||
} | ||
visitAnd(node) { | ||
this.visitNode(node.lhs); | ||
this.visitNode(node.rhs); | ||
this.visitNode(node.left); | ||
this.visitNode(node.right); | ||
} | ||
visitOr(node) { | ||
this.visitNode(node.lhs); | ||
this.visitNode(node.rhs); | ||
this.visitNode(node.left); | ||
this.visitNode(node.right); | ||
} | ||
@@ -103,2 +123,75 @@ visitValueList(node) { | ||
} | ||
visitWhere(node) { | ||
this.visitNode(node.where); | ||
} | ||
visitInsertQuery(node) { | ||
this.visitNode(node.into); | ||
if (node.columns) { | ||
node.columns.forEach(this.visitNode); | ||
} | ||
if (node.values) { | ||
node.values.forEach(this.visitNode); | ||
} | ||
if (node.returning) { | ||
this.visitNode(node.returning); | ||
} | ||
} | ||
visitDeleteQuery(node) { | ||
this.visitNode(node.from); | ||
if (node.joins) { | ||
node.joins.forEach(this.visitNode); | ||
} | ||
if (node.where) { | ||
this.visitNode(node.where); | ||
} | ||
if (node.returning) { | ||
this.visitNode(node.returning); | ||
} | ||
} | ||
visitReturning(node) { | ||
node.selections.forEach(this.visitNode); | ||
} | ||
visitCreateTable(node) { | ||
this.visitNode(node.table); | ||
node.columns.forEach(this.visitNode); | ||
} | ||
visitColumnDefinition(node) { | ||
this.visitNode(node.column); | ||
this.visitNode(node.dataType); | ||
} | ||
visitDropTable(node) { | ||
this.visitNode(node.table); | ||
} | ||
visitOrderBy(node) { | ||
node.items.forEach(this.visitNode); | ||
} | ||
visitOrderByItem(node) { | ||
this.visitNode(node.orderBy); | ||
} | ||
visitGroupBy(node) { | ||
node.items.forEach(this.visitNode); | ||
} | ||
visitGroupByItem(node) { | ||
this.visitNode(node.groupBy); | ||
} | ||
visitUpdateQuery(node) { | ||
this.visitNode(node.table); | ||
if (node.updates) { | ||
node.updates.forEach(this.visitNode); | ||
} | ||
if (node.joins) { | ||
node.joins.forEach(this.visitNode); | ||
} | ||
if (node.where) { | ||
this.visitNode(node.where); | ||
} | ||
if (node.returning) { | ||
this.visitNode(node.returning); | ||
} | ||
} | ||
visitColumnUpdate(node) { | ||
this.visitNode(node.column); | ||
this.visitNode(node.value); | ||
} | ||
visitDataType(node) { } | ||
visitSelectAll(_) { } | ||
@@ -105,0 +198,0 @@ visitIdentifier(_) { } |
@@ -1,4 +0,4 @@ | ||
export declare type OperationNodeKind = 'IdentifierNode' | 'QueryNode' | 'RawNode' | 'SelectNode' | 'SelectionNode' | 'ReferenceNode' | 'ColumnNode' | 'TableNode' | 'AliasNode' | 'FromNode' | 'SelectAllNode' | 'FilterNode' | 'AndNode' | 'OrNode' | 'ParensNode' | 'ValueNode' | 'ValueListNode' | 'PrimitiveValueListNode' | 'JoinNode' | 'OperatorNode'; | ||
export declare type OperationNodeKind = 'IdentifierNode' | 'RawNode' | 'SelectQueryNode' | 'SelectionNode' | 'ReferenceNode' | 'ColumnNode' | 'TableNode' | 'AliasNode' | 'FromNode' | 'SelectAllNode' | 'FilterNode' | 'AndNode' | 'OrNode' | 'ParensNode' | 'ValueNode' | 'ValueListNode' | 'PrimitiveValueListNode' | 'JoinNode' | 'OperatorNode' | 'WhereNode' | 'InsertQueryNode' | 'DeleteQueryNode' | 'ReturningNode' | 'CreateTableNode' | 'ColumnDefinitionNode' | 'DropTableNode' | 'DataTypeNode' | 'OrderByNode' | 'OrderByItemNode' | 'GroupByNode' | 'GroupByItemNode' | 'UpdateQueryNode' | 'ColumnUpdateNode'; | ||
export interface OperationNode { | ||
readonly kind: OperationNodeKind; | ||
} |
import { OperationNode } from './operation-node'; | ||
export interface OperatorNode extends OperationNode { | ||
kind: 'OperatorNode'; | ||
operator: string; | ||
readonly kind: 'OperatorNode'; | ||
readonly operator: string; | ||
} | ||
export declare function isOperatorNode(node: OperationNode): node is OperatorNode; | ||
export declare function createOperatorNode(operator: string): OperatorNode; |
@@ -6,7 +6,7 @@ import { AndNodeChildNode } from './and-node'; | ||
readonly kind: 'OrNode'; | ||
readonly lhs: OrNodeChildNode; | ||
readonly rhs: OrNodeChildNode; | ||
readonly left: OrNodeChildNode; | ||
readonly right: OrNodeChildNode; | ||
} | ||
export declare function isOrNode(node: OperationNode): node is OrNode; | ||
export declare function createOrNode(lhs: OrNodeChildNode, rhs: OrNodeChildNode): OrNode; | ||
export declare function createOrNode(left: OrNodeChildNode, right: OrNodeChildNode): OrNode; | ||
export {}; |
@@ -9,9 +9,9 @@ "use strict"; | ||
exports.isOrNode = isOrNode; | ||
function createOrNode(lhs, rhs) { | ||
function createOrNode(left, right) { | ||
return object_utils_1.freeze({ | ||
kind: 'OrNode', | ||
lhs, | ||
rhs, | ||
left, | ||
right, | ||
}); | ||
} | ||
exports.createOrNode = createOrNode; |
import { OperationNode } from './operation-node'; | ||
import { QueryNode } from './query-node'; | ||
import { RawNode } from './raw-node'; | ||
import { ReferenceNode } from './reference-node'; | ||
import { SelectQueryNode } from './select-query-node'; | ||
import { ValueNode } from './value-node'; | ||
export declare type ListNodeItem = ValueNode | ReferenceNode | QueryNode | RawNode; | ||
export declare type ListNodeItem = ValueNode | ReferenceNode | SelectQueryNode | RawNode; | ||
export interface ValueListNode extends OperationNode { | ||
@@ -8,0 +8,0 @@ readonly kind: 'ValueListNode'; |
import { JoinNode } from '../operation-node/join-node'; | ||
import { OperationNodeSource } from '../operation-node/operation-node-source'; | ||
import { RawBuilder } from '../raw-builder/raw-builder'; | ||
import { TableArg, FromQueryBuilder } from './methods/from-method'; | ||
import { FilterReferenceArg, FilterOperatorArg } from './methods/filter-method'; | ||
import { TableExpression, QueryBuilderWithTable } from '../parser/table-parser'; | ||
import { FilterOperatorArg } from '../parser/filter-parser'; | ||
import { ReferenceExpression } from '../parser/reference-parser'; | ||
export declare class JoinBuilder<DB, TB extends keyof DB, O = {}> implements OperationNodeSource { | ||
@@ -16,12 +17,12 @@ #private; | ||
*/ | ||
subQuery<F extends TableArg<DB, TB, O>>(from: F[]): FromQueryBuilder<DB, TB, O, F>; | ||
subQuery<F extends TableExpression<DB, TB>>(from: F[]): QueryBuilderWithTable<DB, TB, O, F>; | ||
/** | ||
* | ||
*/ | ||
subQuery<F extends TableArg<DB, TB, O>>(from: F): FromQueryBuilder<DB, TB, O, F>; | ||
subQuery<F extends TableExpression<DB, TB>>(from: F): QueryBuilderWithTable<DB, TB, O, F>; | ||
/** | ||
* | ||
*/ | ||
on(lhs: FilterReferenceArg<DB, TB, O>, op: FilterOperatorArg, rhs: FilterReferenceArg<DB, TB, O>): JoinBuilder<DB, TB, O>; | ||
onRef(lhs: ReferenceExpression<DB, TB>, op: FilterOperatorArg, rhs: ReferenceExpression<DB, TB>): JoinBuilder<DB, TB, O>; | ||
toOperationNode(): JoinNode; | ||
} |
@@ -5,7 +5,7 @@ "use strict"; | ||
const join_node_1 = require("../operation-node/join-node"); | ||
const query_node_1 = require("../operation-node/query-node"); | ||
const raw_builder_1 = require("../raw-builder/raw-builder"); | ||
const from_method_1 = require("./methods/from-method"); | ||
const filter_method_1 = require("./methods/filter-method"); | ||
const table_parser_1 = require("../parser/table-parser"); | ||
const filter_parser_1 = require("../parser/filter-parser"); | ||
const query_builder_1 = require("./query-builder"); | ||
const select_query_node_1 = require("../operation-node/select-query-node"); | ||
class JoinBuilder { | ||
@@ -23,7 +23,4 @@ constructor(joinNode) { | ||
subQuery(table) { | ||
const query = new query_builder_1.QueryBuilder({ | ||
queryNode: query_node_1.createQueryNode(), | ||
}); | ||
return new query_builder_1.QueryBuilder({ | ||
queryNode: query_node_1.cloneQueryNodeWithFroms(query.toOperationNode(), from_method_1.parseFromArgs(query, table)), | ||
queryNode: select_query_node_1.createSelectQueryNodeWithFromItems(table_parser_1.parseTableExpressionOrList(table)), | ||
}); | ||
@@ -34,7 +31,4 @@ } | ||
*/ | ||
on(lhs, op, rhs) { | ||
const query = new query_builder_1.QueryBuilder({ | ||
queryNode: query_node_1.createQueryNode(), | ||
}); | ||
return new JoinBuilder(join_node_1.cloneJoinNodeWithOn(this.#joinNode, 'and', filter_method_1.parseFilterReferenceArgs(query, lhs, op, rhs))); | ||
onRef(lhs, op, rhs) { | ||
return new JoinBuilder(join_node_1.cloneJoinNodeWithOn(this.#joinNode, 'and', filter_parser_1.parseReferenceFilterArgs(lhs, op, rhs))); | ||
} | ||
@@ -41,0 +35,0 @@ toOperationNode() { |
@@ -5,8 +5,15 @@ import { AliasNode } from '../operation-node/alias-node'; | ||
import { QueryCompiler } from '../query-compiler/query-compiler'; | ||
import { JoinCallbackArg, JoinReferenceArg } from './methods/join-method'; | ||
import { QueryNode } from '../operation-node/query-node'; | ||
import { TableArg, FromQueryBuilder } from './methods/from-method'; | ||
import { SelectArg, SelectQueryBuilder, SelectAllQueryBuiler } from './methods/select-method'; | ||
import { FilterReferenceArg, FilterValueArg, ExistsFilterArg, FilterOperatorArg } from './methods/filter-method'; | ||
import { JoinCallbackArg, JoinReferenceArg } from '../parser/join-parser'; | ||
import { TableExpression, QueryBuilderWithTable } from '../parser/table-parser'; | ||
import { SelectExpression, QueryBuilderWithSelection, SelectAllQueryBuilder } from '../parser/select-parser'; | ||
import { ExistsFilterArg, FilterOperatorArg } from '../parser/filter-parser'; | ||
import { ConnectionProvider } from '../driver/connection-provider'; | ||
import { QueryBuilderWithReturning } from '../parser/returning-parser'; | ||
import { ReferenceExpression } from '../parser/reference-parser'; | ||
import { ValueExpression, ValueExpressionOrList } from '../parser/value-parser'; | ||
import { OrderByDirection } from '../operation-node/order-by-item-node'; | ||
import { QueryNode } from '../operation-node/query-node-utils'; | ||
import { DeleteResultTypeTag, InsertResultTypeTag, UpdateResultTypeTag } from './type-utils'; | ||
import { OrderByExpression } from '../parser/order-by-parser'; | ||
import { MutationObject } from '../parser/mutation-parser'; | ||
/** | ||
@@ -42,3 +49,3 @@ * The main query builder class. | ||
* ```ts | ||
* const result = await db.query('pet') | ||
* const result = await db.selectFrom('pet') | ||
* .select([ | ||
@@ -72,8 +79,9 @@ * 'pet.name', | ||
*/ | ||
subQuery<F extends TableArg<DB, TB, O>>(from: F[]): FromQueryBuilder<DB, TB, O, F>; | ||
subQuery<F extends TableArg<DB, TB, O>>(from: F): FromQueryBuilder<DB, TB, O, F>; | ||
subQuery<F extends TableExpression<DB, TB>>(from: F[]): QueryBuilderWithTable<DB, TB, O, F>; | ||
subQuery<F extends TableExpression<DB, TB>>(from: F): QueryBuilderWithTable<DB, TB, O, F>; | ||
/** | ||
* Adds a `where` clause to the query. | ||
* | ||
* Also see {@link QueryBuilder.whereExists | whereExists} and {@link QueryBuilder.whereRef | whereRef} | ||
* Also see {@link QueryBuilder.whereExists | whereExists}, {@link QueryBuilder.whereRef | whereRef} | ||
* and {@link QueryBuilder.whereRef | orWhere}. | ||
* | ||
@@ -84,3 +92,3 @@ * @example | ||
* ```ts | ||
* db.query('person') | ||
* db.selectFrom('person') | ||
* .where('id', '=', 100) | ||
@@ -101,3 +109,3 @@ * .selectAll() | ||
* ```ts | ||
* db.query('person') | ||
* db.selectFrom('person') | ||
* .where('id', '>', 100) | ||
@@ -114,7 +122,8 @@ * .selectAll() | ||
* @example | ||
* A `where in` query. The first argument can contain | ||
* the table name, but it's not mandatory. | ||
* A `where in` query an be built by using the `in` operator and an array | ||
* of values. The values in the array can also be subqueries or raw | ||
* instances. | ||
* | ||
* ```ts | ||
* db.query('person') | ||
* db.selectFrom('person') | ||
* .where('person.id', 'in', [100, 200, 300]) | ||
@@ -131,7 +140,9 @@ * .selectAll() | ||
* @example | ||
* Both the first and third argument can also be a subquery. | ||
* A subquery is defined by passing a function: | ||
* Both the first and third argument can also be subqueries. | ||
* A subquery is defined by passing a function and calling | ||
* the `subQuery` method of the object passed into the | ||
* function: | ||
* | ||
* ```ts | ||
* db.query('person') | ||
* db.selectFrom('person') | ||
* .where( | ||
@@ -164,3 +175,3 @@ * (qb) => qb.subQuery('pet') | ||
* ```ts | ||
* db.query('person') | ||
* db.selectFrom('person') | ||
* .where( | ||
@@ -187,3 +198,3 @@ * db.raw('coalesce(first_name, last_name)'), | ||
* ```ts | ||
* db.query('person') | ||
* db.selectFrom('person') | ||
* .selectAll() | ||
@@ -201,12 +212,78 @@ * .where((qb) => qb | ||
* ``` | ||
* | ||
* @example | ||
* In all examples above the columns were known at compile time | ||
* (except for the `raw` expressions). By default kysely only allows | ||
* you to refer to columns that exist in the database **and** can be | ||
* referred to in the current query and context. | ||
* | ||
* Sometimes you may want to refer to columns that come from the user | ||
* input and thus are not available at compile time. | ||
* | ||
* You have two options, `db.raw` or `db.dynamic`. The example below | ||
* uses both: | ||
* | ||
* ```ts | ||
* const { ref } = db.dynamic | ||
* | ||
* db.selectFrom('person') | ||
* .selectAll() | ||
* .where(ref(columnFromUserInput), '=', 1) | ||
* .orWhere(db.raw('??', [columnFromUserInput]), '=', 2) | ||
* ``` | ||
*/ | ||
where(lhs: FilterReferenceArg<DB, TB, O>, op: FilterOperatorArg, rhs: FilterValueArg<DB, TB, O>): QueryBuilder<DB, TB, O>; | ||
where(lhs: ReferenceExpression<DB, TB>, op: FilterOperatorArg, rhs: ValueExpressionOrList<DB, TB>): QueryBuilder<DB, TB, O>; | ||
where(grouper: (qb: QueryBuilder<DB, TB, O>) => QueryBuilder<DB, TB, O>): QueryBuilder<DB, TB, O>; | ||
/** | ||
* Adds a `where` clause where both sides of the operator are references | ||
* to columns. | ||
* | ||
* The normal `where` method treats the right hand side argument as a | ||
* value by default. `whereRef` treats it as a column reference. This method is | ||
* expecially useful with joins and correclated subqueries. | ||
* | ||
* @example | ||
* Usage with a join: | ||
* | ||
* ```ts | ||
* db.selectFrom(['person', 'pet']) | ||
* .selectAll() | ||
* .whereRef('person.first_name', '=', 'pet.name') | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select * from "person", "pet" where "person"."first_name" = "pet"."name" | ||
* ``` | ||
* | ||
* @example | ||
* Usage in a subquery: | ||
* | ||
* ```ts | ||
* db.selectFrom('person) | ||
* .selectAll('person') | ||
* .select((qb) => qb | ||
* .subQuery('pet') | ||
* .select('name') | ||
* .whereRef('pet.owner_id', '=', 'person.id') | ||
* .limit(1) | ||
* .as('pet_name') | ||
* ) | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select "person".*, ( | ||
* select "name" | ||
* from "pet" | ||
* where "pet"."owner_id" = "person"."id" | ||
* ) as pet_name | ||
* from "person"` | ||
*/ | ||
whereRef(lhs: FilterReferenceArg<DB, TB, O>, op: FilterOperatorArg, rhs: FilterReferenceArg<DB, TB, O>): QueryBuilder<DB, TB, O>; | ||
whereRef(lhs: ReferenceExpression<DB, TB>, op: FilterOperatorArg, rhs: ReferenceExpression<DB, TB>): QueryBuilder<DB, TB, O>; | ||
/** | ||
* Adds an `or where` clause to the query. Otherwise works just like | ||
* {@link QueryBuilder.where}. | ||
* {@link QueryBuilder.where | where}. | ||
* | ||
@@ -219,3 +296,3 @@ * It's often necessary to wrap `or where` clauses in parentheses to control | ||
* ```ts | ||
* db.query('person') | ||
* db.selectFrom('person') | ||
* .selectAll() | ||
@@ -236,3 +313,3 @@ * .where('id', '=', 1) | ||
* ```ts | ||
* db.query('person') | ||
* db.selectFrom('person') | ||
* .selectAll() | ||
@@ -256,3 +333,3 @@ * .where((qb) => qb | ||
* ```ts | ||
* db.query('person') | ||
* db.selectFrom('person') | ||
* .selectAll() | ||
@@ -271,40 +348,274 @@ * .where((qb) => qb | ||
*/ | ||
orWhere(lhs: FilterReferenceArg<DB, TB, O>, op: FilterOperatorArg, rhs: FilterValueArg<DB, TB, O>): QueryBuilder<DB, TB, O>; | ||
orWhere(lhs: ReferenceExpression<DB, TB>, op: FilterOperatorArg, rhs: ValueExpression<DB, TB>): QueryBuilder<DB, TB, O>; | ||
orWhere(grouper: (qb: QueryBuilder<DB, TB, O>) => QueryBuilder<DB, TB, O>): QueryBuilder<DB, TB, O>; | ||
/** | ||
* Adds an `or where` clause to the query. Otherwise works just like | ||
* {@link QueryBuilder.whereRef | whereRef}. | ||
* | ||
* Also see {@link QueryBuilder.orWhere | orWhere} and {@link QueryBuilder.where | where}. | ||
*/ | ||
orWhereRef(lhs: FilterReferenceArg<DB, TB, O>, op: FilterOperatorArg, rhs: FilterReferenceArg<DB, TB, O>): QueryBuilder<DB, TB, O>; | ||
orWhereRef(lhs: ReferenceExpression<DB, TB>, op: FilterOperatorArg, rhs: ReferenceExpression<DB, TB>): QueryBuilder<DB, TB, O>; | ||
/** | ||
* Adds a `where exists` clause to the query. | ||
* | ||
*/ | ||
whereExists(arg: ExistsFilterArg<DB, TB, O>): QueryBuilder<DB, TB, O>; | ||
/** | ||
* You can either use a subquery or a raw instance. | ||
* | ||
*/ | ||
whereNotExists(arg: ExistsFilterArg<DB, TB, O>): QueryBuilder<DB, TB, O>; | ||
/** | ||
* @example | ||
* The query below selets all persons that own a pet named Catto: | ||
* | ||
* ```ts | ||
* db.selectFrom('person') | ||
* .selectAll() | ||
* .whereExists((qb) => qb | ||
* .subQuery('pet') | ||
* .select('pet.id') | ||
* .whereRef('person.id', '=', 'pet.owner_id') | ||
* .where('pet.name', '=', 'Catto') | ||
* ) | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select * from "person" | ||
* where exists ( | ||
* select "pet"."id" | ||
* from "pet" | ||
* where "person"."id" = "pet"."owner_id" | ||
* and "pet"."name" = $1 | ||
* ) | ||
* ``` | ||
* | ||
* @example | ||
* The same query as in the previous example but with using raw: | ||
* | ||
* ```ts | ||
* db.selectFrom('person') | ||
* .selectAll() | ||
* .whereExists( | ||
* db.raw( | ||
* '(select pet.id from pet where person.id = pet.owner_id and pet.name = ?)', | ||
* ['Catto'] | ||
* ) | ||
* ) | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select * from "person" | ||
* where exists ( | ||
* select pet.id | ||
* from pet | ||
* where person.id = pet.owner_id | ||
* and pet.name = $1 | ||
* ) | ||
* ``` | ||
*/ | ||
orWhereExists(arg: ExistsFilterArg<DB, TB, O>): QueryBuilder<DB, TB, O>; | ||
whereExists(arg: ExistsFilterArg<DB, TB>): QueryBuilder<DB, TB, O>; | ||
/** | ||
* | ||
* Just like {@link QueryBuilder.whereExists | whereExists} but creates a `not exists` clause. | ||
*/ | ||
orWhereNotExists(arg: ExistsFilterArg<DB, TB, O>): QueryBuilder<DB, TB, O>; | ||
whereNotExists(arg: ExistsFilterArg<DB, TB>): QueryBuilder<DB, TB, O>; | ||
/** | ||
* | ||
* Just like {@link QueryBuilder.whereExists | whereExists} but creates a `or exists` clause. | ||
*/ | ||
select<S extends SelectArg<DB, TB, O>>(selections: S[]): SelectQueryBuilder<DB, TB, O, S>; | ||
orWhereExists(arg: ExistsFilterArg<DB, TB>): QueryBuilder<DB, TB, O>; | ||
/** | ||
* | ||
* Just like {@link QueryBuilder.whereExists | whereExists} but creates a `or not exists` clause. | ||
*/ | ||
select<S extends SelectArg<DB, TB, O>>(selection: S): SelectQueryBuilder<DB, TB, O, S>; | ||
orWhereNotExists(arg: ExistsFilterArg<DB, TB>): QueryBuilder<DB, TB, O>; | ||
/** | ||
* Adds a select clause to the query. | ||
* | ||
* When a column (or any expression) is selected, Kysely also adds it to the return | ||
* type of the query. Kysely is smart enough to parse the field names and types even | ||
* from aliased columns, subqueries, raw expressions etc. | ||
* | ||
* Kysely only allows you to select columns and expressions that exist and would | ||
* produce valid SQL. However, Kysely is not perfect and there may be cases where | ||
* the type inference doesn't work and you need to override it. You can always | ||
* use the {@link Kysely.dynamic | dynamic} object and {@link Kysely.raw | raw} | ||
* to override the types. | ||
* | ||
* Select calls are additive. Calling `select('id').select('first_name')` is the | ||
* same as calling `select(['id', 'first_name']). | ||
* | ||
* To select all columns of the query or specific tables see the | ||
* {@link QueryBuilder.selectAll | selectAll} method. | ||
* | ||
* @example | ||
* Select a single column: | ||
* | ||
* ```ts | ||
* const [person] = await db.selectFrom('person') | ||
* .select('id') | ||
* .execute() | ||
* | ||
* person.id | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select "id" from "person" | ||
* ``` | ||
* | ||
* @example | ||
* Select a single column and specify a table: | ||
* | ||
* ```ts | ||
* const [person] = await db.selectFrom(['person', 'pet']) | ||
* .select('person.id') | ||
* .execute() | ||
* | ||
* person.id | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select "person"."id" from "person", "pet" | ||
* ``` | ||
* | ||
* @example | ||
* Select multiple columns: | ||
* | ||
* ```ts | ||
* const [person] = await db.selectFrom('person') | ||
* .select(['person.id', 'first_name']) | ||
* .execute() | ||
* | ||
* person.id | ||
* person.first_name | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select "person"."id", "first_name" from "person" | ||
* ``` | ||
* | ||
* @example | ||
* Giving an alias for a selection: | ||
* | ||
* ```ts | ||
* const [person] = await db.selectFrom('person') | ||
* .select([ | ||
* 'person.first_name as fn', | ||
* 'person.last_name as ln' | ||
* ]) | ||
* .execute() | ||
* | ||
* person.fn | ||
* person.ln | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select | ||
* "person"."first_name" as "fn", | ||
* "person"."last_name" as "ln" | ||
* from "person" | ||
* ``` | ||
* | ||
* @example | ||
* You can also select subqueries and raw expressions. Note that you | ||
* always need to give a name for the selections using the `as` | ||
* method: | ||
* | ||
* ```ts | ||
* const [person] = await db.selectFrom('person') | ||
* .select([ | ||
* (qb) => qb | ||
* .subQuery('pet') | ||
* .whereRef('person.id', '=', 'pet.owner_id') | ||
* .select('pet.name') | ||
* .as('pet_name') | ||
* db.raw<string>("concat(first_name, ' ', last_name)").as('full_name') | ||
* ]) | ||
* .execute() | ||
* | ||
* person.pet_name | ||
* person.full_name | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select | ||
* ( | ||
* select "pet"."name" | ||
* from "pet" | ||
* where "person"."id" = "pet"."owner_id" | ||
* ) as pet_name, | ||
* concat(first_name, ' ', last_name) as full_name | ||
* from "person" | ||
* ``` | ||
* | ||
* In case you use `raw` you need to specify the type of the expression | ||
* (in this example `string`). | ||
* | ||
* @example | ||
* All the examples above assume you know the column names at compile time. | ||
* While it's better to build your code in that way (that way you also know | ||
* the types) sometimes it's not possible or you just prefer to write more | ||
* dynamic code. | ||
* | ||
* In this example, we use the `dynamic` object's methods to add selections | ||
* dynamically: | ||
* | ||
* ```ts | ||
* const { ref } = db.dynamic | ||
* | ||
* // Some column name provided by the user. Value not know compile-time. | ||
* const columnFromUserInput = req.params.select; | ||
* | ||
* // A type that lists all possible values `columnFromUserInput` can have. | ||
* type PossibleColumns = 'last_name' | 'first_name' | 'birth_date' | ||
* | ||
* const [person] = db.selectFrom('person') | ||
* .select([ | ||
* ref<PossibleColumns>(columnFromUserInput) | ||
* 'id' | ||
* ]) | ||
* | ||
* // The resulting type contains all `PossibleColumns` as optional fields | ||
* // because we cannot know which field was actually selected before | ||
* // running the code. | ||
* const lastName: string | undefined = person.last_name | ||
* const firstName: string | undefined = person.first_name | ||
* const birthDate: string | undefined = person.birth_date | ||
* | ||
* // The result type also contains the compile time selection `id`. | ||
* person.id | ||
* ``` | ||
*/ | ||
distinctOn<S extends SelectArg<DB, TB, O>>(selections: S[]): QueryBuilder<DB, TB, O>; | ||
select<S extends SelectExpression<DB, TB>>(selections: S[]): QueryBuilderWithSelection<DB, TB, O, S>; | ||
select<S extends SelectExpression<DB, TB>>(selection: S): QueryBuilderWithSelection<DB, TB, O, S>; | ||
/** | ||
* Adds `distinct on` selections to the select clause. | ||
* | ||
* @example | ||
* ```ts | ||
* await db.selectFrom('person') | ||
* .selectAll('person') | ||
* .distinctOn('person.id') | ||
* .innerJoin('pet', 'pet.owner_id', 'person.id') | ||
* .where('pet.name', '=', 'Doggo') | ||
* .execute() | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select distinct on ("person".id") "person".* | ||
* from "person" | ||
* inner join "pet" on "pet"."owner_id" = "person"."id" | ||
* where "pet"."name" = $1 | ||
* ``` | ||
*/ | ||
distinctOn<S extends SelectArg<DB, TB, O>>(selection: S): QueryBuilder<DB, TB, O>; | ||
distinctOn<S extends SelectExpression<DB, TB>>(selections: S[]): QueryBuilder<DB, TB, O>; | ||
distinctOn<S extends SelectExpression<DB, TB>>(selection: S): QueryBuilder<DB, TB, O>; | ||
/** | ||
@@ -315,50 +626,635 @@ * | ||
/** | ||
* | ||
* Adds the `for update` option to a select query on supported databases. | ||
*/ | ||
forUpdate(): QueryBuilder<DB, TB, O>; | ||
/** | ||
* | ||
* Adds the `for share` option to a select query on supported databases. | ||
*/ | ||
forShare(): QueryBuilder<DB, TB, O>; | ||
/** | ||
* | ||
* Adds the `for key share` option to a select query on supported databases. | ||
*/ | ||
forKeyShare(): QueryBuilder<DB, TB, O>; | ||
/** | ||
* | ||
* Adds the `for no key update` option to a select query on supported databases. | ||
*/ | ||
forNoKeyUpdate(): QueryBuilder<DB, TB, O>; | ||
/** | ||
* | ||
* Adds the `skip locked` option to a select query on supported databases. | ||
*/ | ||
skipLocked(): QueryBuilder<DB, TB, O>; | ||
/** | ||
* | ||
* Adds the `nowait` option to a select query on supported databases. | ||
*/ | ||
noWait(): QueryBuilder<DB, TB, O>; | ||
/** | ||
* Adds a `select *` or `select table.*` clause to the query. | ||
* | ||
* @example | ||
* ```ts | ||
* await db.selectFrom('person') | ||
* .selectAll() | ||
* .execute() | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select * from "person" | ||
* ``` | ||
* | ||
* @example | ||
* ```ts | ||
* await db.selectFrom('person') | ||
* .selectAll('person') | ||
* .execute() | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select "person".* from "person" | ||
* ``` | ||
* | ||
* @example | ||
* ```ts | ||
* await db.selectFrom(['person', 'pet']) | ||
* .selectAll(['person', 'pet']) | ||
* .execute() | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select "person".*, "pet".* from "person", "pet" | ||
* ``` | ||
*/ | ||
selectAll<T extends TB>(table: T[]): SelectAllQueryBuiler<DB, TB, O, T>; | ||
selectAll<T extends TB>(table: T[]): SelectAllQueryBuilder<DB, TB, O, T>; | ||
selectAll<T extends TB>(table: T): SelectAllQueryBuilder<DB, TB, O, T>; | ||
selectAll<T extends TB>(): SelectAllQueryBuilder<DB, TB, O, T>; | ||
/** | ||
* Joins another table to the query using an inner join. | ||
* | ||
* @example | ||
* Simple usage by providing a table name and two columns to join: | ||
* | ||
* ```ts | ||
* await db.selectFrom('person') | ||
* .selectAll() | ||
* .innerJoin('pet', 'pet.owner_id', 'person.id') | ||
* .execute() | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select * | ||
* from "person" | ||
* inner join "pet" | ||
* on "pet"."owner_id" = "person"."id" | ||
* ``` | ||
* | ||
* @example | ||
* You can give an alias for the joined table like this: | ||
* | ||
* ```ts | ||
* await db.selectFrom('person') | ||
* .selectAll() | ||
* .innerJoin('pet as p', 'p.owner_id', 'person.id') | ||
* .where('p.name', '=', 'Doggo') | ||
* .execute() | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select * | ||
* from "person" | ||
* inner join "pet" as "p" | ||
* on "p"."owner_id" = "person"."id" | ||
* where "p".name" = $1 | ||
* ``` | ||
* | ||
* @example | ||
* You can provide a function as the second argument to get a join | ||
* builder for creating more complex joins. The join builder has a | ||
* bunch of `on*` methods for building the `on` clause of the join. | ||
* There's basically an equivalent for every `where` method | ||
* (`on`, `onRef`, `onExists` etc.). You can do all the same things | ||
* with the `on` method that you can with the corresponding `where` | ||
* method. See the `where` method documentation for more examples. | ||
* | ||
* ```ts | ||
* await db.selectFrom('person') | ||
* .selectAll() | ||
* .innerJoin( | ||
* 'pet', | ||
* (join) => join | ||
* .onRef('pet.owner_id', '=', 'person.id') | ||
* .on('pet.name', '=', 'Doggo') | ||
* ) | ||
* .execute() | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select * | ||
* from "person" | ||
* inner join "pet" | ||
* on "pet"."owner_id" = "person"."id" | ||
* and "pet"."name" = $1 | ||
* ``` | ||
* | ||
* @example | ||
* You can join a subquery by providing a function as the first | ||
* argument: | ||
* | ||
* ```ts | ||
* await db.selectFrom('person') | ||
* .selectAll() | ||
* .innerJoin( | ||
* (qb) => qb.subQuery('pet') | ||
* .select(['owner_id', 'name']) | ||
* .where('name', '=', 'Doggo') | ||
* .as('doggos'), | ||
* 'doggos.owner_id', | ||
* 'person.id', | ||
* ) | ||
* .execute() | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select * | ||
* from "person" | ||
* inner join ( | ||
* select "owner_id", "name" | ||
* from "pet" | ||
* where "name" = $1 | ||
* ) as doggos | ||
* on "doggos"."owner_id" = "person"."id" | ||
* ``` | ||
*/ | ||
selectAll<T extends TB>(table: T): SelectAllQueryBuiler<DB, TB, O, T>; | ||
innerJoin<TE extends TableExpression<DB, TB>, K1 extends JoinReferenceArg<DB, TB, TE>, K2 extends JoinReferenceArg<DB, TB, TE>>(table: TE, k1: K1, k2: K2): QueryBuilderWithTable<DB, TB, O, TE>; | ||
innerJoin<TE extends TableExpression<DB, TB>, FN extends JoinCallbackArg<DB, TB, TE>>(table: TE, callback: FN): QueryBuilderWithTable<DB, TB, O, TE>; | ||
/** | ||
* Just like {@link QueryBuilder.innerJoin | innerJoin} but adds a left join | ||
* instead of an inner join. | ||
*/ | ||
leftJoin<TE extends TableExpression<DB, TB>, K1 extends JoinReferenceArg<DB, TB, TE>, K2 extends JoinReferenceArg<DB, TB, TE>>(table: TE, k1: K1, k2: K2): QueryBuilderWithTable<DB, TB, O, TE>; | ||
leftJoin<TE extends TableExpression<DB, TB>, FN extends JoinCallbackArg<DB, TB, TE>>(table: TE, callback: FN): QueryBuilderWithTable<DB, TB, O, TE>; | ||
/** | ||
* Just like {@link QueryBuilder.innerJoin | innerJoin} but adds a right join | ||
* instead of an inner join. | ||
*/ | ||
rightJoin<TE extends TableExpression<DB, TB>, K1 extends JoinReferenceArg<DB, TB, TE>, K2 extends JoinReferenceArg<DB, TB, TE>>(table: TE, k1: K1, k2: K2): QueryBuilderWithTable<DB, TB, O, TE>; | ||
rightJoin<TE extends TableExpression<DB, TB>, FN extends JoinCallbackArg<DB, TB, TE>>(table: TE, callback: FN): QueryBuilderWithTable<DB, TB, O, TE>; | ||
/** | ||
* Just like {@link QueryBuilder.innerJoin | innerJoin} but adds a full join | ||
* instead of an inner join. | ||
*/ | ||
fullJoin<TE extends TableExpression<DB, TB>, K1 extends JoinReferenceArg<DB, TB, TE>, K2 extends JoinReferenceArg<DB, TB, TE>>(table: TE, k1: K1, k2: K2): QueryBuilderWithTable<DB, TB, O, TE>; | ||
fullJoin<TE extends TableExpression<DB, TB>, FN extends JoinCallbackArg<DB, TB, TE>>(table: TE, callback: FN): QueryBuilderWithTable<DB, TB, O, TE>; | ||
/** | ||
* Sets the values to insert for an `insertInto` query. | ||
* | ||
* This method takes an object whose keys are column names and values are | ||
* values to insert. In addition to the column's type, the values can be `raw` | ||
* instances or select queries. | ||
* | ||
* The return value is the primary key of the inserted row BUT on some databases | ||
* there is no return value by default. That's the reason for the `any` type of the | ||
* return value. On postgres you need to additionally call `returning` to get | ||
* something out of the query. | ||
* | ||
* @example | ||
* Insert a row into `person`: | ||
* ```ts | ||
* const maybeId = await db | ||
* .insertInto('person') | ||
* .values({ | ||
* first_name: 'Jennifer', | ||
* last_name: 'Aniston' | ||
* }) | ||
* .executeTakeFirst() | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* insert into "person" ("first_name", "last_name") values ($1, $2) | ||
* ``` | ||
* | ||
* @example | ||
* On dialects that support it (for example postgres) you can insert multiple | ||
* rows by providing an array. Note that the return value is once again very | ||
* dialect-specific. Some databases may only return the id of the *first* inserted | ||
* row and some return nothing at all unless you call `returning`. | ||
* | ||
* ```ts | ||
* const maybeId = await db | ||
* .insertInto('person') | ||
* .values([{ | ||
* first_name: 'Jennifer', | ||
* last_name: 'Aniston' | ||
* }, { | ||
* first_name: 'Arnold', | ||
* last_name: 'Schwarzenegger', | ||
* }]) | ||
* .executeTakeFirst() | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* insert into "person" ("first_name", "last_name") values (($1, $2), ($3, $4)) | ||
* ``` | ||
* | ||
* @example | ||
* On postgresql you need to chain `returning` to the query to get | ||
* the inserted row's columns (or any other expression) as the | ||
* return value: | ||
* | ||
* ```ts | ||
* const row = await db | ||
* .insertInto('person') | ||
* .values({ | ||
* first_name: 'Jennifer', | ||
* last_name: 'Aniston' | ||
* }) | ||
* .returning('id') | ||
* .executeTakeFirst() | ||
* | ||
* row.id | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* insert into "person" ("first_name", "last_name") values ($1, $2) returning "id" | ||
* ``` | ||
* | ||
* @example | ||
* In addition to primitives, the values can also be `raw` expressions or | ||
* select queries: | ||
* | ||
* ```ts | ||
* const maybeId = await db | ||
* .insertInto('person') | ||
* .values({ | ||
* first_name: 'Jennifer', | ||
* last_name: db.raw('? || ?', ['Ani', 'ston']), | ||
* age: db.selectFrom('person').select(raw('avg(age)')), | ||
* }) | ||
* .executeTakeFirst() | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* insert into "person" ("first_name", "last_name", "age") | ||
* values ($1, $2 || $3, (select avg(age) from "person")) | ||
* ``` | ||
*/ | ||
selectAll<T extends TB>(): SelectAllQueryBuiler<DB, TB, O, T>; | ||
values(row: MutationObject<DB, TB>): QueryBuilder<DB, TB, O>; | ||
values(row: MutationObject<DB, TB>[]): QueryBuilder<DB, TB, O>; | ||
/** | ||
* Sets the values to update for an `updateTable` query. | ||
* | ||
* This method takes an object whose keys are column names and values are | ||
* values to update. In addition to the column's type, the values can be `raw` | ||
* instances or select queries. | ||
* | ||
* The return value is the number of affected rows. You can use the | ||
* {@link QueryBuilder.returning | returning} method on supported databases | ||
* to get out the updated rows. | ||
* | ||
* @example | ||
* Update a row in `person` table: | ||
* | ||
* ```ts | ||
* const numAffectedRows = await db | ||
* .updateTable('person') | ||
* .set({ | ||
* first_name: 'Jennifer', | ||
* last_name: 'Aniston' | ||
* }) | ||
* .where('id', '=', 1) | ||
* .executeTakeFirst() | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* update "person" set "first_name" = $1, "last_name" = $2 where "id" = $3 | ||
* ``` | ||
* | ||
* @example | ||
* On postgresql you need to chain `returning` to the query to get | ||
* the updated rows' columns (or any other expression) as the | ||
* return value: | ||
* | ||
* ```ts | ||
* const row = await db | ||
* .updateTable('person') | ||
* .set({ | ||
* first_name: 'Jennifer', | ||
* last_name: 'Aniston' | ||
* }) | ||
* .where('id', '=', 1) | ||
* .returning('id') | ||
* .executeTakeFirst() | ||
* | ||
* row.id | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* update "person" set "first_name" = $1, "last_name" = $2 where "id" = $3 returning "id" | ||
* ``` | ||
* | ||
* @example | ||
* In addition to primitives, the values can also be `raw` expressions or | ||
* select queries: | ||
* | ||
* ```ts | ||
* const numAffectedRows = await db | ||
* .updateTable('person') | ||
* .set({ | ||
* first_name: 'Jennifer', | ||
* last_name: db.raw('? || ?', ['Ani', 'ston']), | ||
* age: db.selectFrom('person').select(raw('avg(age)')), | ||
* }) | ||
* .where('id', '=', 1) | ||
* .executeTakeFirst() | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* update "person" set | ||
* "first_name" = $1, | ||
* "last_name" = $2 || $3, | ||
* "age" = (select avg(age) from "person") | ||
* where "id" = $4 | ||
* ``` | ||
*/ | ||
innerJoin<F extends TableArg<DB, TB, O>, K1 extends JoinReferenceArg<DB, TB, F>, K2 extends JoinReferenceArg<DB, TB, F>>(table: F, k1: K1, k2: K2): FromQueryBuilder<DB, TB, O, F>; | ||
innerJoin<F extends TableArg<DB, TB, O>, FN extends JoinCallbackArg<DB, TB, F>>(table: F, callback: FN): FromQueryBuilder<DB, TB, O, F>; | ||
set(row: MutationObject<DB, TB>): QueryBuilder<DB, TB, O>; | ||
/** | ||
* Allows you to return data from modified rows. | ||
* | ||
* On supported databases like postgres, this method can be chained to | ||
* `insert`, `update` and `delete` queries to return data. | ||
* | ||
* Also see the {@link QueryBuilder.returningAll | returningAll} method. | ||
* | ||
* @example | ||
* Return one column: | ||
* | ||
* ```ts | ||
* const { id } = await db | ||
* .insertInto('person') | ||
* .values({ | ||
* first_name: 'Jennifer', | ||
* last_name: 'Aniston' | ||
* }) | ||
* .returning('id') | ||
* .executeTakeFirst() | ||
* ``` | ||
* | ||
* @example | ||
* Return multiple columns: | ||
* | ||
* ```ts | ||
* const { id, first_name } = await db | ||
* .insertInto('person') | ||
* .values({ | ||
* first_name: 'Jennifer', | ||
* last_name: 'Aniston' | ||
* }) | ||
* .returning(['id', 'last_name']) | ||
* .executeTakeFirst() | ||
* ``` | ||
* | ||
* @example | ||
* Return arbitrary expressions: | ||
* | ||
* ```ts | ||
* const { raw } = db | ||
* | ||
* const { id, full_name, first_pet_id } = await db | ||
* .insertInto('person') | ||
* .values({ | ||
* first_name: 'Jennifer', | ||
* last_name: 'Aniston' | ||
* }) | ||
* .returning([ | ||
* raw<string>(`concat(first_name, ' ', last_name)`).as('full_name'), | ||
* (qb) => qb.subQuery('pets').select('pet.id').limit(1).as('first_pet_id') | ||
* ]) | ||
* .executeTakeFirst() | ||
* ``` | ||
*/ | ||
returning<S extends SelectExpression<DB, TB>>(selections: S[]): QueryBuilderWithReturning<DB, TB, O, S>; | ||
returning<S extends SelectExpression<DB, TB>>(selection: S): QueryBuilderWithReturning<DB, TB, O, S>; | ||
/** | ||
* Adds a `returning *` to an insert/update/delete query on databases | ||
* that support `returning` such as postgres. | ||
*/ | ||
returningAll(): QueryBuilder<DB, TB, DB[TB]>; | ||
/** | ||
* Adds an `order by` clause to the query. | ||
* | ||
* `orderBy` calls are additive. To order by multiple columns, call `orderBy` | ||
* multiple times. | ||
* | ||
* The first argument is the expression to order by and the second is the | ||
* order (`asc` or `desc`). | ||
* | ||
* @example | ||
* ```ts | ||
* await db | ||
* .selectFrom('person') | ||
* .select('person.first_name as fn') | ||
* .orderBy('id') | ||
* .orderBy('fn', 'desc') | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select "person"."first_name" as "fn" | ||
* from "person" | ||
* order by "id" asc, "fn" desc | ||
* ``` | ||
* | ||
* @example | ||
* The order by expression can also be a `raw` expression or a subquery | ||
* in addition to column references: | ||
* | ||
* ```ts | ||
* await db | ||
* .selectFrom('person') | ||
* .selectAll() | ||
* .orderBy((qb) => qb.subQuery('pet') | ||
* .select('pet.name') | ||
* .whereRef('pet.owner_id', '=', 'person.id') | ||
* .limit(1) | ||
* ) | ||
* .orderBy( | ||
* db.raw('concat(first_name, last_name)') | ||
* ) | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select * | ||
* from "person" | ||
* order by | ||
* ( select "pet"."name" | ||
* from "pet" | ||
* where "pet"."owner_id" = "person"."id" | ||
* limit 1 | ||
* ) asc, | ||
* concat(first_name, last_name) asc | ||
* ``` | ||
* | ||
* @example | ||
* `dynamic.ref` can be used to refer to columns not known at | ||
* compile time: | ||
* | ||
* ```ts | ||
* async function someQuery(orderBy: string) { | ||
* const { ref } = db.dynamic | ||
* | ||
* return await db | ||
* .selectFrom('person') | ||
* .select('person.first_name as fn') | ||
* .orderBy(ref(orderBy)) | ||
* } | ||
* | ||
* someQuery('fn') | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select "person"."first_name" as "fn" | ||
* from "person" | ||
* order by "fn" asc | ||
* ``` | ||
*/ | ||
orderBy(orderBy: OrderByExpression<DB, TB, O>, direction?: OrderByDirection): QueryBuilder<DB, TB, O>; | ||
/** | ||
* Adds a `group by` clause to the query. | ||
* | ||
* @example | ||
* ```ts | ||
* await db | ||
* .selectFrom('person') | ||
* .select([ | ||
* 'first_name', | ||
* db.raw('max(id)').as('max_id') | ||
* ]) | ||
* .groupBy('first_name') | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select "first_name", max(id) | ||
* from "person" | ||
* group by "first_name" | ||
* ``` | ||
* | ||
* @example | ||
* `groupBy` also accepts an array: | ||
* | ||
* ```ts | ||
* const { raw } = db | ||
* | ||
* await db | ||
* .selectFrom('person') | ||
* .select([ | ||
* 'first_name', | ||
* 'last_name', | ||
* raw('max(id)').as('max_id') | ||
* ]) | ||
* .groupBy([ | ||
* 'first_name', | ||
* 'last_name' | ||
* ]) | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select "first_name", "last_name", max(id) | ||
* from "person" | ||
* group by "first_name", "last_name" | ||
* ``` | ||
* | ||
* @example | ||
* The group by expressions can also be subqueries or | ||
* raw expressions: | ||
* | ||
* ```ts | ||
* const { raw } = db | ||
* | ||
* await db | ||
* .selectFrom('person') | ||
* .select([ | ||
* 'first_name', | ||
* 'last_name', | ||
* raw('max(id)').as('max_id') | ||
* ]) | ||
* .groupBy([ | ||
* raw('concat(first_name, last_name)'), | ||
* (qb) => qb.subQuery('pet').select('id').limit(1) | ||
* ]) | ||
* ``` | ||
* | ||
* @example | ||
* `dynamic.ref` can be used to refer to columns not known at | ||
* compile time: | ||
* | ||
* ```ts | ||
* async function someQuery(groupBy: string) { | ||
* const { ref } = db.dynamic | ||
* | ||
* return await db | ||
* .selectFrom('person') | ||
* .select('first_name') | ||
* .groupBy(ref(groupBy)) | ||
* } | ||
* | ||
* someQuery('first_name') | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select "first_name" | ||
* from "person" | ||
* group by "first_name" | ||
* ``` | ||
*/ | ||
groupBy(orderBy: ReferenceExpression<DB, TB>[]): QueryBuilder<DB, TB, O>; | ||
groupBy(orderBy: ReferenceExpression<DB, TB>): QueryBuilder<DB, TB, O>; | ||
/** | ||
* | ||
*/ | ||
as<A extends string>(alias: A): AliasedQueryBuilder<DB, TB, O, A>; | ||
toOperationNode(): QueryNode; | ||
/** | ||
* Change the output type of the query. | ||
*/ | ||
castTo<T>(): QueryBuilder<DB, TB, T>; | ||
compile(): CompiledQuery; | ||
execute(): Promise<O[]>; | ||
execute(): Promise<ManyResultType<O>>; | ||
executeTakeFirst(): Promise<SingleResultType<O>>; | ||
} | ||
@@ -375,2 +1271,3 @@ export interface QueryBuilderArgs { | ||
#private; | ||
constructor(queryBuilder: QueryBuilder<DB, TB, O>, alias: A); | ||
/** | ||
@@ -386,3 +1283,6 @@ * @private | ||
toOperationNode(): AliasNode; | ||
constructor(queryBuilder: QueryBuilder<DB, TB, O>, alias: A); | ||
} | ||
export declare function createEmptySelectQuery<DB, TB extends keyof DB, O = {}>(): QueryBuilder<DB, TB, O>; | ||
declare type ManyResultType<O> = O extends InsertResultTypeTag ? (number | undefined)[] : O extends DeleteResultTypeTag ? number[] : O extends UpdateResultTypeTag ? number[] : O[]; | ||
declare type SingleResultType<O> = O extends InsertResultTypeTag ? number | undefined : O extends DeleteResultTypeTag ? number : O extends UpdateResultTypeTag ? number : O | undefined; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.AliasedQueryBuilder = exports.QueryBuilder = void 0; | ||
exports.createEmptySelectQuery = exports.AliasedQueryBuilder = exports.QueryBuilder = void 0; | ||
const alias_node_1 = require("../operation-node/alias-node"); | ||
const join_method_1 = require("./methods/join-method"); | ||
const query_node_1 = require("../operation-node/query-node"); | ||
const from_method_1 = require("./methods/from-method"); | ||
const select_method_1 = require("./methods/select-method"); | ||
const filter_method_1 = require("./methods/filter-method"); | ||
const join_parser_1 = require("../parser/join-parser"); | ||
const table_parser_1 = require("../parser/table-parser"); | ||
const select_parser_1 = require("../parser/select-parser"); | ||
const filter_parser_1 = require("../parser/filter-parser"); | ||
const insert_values_parser_1 = require("../parser/insert-values-parser"); | ||
const reference_parser_1 = require("../parser/reference-parser"); | ||
const order_by_item_node_1 = require("../operation-node/order-by-item-node"); | ||
const select_query_node_1 = require("../operation-node/select-query-node"); | ||
const insert_query_node_1 = require("../operation-node/insert-query-node"); | ||
const delete_query_node_1 = require("../operation-node/delete-query-node"); | ||
const query_node_utils_1 = require("../operation-node/query-node-utils"); | ||
const group_by_item_node_1 = require("../operation-node/group-by-item-node"); | ||
const update_query_node_1 = require("../operation-node/update-query-node"); | ||
const update_set_parser_1 = require("../parser/update-set-parser"); | ||
/** | ||
@@ -36,91 +45,203 @@ * The main query builder class. | ||
return new QueryBuilder({ | ||
queryNode: query_node_1.cloneQueryNodeWithFroms(query_node_1.createQueryNode(), from_method_1.parseFromArgs(this, table)), | ||
queryNode: select_query_node_1.createSelectQueryNodeWithFromItems(table_parser_1.parseTableExpressionOrList(table)), | ||
}); | ||
} | ||
where(...args) { | ||
ensureCanHaveWhereClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'and', filter_method_1.parseFilterArgs(this, args)), | ||
queryNode: query_node_utils_1.cloneQueryNodeWithWhere(this.#queryNode, 'and', filter_parser_1.parseFilterArgs(args)), | ||
}); | ||
} | ||
/** | ||
* Adds a `where` clause where both sides of the operator are references | ||
* to columns. | ||
* | ||
* The normal `where` method treats the right hand side argument as a | ||
* value by default. `whereRef` treats it as a column reference. This method is | ||
* expecially useful with joins and correclated subqueries. | ||
* | ||
* @example | ||
* Usage with a join: | ||
* | ||
* ```ts | ||
* db.selectFrom(['person', 'pet']) | ||
* .selectAll() | ||
* .whereRef('person.first_name', '=', 'pet.name') | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select * from "person", "pet" where "person"."first_name" = "pet"."name" | ||
* ``` | ||
* | ||
* @example | ||
* Usage in a subquery: | ||
* | ||
* ```ts | ||
* db.selectFrom('person) | ||
* .selectAll('person') | ||
* .select((qb) => qb | ||
* .subQuery('pet') | ||
* .select('name') | ||
* .whereRef('pet.owner_id', '=', 'person.id') | ||
* .limit(1) | ||
* .as('pet_name') | ||
* ) | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select "person".*, ( | ||
* select "name" | ||
* from "pet" | ||
* where "pet"."owner_id" = "person"."id" | ||
* ) as pet_name | ||
* from "person"` | ||
*/ | ||
whereRef(lhs, op, rhs) { | ||
ensureCanHaveWhereClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'and', filter_method_1.parseFilterReferenceArgs(this, lhs, op, rhs)), | ||
queryNode: query_node_utils_1.cloneQueryNodeWithWhere(this.#queryNode, 'and', filter_parser_1.parseReferenceFilterArgs(lhs, op, rhs)), | ||
}); | ||
} | ||
orWhere(...args) { | ||
ensureCanHaveWhereClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'or', filter_method_1.parseFilterArgs(this, args)), | ||
queryNode: query_node_utils_1.cloneQueryNodeWithWhere(this.#queryNode, 'or', filter_parser_1.parseFilterArgs(args)), | ||
}); | ||
} | ||
/** | ||
* Adds an `or where` clause to the query. Otherwise works just like | ||
* {@link QueryBuilder.whereRef | whereRef}. | ||
* | ||
* Also see {@link QueryBuilder.orWhere | orWhere} and {@link QueryBuilder.where | where}. | ||
*/ | ||
orWhereRef(lhs, op, rhs) { | ||
ensureCanHaveWhereClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'or', filter_method_1.parseFilterReferenceArgs(this, lhs, op, rhs)), | ||
queryNode: query_node_utils_1.cloneQueryNodeWithWhere(this.#queryNode, 'or', filter_parser_1.parseReferenceFilterArgs(lhs, op, rhs)), | ||
}); | ||
} | ||
/** | ||
* Adds a `where exists` clause to the query. | ||
* | ||
* You can either use a subquery or a raw instance. | ||
* | ||
* @example | ||
* The query below selets all persons that own a pet named Catto: | ||
* | ||
* ```ts | ||
* db.selectFrom('person') | ||
* .selectAll() | ||
* .whereExists((qb) => qb | ||
* .subQuery('pet') | ||
* .select('pet.id') | ||
* .whereRef('person.id', '=', 'pet.owner_id') | ||
* .where('pet.name', '=', 'Catto') | ||
* ) | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select * from "person" | ||
* where exists ( | ||
* select "pet"."id" | ||
* from "pet" | ||
* where "person"."id" = "pet"."owner_id" | ||
* and "pet"."name" = $1 | ||
* ) | ||
* ``` | ||
* | ||
* @example | ||
* The same query as in the previous example but with using raw: | ||
* | ||
* ```ts | ||
* db.selectFrom('person') | ||
* .selectAll() | ||
* .whereExists( | ||
* db.raw( | ||
* '(select pet.id from pet where person.id = pet.owner_id and pet.name = ?)', | ||
* ['Catto'] | ||
* ) | ||
* ) | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select * from "person" | ||
* where exists ( | ||
* select pet.id | ||
* from pet | ||
* where person.id = pet.owner_id | ||
* and pet.name = $1 | ||
* ) | ||
* ``` | ||
*/ | ||
whereExists(arg) { | ||
ensureCanHaveWhereClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'and', filter_method_1.parseExistsFilterArgs(this, 'exists', arg)), | ||
queryNode: query_node_utils_1.cloneQueryNodeWithWhere(this.#queryNode, 'and', filter_parser_1.parseExistsFilterArgs(this, 'exists', arg)), | ||
}); | ||
} | ||
/** | ||
* | ||
* Just like {@link QueryBuilder.whereExists | whereExists} but creates a `not exists` clause. | ||
*/ | ||
whereNotExists(arg) { | ||
ensureCanHaveWhereClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'and', filter_method_1.parseExistsFilterArgs(this, 'not exists', arg)), | ||
queryNode: query_node_utils_1.cloneQueryNodeWithWhere(this.#queryNode, 'and', filter_parser_1.parseExistsFilterArgs(this, 'not exists', arg)), | ||
}); | ||
} | ||
/** | ||
* | ||
* Just like {@link QueryBuilder.whereExists | whereExists} but creates a `or exists` clause. | ||
*/ | ||
orWhereExists(arg) { | ||
ensureCanHaveWhereClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'or', filter_method_1.parseExistsFilterArgs(this, 'exists', arg)), | ||
queryNode: query_node_utils_1.cloneQueryNodeWithWhere(this.#queryNode, 'or', filter_parser_1.parseExistsFilterArgs(this, 'exists', arg)), | ||
}); | ||
} | ||
/** | ||
* | ||
* Just like {@link QueryBuilder.whereExists | whereExists} but creates a `or not exists` clause. | ||
*/ | ||
orWhereNotExists(arg) { | ||
ensureCanHaveWhereClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithWhere(this.#queryNode, 'or', filter_method_1.parseExistsFilterArgs(this, 'not exists', arg)), | ||
queryNode: query_node_utils_1.cloneQueryNodeWithWhere(this.#queryNode, 'or', filter_parser_1.parseExistsFilterArgs(this, 'not exists', arg)), | ||
}); | ||
} | ||
select(selection) { | ||
ensureCanHaveSelectClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithSelections(this.#queryNode, select_method_1.parseSelectArgs(this, selection)), | ||
queryNode: select_query_node_1.cloneSelectQueryNodeWithSelections(this.#queryNode, select_parser_1.parseSelectExpressionOrList(selection)), | ||
}); | ||
} | ||
distinctOn(selection) { | ||
ensureCanHaveSelectClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithDistinctOnSelections(this.#queryNode, select_method_1.parseSelectArgs(this, selection)), | ||
queryNode: select_query_node_1.cloneSelectQueryNodeWithDistinctOnSelections(this.#queryNode, select_parser_1.parseSelectExpressionOrList(selection)), | ||
}); | ||
@@ -132,85 +253,335 @@ } | ||
distinct() { | ||
ensureCanHaveSelectClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithSelectModifier(this.#queryNode, 'Distinct'), | ||
queryNode: select_query_node_1.cloneSelectQueryNodeWithModifier(this.#queryNode, 'Distinct'), | ||
}); | ||
} | ||
/** | ||
* | ||
* Adds the `for update` option to a select query on supported databases. | ||
*/ | ||
forUpdate() { | ||
ensureCanHaveSelectClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithModifier(this.#queryNode, 'ForUpdate'), | ||
queryNode: select_query_node_1.cloneSelectQueryNodeWithModifier(this.#queryNode, 'ForUpdate'), | ||
}); | ||
} | ||
/** | ||
* | ||
* Adds the `for share` option to a select query on supported databases. | ||
*/ | ||
forShare() { | ||
ensureCanHaveSelectClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithModifier(this.#queryNode, 'ForShare'), | ||
queryNode: select_query_node_1.cloneSelectQueryNodeWithModifier(this.#queryNode, 'ForShare'), | ||
}); | ||
} | ||
/** | ||
* | ||
* Adds the `for key share` option to a select query on supported databases. | ||
*/ | ||
forKeyShare() { | ||
ensureCanHaveSelectClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithModifier(this.#queryNode, 'ForKeyShare'), | ||
queryNode: select_query_node_1.cloneSelectQueryNodeWithModifier(this.#queryNode, 'ForKeyShare'), | ||
}); | ||
} | ||
/** | ||
* | ||
* Adds the `for no key update` option to a select query on supported databases. | ||
*/ | ||
forNoKeyUpdate() { | ||
ensureCanHaveSelectClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithModifier(this.#queryNode, 'ForNoKeyUpdate'), | ||
queryNode: select_query_node_1.cloneSelectQueryNodeWithModifier(this.#queryNode, 'ForNoKeyUpdate'), | ||
}); | ||
} | ||
/** | ||
* | ||
* Adds the `skip locked` option to a select query on supported databases. | ||
*/ | ||
skipLocked() { | ||
ensureCanHaveSelectClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithModifier(this.#queryNode, 'SkipLocked'), | ||
queryNode: select_query_node_1.cloneSelectQueryNodeWithModifier(this.#queryNode, 'SkipLocked'), | ||
}); | ||
} | ||
/** | ||
* | ||
* Adds the `nowait` option to a select query on supported databases. | ||
*/ | ||
noWait() { | ||
ensureCanHaveSelectClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithModifier(this.#queryNode, 'NoWait'), | ||
queryNode: select_query_node_1.cloneSelectQueryNodeWithModifier(this.#queryNode, 'NoWait'), | ||
}); | ||
} | ||
selectAll(table) { | ||
ensureCanHaveSelectClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithSelections(this.#queryNode, select_method_1.parseSelectAllArgs(table)), | ||
queryNode: select_query_node_1.cloneSelectQueryNodeWithSelections(this.#queryNode, select_parser_1.parseSelectAllArgs(table)), | ||
}); | ||
} | ||
innerJoin(...args) { | ||
ensureCanHaveJoins(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_1.cloneQueryNodeWithJoin(this.#queryNode, join_method_1.parseJoinArgs(this, 'InnerJoin', args)), | ||
queryNode: query_node_utils_1.cloneQueryNodeWithJoin(this.#queryNode, join_parser_1.parseJoinArgs('InnerJoin', args)), | ||
}); | ||
} | ||
leftJoin(...args) { | ||
ensureCanHaveJoins(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_utils_1.cloneQueryNodeWithJoin(this.#queryNode, join_parser_1.parseJoinArgs('LeftJoin', args)), | ||
}); | ||
} | ||
rightJoin(...args) { | ||
ensureCanHaveJoins(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_utils_1.cloneQueryNodeWithJoin(this.#queryNode, join_parser_1.parseJoinArgs('RightJoin', args)), | ||
}); | ||
} | ||
fullJoin(...args) { | ||
ensureCanHaveJoins(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_utils_1.cloneQueryNodeWithJoin(this.#queryNode, join_parser_1.parseJoinArgs('FullJoin', args)), | ||
}); | ||
} | ||
values(args) { | ||
ensureCanHaveInsertValues(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: insert_query_node_1.cloneInsertQueryNodeWithColumnsAndValues(this.#queryNode, ...insert_values_parser_1.parseInsertValuesArgs(args)), | ||
}); | ||
} | ||
/** | ||
* Sets the values to update for an `updateTable` query. | ||
* | ||
* This method takes an object whose keys are column names and values are | ||
* values to update. In addition to the column's type, the values can be `raw` | ||
* instances or select queries. | ||
* | ||
* The return value is the number of affected rows. You can use the | ||
* {@link QueryBuilder.returning | returning} method on supported databases | ||
* to get out the updated rows. | ||
* | ||
* @example | ||
* Update a row in `person` table: | ||
* | ||
* ```ts | ||
* const numAffectedRows = await db | ||
* .updateTable('person') | ||
* .set({ | ||
* first_name: 'Jennifer', | ||
* last_name: 'Aniston' | ||
* }) | ||
* .where('id', '=', 1) | ||
* .executeTakeFirst() | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* update "person" set "first_name" = $1, "last_name" = $2 where "id" = $3 | ||
* ``` | ||
* | ||
* @example | ||
* On postgresql you need to chain `returning` to the query to get | ||
* the updated rows' columns (or any other expression) as the | ||
* return value: | ||
* | ||
* ```ts | ||
* const row = await db | ||
* .updateTable('person') | ||
* .set({ | ||
* first_name: 'Jennifer', | ||
* last_name: 'Aniston' | ||
* }) | ||
* .where('id', '=', 1) | ||
* .returning('id') | ||
* .executeTakeFirst() | ||
* | ||
* row.id | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* update "person" set "first_name" = $1, "last_name" = $2 where "id" = $3 returning "id" | ||
* ``` | ||
* | ||
* @example | ||
* In addition to primitives, the values can also be `raw` expressions or | ||
* select queries: | ||
* | ||
* ```ts | ||
* const numAffectedRows = await db | ||
* .updateTable('person') | ||
* .set({ | ||
* first_name: 'Jennifer', | ||
* last_name: db.raw('? || ?', ['Ani', 'ston']), | ||
* age: db.selectFrom('person').select(raw('avg(age)')), | ||
* }) | ||
* .where('id', '=', 1) | ||
* .executeTakeFirst() | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* update "person" set | ||
* "first_name" = $1, | ||
* "last_name" = $2 || $3, | ||
* "age" = (select avg(age) from "person") | ||
* where "id" = $4 | ||
* ``` | ||
*/ | ||
set(row) { | ||
ensureCanHaveUpdates(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: update_query_node_1.cloneUpdateQueryNodeWithColumnUpdates(this.#queryNode, update_set_parser_1.parseUpdateSetArgs(row)), | ||
}); | ||
} | ||
returning(selection) { | ||
ensureCanHaveReturningClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_utils_1.cloneQueryNodeWithReturningSelections(this.#queryNode, select_parser_1.parseSelectExpressionOrList(selection)), | ||
}); | ||
} | ||
/** | ||
* Adds a `returning *` to an insert/update/delete query on databases | ||
* that support `returning` such as postgres. | ||
*/ | ||
returningAll() { | ||
ensureCanHaveReturningClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: query_node_utils_1.cloneQueryNodeWithReturningSelections(this.#queryNode, select_parser_1.parseSelectAllArgs()), | ||
}); | ||
} | ||
/** | ||
* Adds an `order by` clause to the query. | ||
* | ||
* `orderBy` calls are additive. To order by multiple columns, call `orderBy` | ||
* multiple times. | ||
* | ||
* The first argument is the expression to order by and the second is the | ||
* order (`asc` or `desc`). | ||
* | ||
* @example | ||
* ```ts | ||
* await db | ||
* .selectFrom('person') | ||
* .select('person.first_name as fn') | ||
* .orderBy('id') | ||
* .orderBy('fn', 'desc') | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select "person"."first_name" as "fn" | ||
* from "person" | ||
* order by "id" asc, "fn" desc | ||
* ``` | ||
* | ||
* @example | ||
* The order by expression can also be a `raw` expression or a subquery | ||
* in addition to column references: | ||
* | ||
* ```ts | ||
* await db | ||
* .selectFrom('person') | ||
* .selectAll() | ||
* .orderBy((qb) => qb.subQuery('pet') | ||
* .select('pet.name') | ||
* .whereRef('pet.owner_id', '=', 'person.id') | ||
* .limit(1) | ||
* ) | ||
* .orderBy( | ||
* db.raw('concat(first_name, last_name)') | ||
* ) | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select * | ||
* from "person" | ||
* order by | ||
* ( select "pet"."name" | ||
* from "pet" | ||
* where "pet"."owner_id" = "person"."id" | ||
* limit 1 | ||
* ) asc, | ||
* concat(first_name, last_name) asc | ||
* ``` | ||
* | ||
* @example | ||
* `dynamic.ref` can be used to refer to columns not known at | ||
* compile time: | ||
* | ||
* ```ts | ||
* async function someQuery(orderBy: string) { | ||
* const { ref } = db.dynamic | ||
* | ||
* return await db | ||
* .selectFrom('person') | ||
* .select('person.first_name as fn') | ||
* .orderBy(ref(orderBy)) | ||
* } | ||
* | ||
* someQuery('fn') | ||
* ``` | ||
* | ||
* The generated SQL (postgresql): | ||
* | ||
* ```sql | ||
* select "person"."first_name" as "fn" | ||
* from "person" | ||
* order by "fn" asc | ||
* ``` | ||
*/ | ||
orderBy(orderBy, direction = 'asc') { | ||
ensureCanHaveOrderByClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: select_query_node_1.cloneSelectQueryNodeWithOrderByItem(this.#queryNode, order_by_item_node_1.createOrderByItemNode(reference_parser_1.parseReferenceExpression(orderBy), direction)), | ||
}); | ||
} | ||
groupBy(orderBy) { | ||
ensureCanHaveGroupByClause(this.#queryNode); | ||
return new QueryBuilder({ | ||
compiler: this.#compiler, | ||
connectionProvider: this.#connectionProvider, | ||
queryNode: select_query_node_1.cloneSelectQueryNodeWithGroupByItems(this.#queryNode, reference_parser_1.parseReferenceExpressionOrList(orderBy).map(group_by_item_node_1.createGroupByItemNode)), | ||
}); | ||
} | ||
/** | ||
* | ||
*/ | ||
as(alias) { | ||
@@ -222,2 +593,5 @@ return new AliasedQueryBuilder(this, alias); | ||
} | ||
/** | ||
* Change the output type of the query. | ||
*/ | ||
castTo() { | ||
@@ -240,13 +614,13 @@ return new QueryBuilder({ | ||
} | ||
let connection; | ||
try { | ||
connection = await this.#connectionProvider.acquireConnection(); | ||
const result = await this.#connectionProvider.withConnection(async (connection) => { | ||
return await connection.execute(this.compile()); | ||
} | ||
finally { | ||
if (connection) { | ||
await this.#connectionProvider.releaseConnection(connection); | ||
} | ||
} | ||
}); | ||
// Ugly cast but trust me, the type is correct. | ||
return result; | ||
} | ||
async executeTakeFirst() { | ||
const result = await this.execute(); | ||
// Ugly cast but trust me, the type is correct. | ||
return result[0]; | ||
} | ||
} | ||
@@ -276,5 +650,59 @@ exports.QueryBuilder = QueryBuilder; | ||
toOperationNode() { | ||
return alias_node_1.createAliasNode(this.#queryBuilder.toOperationNode(), this.#alias); | ||
const node = this.#queryBuilder.toOperationNode(); | ||
if (select_query_node_1.isSelectQueryNode(node)) { | ||
return alias_node_1.createAliasNode(node, this.#alias); | ||
} | ||
throw new Error('only select queries can be aliased'); | ||
} | ||
} | ||
exports.AliasedQueryBuilder = AliasedQueryBuilder; | ||
function createEmptySelectQuery() { | ||
return new QueryBuilder({ | ||
queryNode: select_query_node_1.createSelectQueryNodeWithFromItems([]), | ||
}); | ||
} | ||
exports.createEmptySelectQuery = createEmptySelectQuery; | ||
function ensureCanHaveWhereClause(node) { | ||
if (!select_query_node_1.isSelectQueryNode(node) && | ||
!delete_query_node_1.isDeleteQueryNode(node) && | ||
!update_query_node_1.isUpdateQueryNode(node)) { | ||
throw new Error('only select, delete and update queries can have a where clause'); | ||
} | ||
} | ||
function ensureCanHaveSelectClause(node) { | ||
if (!select_query_node_1.isSelectQueryNode(node)) { | ||
throw new Error('only a select query can have selections'); | ||
} | ||
} | ||
function ensureCanHaveJoins(node) { | ||
if (!insert_query_node_1.isInsertQueryNode(node) && | ||
!delete_query_node_1.isDeleteQueryNode(node) && | ||
!update_query_node_1.isUpdateQueryNode(node)) { | ||
throw new Error('only select, delete and update queries can have joins'); | ||
} | ||
} | ||
function ensureCanHaveInsertValues(node) { | ||
if (!insert_query_node_1.isInsertQueryNode(node)) { | ||
throw new Error('only an insert query can have insert values'); | ||
} | ||
} | ||
function ensureCanHaveUpdates(node) { | ||
if (!update_query_node_1.isUpdateQueryNode(node)) { | ||
throw new Error('only an update query can set values'); | ||
} | ||
} | ||
function ensureCanHaveReturningClause(node) { | ||
if (!query_node_utils_1.isMutatingQueryNode(node)) { | ||
throw new Error('only an insert, delete and update queries can have a returning clause'); | ||
} | ||
} | ||
function ensureCanHaveOrderByClause(node) { | ||
if (!select_query_node_1.isSelectQueryNode(node)) { | ||
throw new Error('only a select query can have an order by clause'); | ||
} | ||
} | ||
function ensureCanHaveGroupByClause(node) { | ||
if (!select_query_node_1.isSelectQueryNode(node)) { | ||
throw new Error('only a select query can have a group by clause'); | ||
} | ||
} |
@@ -109,2 +109,3 @@ import { AliasedRawBuilder, RawBuilder } from '../raw-builder/raw-builder'; | ||
}[TB]; | ||
export declare type AnyAliasedColumnWithTable<DB, TB extends keyof DB> = `${AnyColumnWithTable<DB, TB>} as ${string}`; | ||
/** | ||
@@ -116,5 +117,14 @@ * Extracts an array item type. | ||
export declare type AnyAliasedQueryBuilder = AliasedQueryBuilder<any, any, any, any>; | ||
export declare type QueryBuilderFactory<DB, TB extends keyof DB, O> = (qb: QueryBuilder<DB, TB, O>) => QueryBuilder<any, any, any>; | ||
export declare type AliasedQueryBuilderFactory<DB, TB extends keyof DB, O> = (qb: QueryBuilder<DB, TB, O>) => AnyAliasedQueryBuilder; | ||
export declare type RawBuilderFactory<DB, TB extends keyof DB, O> = (qb: QueryBuilder<DB, TB, O>) => RawBuilder<any>; | ||
export declare type AliasedRawBuilderFactory<DB, TB extends keyof DB, O> = (qb: QueryBuilder<DB, TB, O>) => AliasedRawBuilder<any, any>; | ||
export declare type QueryBuilderFactory<DB, TB extends keyof DB> = (qb: QueryBuilder<DB, TB, {}>) => QueryBuilder<any, any, any>; | ||
export declare type AliasedQueryBuilderFactory<DB, TB extends keyof DB> = (qb: QueryBuilder<DB, TB, {}>) => AnyAliasedQueryBuilder; | ||
export declare type RawBuilderFactory<DB, TB extends keyof DB> = (qb: QueryBuilder<DB, TB, {}>) => RawBuilder<any>; | ||
export declare type AliasedRawBuilderFactory<DB, TB extends keyof DB> = (qb: QueryBuilder<DB, TB, {}>) => AliasedRawBuilder<any, any>; | ||
export interface InsertResultTypeTag { | ||
__isInsertResultTypeTag__: true; | ||
} | ||
export interface DeleteResultTypeTag { | ||
__isDeleteResultTypeTag__: true; | ||
} | ||
export interface UpdateResultTypeTag { | ||
__isUpdateResultTypeTag__: true; | ||
} |
import { AliasNode } from '../operation-node/alias-node'; | ||
import { AndNode } from '../operation-node/and-node'; | ||
import { ColumnDefinitionNode } from '../operation-node/column-definition-node'; | ||
import { ColumnUpdateNode } from '../operation-node/column-update-node'; | ||
import { CreateTableNode } from '../operation-node/create-table-node'; | ||
import { DataTypeNode } from '../operation-node/data-type-node'; | ||
import { DeleteQueryNode } from '../operation-node/delete-query-node'; | ||
import { DropTableNode } from '../operation-node/drop-table-node'; | ||
import { FilterNode } from '../operation-node/filter-node'; | ||
import { FromNode } from '../operation-node/from-node'; | ||
import { GroupByItemNode } from '../operation-node/group-by-item-node'; | ||
import { GroupByNode } from '../operation-node/group-by-node'; | ||
import { IdentifierNode } from '../operation-node/identifier-node'; | ||
import { InsertQueryNode } from '../operation-node/insert-query-node'; | ||
import { JoinNode } from '../operation-node/join-node'; | ||
@@ -11,27 +20,33 @@ import { OperationNode } from '../operation-node/operation-node'; | ||
import { OrNode } from '../operation-node/or-node'; | ||
import { OrderByItemNode } from '../operation-node/order-by-item-node'; | ||
import { OrderByNode } from '../operation-node/order-by-node'; | ||
import { ParensNode } from '../operation-node/parens-node'; | ||
import { PrimitiveValueListNode } from '../operation-node/primitive-value-list-node'; | ||
import { QueryModifier, QueryNode } from '../operation-node/query-node'; | ||
import { QueryNode } from '../operation-node/query-node-utils'; | ||
import { RawNode } from '../operation-node/raw-node'; | ||
import { ReferenceNode } from '../operation-node/reference-node'; | ||
import { ReturningNode } from '../operation-node/returning-node'; | ||
import { SelectAllNode } from '../operation-node/select-all-node'; | ||
import { SelectNode } from '../operation-node/select-node'; | ||
import { SelectQueryNode } from '../operation-node/select-query-node'; | ||
import { SelectionNode } from '../operation-node/selection-node'; | ||
import { TableNode } from '../operation-node/table-node'; | ||
import { UpdateQueryNode } from '../operation-node/update-query-node'; | ||
import { ValueListNode } from '../operation-node/value-list-node'; | ||
import { ValueNode } from '../operation-node/value-node'; | ||
import { WhereNode } from '../operation-node/where-node'; | ||
import { CompiledQuery } from './compiled-query'; | ||
export declare class QueryCompiler extends OperationNodeVisitor { | ||
#private; | ||
compile(queryNode: QueryNode): CompiledQuery; | ||
protected queryNodeStack: QueryNode[]; | ||
compile(node: QueryNode | CreateTableNode | DropTableNode): CompiledQuery; | ||
private getSql; | ||
private getBindings; | ||
protected visitQuery(node: QueryNode): void; | ||
protected compileSelect(node: SelectNode): void; | ||
protected compileFrom(nodes: ReadonlyArray<FromNode>): void; | ||
protected compileWhere(node: OperationNode): void; | ||
protected compileQueryModifier(modifier: QueryModifier): void; | ||
protected visitSelect({ selections, distinctOnSelections, modifier, }: SelectNode): void; | ||
protected visitSelectQuery(node: SelectQueryNode): void; | ||
protected visitFrom(node: FromNode): void; | ||
protected compileDistinctOn(selections: ReadonlyArray<SelectionNode>): void; | ||
protected compileList(nodes: ReadonlyArray<OperationNode>): void; | ||
protected visitWhere(node: WhereNode): void; | ||
protected visitInsertQuery(node: InsertQueryNode): void; | ||
protected visitDeleteQuery(node: DeleteQueryNode): void; | ||
protected visitReturning(node: ReturningNode): void; | ||
protected visitAlias(node: AliasNode): void; | ||
@@ -53,2 +68,12 @@ protected visitReference(node: ReferenceNode): void; | ||
protected visitTable(node: TableNode): void; | ||
protected visitCreateTable(node: CreateTableNode): void; | ||
protected visitColumnDefinition(node: ColumnDefinitionNode): void; | ||
protected visitDropTable(node: DropTableNode): void; | ||
protected visitDataType(node: DataTypeNode): void; | ||
protected visitOrderBy(node: OrderByNode): void; | ||
protected visitOrderByItem(node: OrderByItemNode): void; | ||
protected visitGroupBy(node: GroupByNode): void; | ||
protected visitGroupByItem(node: GroupByItemNode): void; | ||
protected visitUpdateQuery(node: UpdateQueryNode): void; | ||
protected visitColumnUpdate(node: ColumnUpdateNode): void; | ||
protected appendLeftIdentifierWrapper(): void; | ||
@@ -55,0 +80,0 @@ protected appendRightIdentifierWrapper(): void; |
@@ -11,12 +11,11 @@ "use strict"; | ||
this.#bindings = []; | ||
this.#subQueryDepth = 0; | ||
this.queryNodeStack = []; | ||
} | ||
#sqlFragments; | ||
#bindings; | ||
#subQueryDepth; | ||
compile(queryNode) { | ||
compile(node) { | ||
this.#sqlFragments = []; | ||
this.#bindings = []; | ||
this.#subQueryDepth = 0; | ||
this.visitQuery(queryNode); | ||
this.queryNodeStack = []; | ||
this.visitNode(node); | ||
return object_utils_1.freeze({ | ||
@@ -33,15 +32,24 @@ sql: this.getSql(), | ||
} | ||
visitQuery(node) { | ||
const needsParens = this.#subQueryDepth > 0; | ||
++this.#subQueryDepth; | ||
visitSelectQuery(node) { | ||
const needsParens = !object_utils_1.isEmpty(this.queryNodeStack); | ||
this.queryNodeStack.push(node); | ||
if (needsParens) { | ||
this.append('('); | ||
} | ||
if (node.select) { | ||
this.compileSelect(node.select); | ||
this.append('select '); | ||
if (node.distinctOnSelections && !object_utils_1.isEmpty(node.distinctOnSelections)) { | ||
this.compileDistinctOn(node.distinctOnSelections); | ||
this.append(' '); | ||
} | ||
this.compileFrom(node.from); | ||
if (!object_utils_1.isEmpty(node.joins)) { | ||
if (node.modifier === 'Distinct') { | ||
this.append(SELECT_MODIFIER_SQL[node.modifier]); | ||
this.append(' '); | ||
} | ||
if (node.selections) { | ||
this.compileList(node.selections); | ||
this.append(' '); | ||
} | ||
this.visitNode(node.from); | ||
if (node.joins) { | ||
this.append(' '); | ||
node.joins.forEach(this.visitNode); | ||
@@ -51,7 +59,15 @@ } | ||
this.append(' '); | ||
this.compileWhere(node.where); | ||
this.visitNode(node.where); | ||
} | ||
if (node.groupBy) { | ||
this.append(' '); | ||
this.visitNode(node.groupBy); | ||
} | ||
if (node.orderBy) { | ||
this.append(' '); | ||
this.visitNode(node.orderBy); | ||
} | ||
if (node.modifier) { | ||
this.append(' '); | ||
this.compileQueryModifier(node.modifier); | ||
this.append(SELECT_MODIFIER_SQL[node.modifier]); | ||
} | ||
@@ -61,29 +77,8 @@ if (needsParens) { | ||
} | ||
--this.#subQueryDepth; | ||
this.queryNodeStack.pop(); | ||
} | ||
compileSelect(node) { | ||
this.visitNode(node); | ||
} | ||
compileFrom(nodes) { | ||
visitFrom(node) { | ||
this.append('from '); | ||
this.compileList(nodes); | ||
this.compileList(node.froms); | ||
} | ||
compileWhere(node) { | ||
this.append('where '); | ||
this.visitNode(node); | ||
} | ||
compileQueryModifier(modifier) { | ||
this.append(QUERY_MODIFIER_SQL[modifier]); | ||
} | ||
visitSelect({ selections, distinctOnSelections, modifier, }) { | ||
this.append('select '); | ||
if (!object_utils_1.isEmpty(distinctOnSelections)) { | ||
this.compileDistinctOn(distinctOnSelections); | ||
this.append(' '); | ||
} | ||
if (modifier === 'Distinct') { | ||
this.append('distinct '); | ||
} | ||
this.compileList(selections); | ||
} | ||
compileDistinctOn(selections) { | ||
@@ -103,2 +98,52 @@ this.append('distinct on ('); | ||
} | ||
visitWhere(node) { | ||
this.append('where '); | ||
this.visitNode(node.where); | ||
} | ||
visitInsertQuery(node) { | ||
this.queryNodeStack.push(node); | ||
this.append('insert into '); | ||
this.visitNode(node.into); | ||
if (node.columns) { | ||
this.append(' ('); | ||
this.compileList(node.columns); | ||
this.append(')'); | ||
} | ||
if (node.values) { | ||
this.append(' values '); | ||
if (node.values.length === 1) { | ||
this.visitNode(node.values[0]); | ||
} | ||
else { | ||
this.compileList(node.values); | ||
} | ||
} | ||
if (node.returning) { | ||
this.append(' '); | ||
this.visitNode(node.returning); | ||
} | ||
this.queryNodeStack.pop(); | ||
} | ||
visitDeleteQuery(node) { | ||
this.queryNodeStack.push(node); | ||
this.append('delete '); | ||
this.visitNode(node.from); | ||
if (node.joins) { | ||
this.append(' '); | ||
node.joins.forEach(this.visitNode); | ||
} | ||
if (node.where) { | ||
this.append(' '); | ||
this.visitNode(node.where); | ||
} | ||
if (node.returning) { | ||
this.append(' '); | ||
this.visitNode(node.returning); | ||
} | ||
this.queryNodeStack.pop(); | ||
} | ||
visitReturning(node) { | ||
this.append('returning '); | ||
this.compileList(node.selections); | ||
} | ||
visitAlias(node) { | ||
@@ -126,4 +171,4 @@ this.visitNode(node.node); | ||
visitFilter(node) { | ||
if (node.lhs) { | ||
this.visitNode(node.lhs); | ||
if (node.left) { | ||
this.visitNode(node.left); | ||
this.append(' '); | ||
@@ -133,13 +178,13 @@ } | ||
this.append(' '); | ||
this.visitNode(node.rhs); | ||
this.visitNode(node.right); | ||
} | ||
visitAnd(node) { | ||
this.visitNode(node.lhs); | ||
this.visitNode(node.left); | ||
this.append(' and '); | ||
this.visitNode(node.rhs); | ||
this.visitNode(node.right); | ||
} | ||
visitOr(node) { | ||
this.visitNode(node.lhs); | ||
this.visitNode(node.left); | ||
this.append(' or '); | ||
this.visitNode(node.rhs); | ||
this.visitNode(node.right); | ||
} | ||
@@ -197,2 +242,92 @@ visitValue(node) { | ||
} | ||
visitCreateTable(node) { | ||
this.append('create table '); | ||
this.visitNode(node.table); | ||
this.append(' ('); | ||
this.compileList(node.columns); | ||
this.append(')'); | ||
} | ||
visitColumnDefinition(node) { | ||
this.visitNode(node.column); | ||
this.append(' '); | ||
if (node.isAutoIncrementing) { | ||
this.append('serial'); | ||
} | ||
else { | ||
this.visitNode(node.dataType); | ||
} | ||
if (!node.isNullable) { | ||
this.append(' not null'); | ||
} | ||
if (node.isUnique) { | ||
this.append(' unique'); | ||
} | ||
if (node.isPrimaryKey) { | ||
this.append(' primary key'); | ||
} | ||
if (node.references) { | ||
this.append(' references '); | ||
this.visitNode(node.references.table); | ||
this.append('('); | ||
this.visitNode(node.references.column); | ||
this.append(')'); | ||
if (node.onDelete) { | ||
this.append(' on delete '); | ||
this.append(node.onDelete); | ||
} | ||
} | ||
} | ||
visitDropTable(node) { | ||
this.append('drop table '); | ||
if (node.modifier === 'IfExists') { | ||
this.append('if exists '); | ||
} | ||
this.visitNode(node.table); | ||
} | ||
visitDataType(node) { | ||
this.append(DATA_TYPE_SQL[node.dataType](node)); | ||
} | ||
visitOrderBy(node) { | ||
this.append('order by '); | ||
this.compileList(node.items); | ||
} | ||
visitOrderByItem(node) { | ||
this.visitNode(node.orderBy); | ||
this.append(' '); | ||
this.append(node.direction); | ||
} | ||
visitGroupBy(node) { | ||
this.append('group by '); | ||
this.compileList(node.items); | ||
} | ||
visitGroupByItem(node) { | ||
this.visitNode(node.groupBy); | ||
} | ||
visitUpdateQuery(node) { | ||
this.queryNodeStack.push(node); | ||
this.append('update '); | ||
this.visitNode(node.table); | ||
this.append(' set '); | ||
if (node.updates) { | ||
this.compileList(node.updates); | ||
} | ||
if (node.joins) { | ||
this.append(' '); | ||
node.joins.forEach(this.visitNode); | ||
} | ||
if (node.where) { | ||
this.append(' '); | ||
this.visitNode(node.where); | ||
} | ||
if (node.returning) { | ||
this.append(' '); | ||
this.visitNode(node.returning); | ||
} | ||
this.queryNodeStack.pop(); | ||
} | ||
visitColumnUpdate(node) { | ||
this.visitNode(node.column); | ||
this.append(' = '); | ||
this.visitNode(node.value); | ||
} | ||
appendLeftIdentifierWrapper() { | ||
@@ -208,8 +343,9 @@ this.append('"'); | ||
appendValue(value) { | ||
this.#bindings.push(value); | ||
this.append(`$${this.#bindings.length}`); | ||
this.#bindings.push(value); | ||
} | ||
} | ||
exports.QueryCompiler = QueryCompiler; | ||
const QUERY_MODIFIER_SQL = { | ||
const SELECT_MODIFIER_SQL = { | ||
Distinct: 'distinct', | ||
ForKeyShare: 'for key share', | ||
@@ -228,1 +364,11 @@ ForNoKeyUpdate: 'for no key update', | ||
}; | ||
const DATA_TYPE_SQL = { | ||
BigInteger: () => 'bigint', | ||
Binary: () => '???', | ||
Boolean: () => 'boolean', | ||
Double: () => 'double precision', | ||
Float: () => 'real', | ||
Integer: () => 'integer', | ||
String: (node) => `varchar(${node.size ?? 255})`, | ||
Text: () => 'text', | ||
}; |
@@ -8,3 +8,3 @@ "use strict"; | ||
const value_node_1 = require("../operation-node/value-node"); | ||
const select_method_1 = require("../query-builder/methods/select-method"); | ||
const reference_parser_1 = require("../parser/reference-parser"); | ||
class RawBuilder { | ||
@@ -75,3 +75,3 @@ constructor(sql, params) { | ||
else if (match === '??') { | ||
return select_method_1.parseStringReference(arg); | ||
return reference_parser_1.parseStringReference(arg); | ||
} | ||
@@ -78,0 +78,0 @@ else { |
@@ -0,1 +1,2 @@ | ||
export declare function assertNotNullOrUndefined<T>(value: T): asserts value is NonNullable<T>; | ||
export declare function assertIsString(value: any): asserts value is string; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.assertIsString = void 0; | ||
exports.assertIsString = exports.assertNotNullOrUndefined = void 0; | ||
function assertNotNullOrUndefined(value) { | ||
if (value === null || value === undefined) { | ||
throw new Error(`${value} must not be null or undefined`); | ||
} | ||
} | ||
exports.assertNotNullOrUndefined = assertNotNullOrUndefined; | ||
function assertIsString(value) { | ||
@@ -5,0 +11,0 @@ if (typeof value !== 'string') { |
/// <reference types="node" /> | ||
export declare type PrimitiveValue = string | number | boolean | null | Date | Buffer; | ||
export declare type PrimitiveValue = string | number | boolean | null | Date | Buffer | BigInt; | ||
export declare function isEmpty(obj: ArrayLike<any> | string | object | Buffer): boolean; | ||
@@ -10,2 +10,3 @@ export declare function isString(obj: any): obj is string; | ||
export declare function isBuffer(obj: any): obj is Buffer; | ||
export declare function isBigInt(obj: any): obj is BigInt; | ||
export declare function isPrimitive(obj: any): obj is PrimitiveValue; | ||
@@ -12,0 +13,0 @@ export declare function isFunction(obj: any): obj is Function; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.freeze = exports.getLast = exports.isObject = exports.isFunction = exports.isPrimitive = exports.isBuffer = exports.isDate = exports.isNull = exports.isBoolean = exports.isNumber = exports.isString = exports.isEmpty = void 0; | ||
exports.freeze = exports.getLast = exports.isObject = exports.isFunction = exports.isPrimitive = exports.isBigInt = exports.isBuffer = exports.isDate = exports.isNull = exports.isBoolean = exports.isNumber = exports.isString = exports.isEmpty = void 0; | ||
function isEmpty(obj) { | ||
@@ -38,2 +38,6 @@ if (Array.isArray(obj) || isString(obj) || Buffer.isBuffer(obj)) { | ||
exports.isBuffer = isBuffer; | ||
function isBigInt(obj) { | ||
return typeof obj === 'bigint'; | ||
} | ||
exports.isBigInt = isBigInt; | ||
function isPrimitive(obj) { | ||
@@ -45,3 +49,4 @@ return (isString(obj) || | ||
isDate(obj) || | ||
isBuffer(obj)); | ||
isBuffer(obj) || | ||
isBigInt(obj)); | ||
} | ||
@@ -48,0 +53,0 @@ exports.isPrimitive = isPrimitive; |
{ | ||
"name": "kysely", | ||
"version": "0.1.2", | ||
"version": "0.1.3", | ||
"description": "Type safe SQL query builder", | ||
"main": "lib/index.js", | ||
"scripts": { | ||
"test": "mocha -r ts-node/register test/**/*.test.ts", | ||
"test": "npm run test:integration && npm run test:typings", | ||
"test:integration": "mocha -r ts-node/register test/**/*.test.ts", | ||
"test:typings": "npm run build && tsd test/typings", | ||
@@ -17,2 +18,4 @@ "prettier": "prettier --write src/**/*.ts test/**/*.ts", | ||
"devDependencies": { | ||
"@types/chai": "^4.2.16", | ||
"@types/chai-subset": "^1.3.3", | ||
"@types/mocha": "^8.2.0", | ||
@@ -22,2 +25,3 @@ "@types/node": "^14.14.31", | ||
"chai": "^4.3.0", | ||
"chai-subset": "^1.6.0", | ||
"mocha": "^8.3.0", | ||
@@ -24,0 +28,0 @@ "pg": "^8.5.1", |
@@ -38,3 +38,3 @@ # Kysely | ||
interface Pet { | ||
id: string | ||
id: number | ||
name: string | ||
@@ -66,3 +66,3 @@ owner_id: number | ||
const [person] = await db | ||
.query('person') | ||
.selectFrom('person') | ||
.innerJoin('pet', 'pet.owner_id', 'person.id') | ||
@@ -69,0 +69,0 @@ .select(['first_name', 'pet.name as pet_name']) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
241767
148
6259
14