From 2dd1e6abdbc3c366354a94802d645909088096cd Mon Sep 17 00:00:00 2001 From: igalklebanov Date: Fri, 29 Dec 2023 20:28:01 +0200 Subject: [PATCH 01/18] implement compilation. --- src/index.ts | 1 + .../operation-node-transformer.ts | 50 ++++++++++++------- src/operation-node/operation-node-visitor.ts | 13 +++-- src/operation-node/operation-node.ts | 1 + src/operation-node/select-query-node.ts | 31 ++++++++---- src/operation-node/top-node.ts | 27 ++++++++++ src/query-compiler/default-query-compiler.ts | 35 +++++++++---- 7 files changed, 112 insertions(+), 46 deletions(-) create mode 100644 src/operation-node/top-node.ts diff --git a/src/index.ts b/src/index.ts index 4aec54bb0..2216e7a7e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -197,6 +197,7 @@ export * from './operation-node/json-path-leg-node.js' export * from './operation-node/json-path-node.js' export * from './operation-node/json-operator-chain-node.js' export * from './operation-node/tuple-node.js' +export * from './operation-node/top-node.js' export * from './util/column-type.js' export * from './util/compilable.js' diff --git a/src/operation-node/operation-node-transformer.ts b/src/operation-node/operation-node-transformer.ts index 1adc18e79..ebaf4186f 100644 --- a/src/operation-node/operation-node-transformer.ts +++ b/src/operation-node/operation-node-transformer.ts @@ -88,6 +88,7 @@ import { JSONPathLegNode } from './json-path-leg-node.js' import { JSONOperatorChainNode } from './json-operator-chain-node.js' import { TupleNode } from './tuple-node.js' import { AddIndexNode } from './add-index-node.js' +import { TopNode } from './top-node.js' /** * Transforms an operation node tree into another one. @@ -210,6 +211,7 @@ export class OperationNodeTransformer { JSONOperatorChainNode: this.transformJSONOperatorChain.bind(this), TupleNode: this.transformTuple.bind(this), AddIndexNode: this.transformAddIndex.bind(this), + TopNode: this.transformTop.bind(this), }) transformNode(node: T): T { @@ -229,7 +231,7 @@ export class OperationNodeTransformer { } protected transformNodeList< - T extends ReadonlyArray | undefined + T extends ReadonlyArray | undefined, >(list: T): T { if (!list) { return list @@ -256,6 +258,7 @@ export class OperationNodeTransformer { having: this.transformNode(node.having), explain: this.transformNode(node.explain), setOperations: this.transformNodeList(node.setOperations), + top: this.transformNode(node.top), }) } @@ -418,7 +421,7 @@ export class OperationNodeTransformer { } protected transformColumnDefinition( - node: ColumnDefinitionNode + node: ColumnDefinitionNode, ): ColumnDefinitionNode { return requireAllProps({ kind: 'ColumnDefinitionNode', @@ -534,7 +537,7 @@ export class OperationNodeTransformer { } protected transformOnDuplicateKey( - node: OnDuplicateKeyNode + node: OnDuplicateKeyNode, ): OnDuplicateKeyNode { return requireAllProps({ kind: 'OnDuplicateKeyNode', @@ -574,7 +577,7 @@ export class OperationNodeTransformer { } protected transformPrimaryKeyConstraint( - node: PrimaryKeyConstraintNode + node: PrimaryKeyConstraintNode, ): PrimaryKeyConstraintNode { return requireAllProps({ kind: 'PrimaryKeyConstraintNode', @@ -584,7 +587,7 @@ export class OperationNodeTransformer { } protected transformUniqueConstraint( - node: UniqueConstraintNode + node: UniqueConstraintNode, ): UniqueConstraintNode { return requireAllProps({ kind: 'UniqueConstraintNode', @@ -595,7 +598,7 @@ export class OperationNodeTransformer { } protected transformForeignKeyConstraint( - node: ForeignKeyConstraintNode + node: ForeignKeyConstraintNode, ): ForeignKeyConstraintNode { return requireAllProps({ kind: 'ForeignKeyConstraintNode', @@ -627,7 +630,7 @@ export class OperationNodeTransformer { } protected transformCheckConstraint( - node: CheckConstraintNode + node: CheckConstraintNode, ): CheckConstraintNode { return requireAllProps({ kind: 'CheckConstraintNode', @@ -645,7 +648,7 @@ export class OperationNodeTransformer { } protected transformCommonTableExpression( - node: CommonTableExpressionNode + node: CommonTableExpressionNode, ): CommonTableExpressionNode { return requireAllProps({ kind: 'CommonTableExpressionNode', @@ -656,7 +659,7 @@ export class OperationNodeTransformer { } protected transformCommonTableExpressionName( - node: CommonTableExpressionNameNode + node: CommonTableExpressionNameNode, ): CommonTableExpressionNameNode { return requireAllProps({ kind: 'CommonTableExpressionNameNode', @@ -746,7 +749,7 @@ export class OperationNodeTransformer { } protected transformDropConstraint( - node: DropConstraintNode + node: DropConstraintNode, ): DropConstraintNode { return requireAllProps({ kind: 'DropConstraintNode', @@ -805,7 +808,7 @@ export class OperationNodeTransformer { } protected transformSelectModifier( - node: SelectModifierNode + node: SelectModifierNode, ): SelectModifierNode { return requireAllProps({ kind: 'SelectModifierNode', @@ -839,7 +842,7 @@ export class OperationNodeTransformer { } protected transformSchemableIdentifier( - node: SchemableIdentifierNode + node: SchemableIdentifierNode, ): SchemableIdentifierNode { return requireAllProps({ kind: 'SchemableIdentifierNode', @@ -849,7 +852,7 @@ export class OperationNodeTransformer { } protected transformAggregateFunction( - node: AggregateFunctionNode + node: AggregateFunctionNode, ): AggregateFunctionNode { return requireAllProps({ kind: 'AggregateFunctionNode', @@ -877,7 +880,7 @@ export class OperationNodeTransformer { } protected transformPartitionByItem( - node: PartitionByItemNode + node: PartitionByItemNode, ): PartitionByItemNode { return requireAllProps({ kind: 'PartitionByItemNode', @@ -886,7 +889,7 @@ export class OperationNodeTransformer { } protected transformBinaryOperation( - node: BinaryOperationNode + node: BinaryOperationNode, ): BinaryOperationNode { return requireAllProps({ kind: 'BinaryOperationNode', @@ -897,7 +900,7 @@ export class OperationNodeTransformer { } protected transformUnaryOperation( - node: UnaryOperationNode + node: UnaryOperationNode, ): UnaryOperationNode { return requireAllProps({ kind: 'UnaryOperationNode', @@ -964,7 +967,7 @@ export class OperationNodeTransformer { } protected transformJSONOperatorChain( - node: JSONOperatorChainNode + node: JSONOperatorChainNode, ): JSONOperatorChainNode { return requireAllProps({ kind: 'JSONOperatorChainNode', @@ -991,6 +994,15 @@ export class OperationNodeTransformer { }) } + protected transformTop(node: TopNode): TopNode { + return requireAllProps({ + kind: 'TopNode', + expression: node.expression, + percent: node.percent, + withTies: node.withTies, + }) + } + protected transformDataType(node: DataTypeNode): DataTypeNode { // An Object.freezed leaf node. No need to clone. return node @@ -1012,7 +1024,7 @@ export class OperationNodeTransformer { } protected transformPrimitiveValueList( - node: PrimitiveValueListNode + node: PrimitiveValueListNode, ): PrimitiveValueListNode { // An Object.freezed leaf node. No need to clone. return node @@ -1024,7 +1036,7 @@ export class OperationNodeTransformer { } protected transformDefaultInsertValue( - node: DefaultInsertValueNode + node: DefaultInsertValueNode, ): DefaultInsertValueNode { // An Object.freezed leaf node. No need to clone. return node diff --git a/src/operation-node/operation-node-visitor.ts b/src/operation-node/operation-node-visitor.ts index 4e48300bc..502f53486 100644 --- a/src/operation-node/operation-node-visitor.ts +++ b/src/operation-node/operation-node-visitor.ts @@ -90,6 +90,7 @@ import { JSONPathLegNode } from './json-path-leg-node.js' import { JSONOperatorChainNode } from './json-operator-chain-node.js' import { TupleNode } from './tuple-node.js' import { AddIndexNode } from './add-index-node.js' +import { TopNode } from './top-node.js' export abstract class OperationNodeVisitor { protected readonly nodeStack: OperationNode[] = [] @@ -187,6 +188,7 @@ export abstract class OperationNodeVisitor { JSONOperatorChainNode: this.visitJSONOperatorChain.bind(this), TupleNode: this.visitTuple.bind(this), AddIndexNode: this.visitAddIndex.bind(this), + TopNode: this.visitTop.bind(this), }) protected readonly visitNode = (node: OperationNode): void => { @@ -230,17 +232,17 @@ export abstract class OperationNodeVisitor { protected abstract visitDropIndex(node: DropIndexNode): void protected abstract visitList(node: ListNode): void protected abstract visitPrimaryKeyConstraint( - node: PrimaryKeyConstraintNode + node: PrimaryKeyConstraintNode, ): void protected abstract visitUniqueConstraint(node: UniqueConstraintNode): void protected abstract visitReferences(node: ReferencesNode): void protected abstract visitCheckConstraint(node: CheckConstraintNode): void protected abstract visitWith(node: WithNode): void protected abstract visitCommonTableExpression( - node: CommonTableExpressionNode + node: CommonTableExpressionNode, ): void protected abstract visitCommonTableExpressionName( - node: CommonTableExpressionNameNode + node: CommonTableExpressionNameNode, ): void protected abstract visitHaving(node: HavingNode): void protected abstract visitCreateSchema(node: CreateSchemaNode): void @@ -253,13 +255,13 @@ export abstract class OperationNodeVisitor { protected abstract visitAddConstraint(node: AddConstraintNode): void protected abstract visitDropConstraint(node: DropConstraintNode): void protected abstract visitForeignKeyConstraint( - node: ForeignKeyConstraintNode + node: ForeignKeyConstraintNode, ): void protected abstract visitDataType(node: DataTypeNode): void protected abstract visitSelectAll(node: SelectAllNode): void protected abstract visitIdentifier(node: IdentifierNode): void protected abstract visitSchemableIdentifier( - node: SchemableIdentifierNode + node: SchemableIdentifierNode, ): void protected abstract visitValue(node: ValueNode): void protected abstract visitPrimitiveValueList(node: PrimitiveValueListNode): void @@ -292,4 +294,5 @@ export abstract class OperationNodeVisitor { protected abstract visitJSONOperatorChain(node: JSONOperatorChainNode): void protected abstract visitTuple(node: TupleNode): void protected abstract visitAddIndex(node: AddIndexNode): void + protected abstract visitTop(node: TopNode): void } diff --git a/src/operation-node/operation-node.ts b/src/operation-node/operation-node.ts index d40bb551c..db8396c11 100644 --- a/src/operation-node/operation-node.ts +++ b/src/operation-node/operation-node.ts @@ -86,6 +86,7 @@ export type OperationNodeKind = | 'JSONOperatorChainNode' | 'TupleNode' | 'AddIndexNode' + | 'TopNode' export interface OperationNode { readonly kind: OperationNodeKind diff --git a/src/operation-node/select-query-node.ts b/src/operation-node/select-query-node.ts index e9c08806d..2d239e6ce 100644 --- a/src/operation-node/select-query-node.ts +++ b/src/operation-node/select-query-node.ts @@ -15,6 +15,7 @@ import { WithNode } from './with-node.js' import { SelectModifierNode } from './select-modifier-node.js' import { ExplainNode } from './explain-node.js' import { SetOperationNode } from './set-operation-node.js' +import { TopNode } from './top-node.js' export interface SelectQueryNode extends OperationNode { readonly kind: 'SelectQueryNode' @@ -33,6 +34,7 @@ export interface SelectQueryNode extends OperationNode { readonly having?: HavingNode readonly explain?: ExplainNode readonly setOperations?: ReadonlyArray + readonly top?: TopNode } /** @@ -52,7 +54,7 @@ export const SelectQueryNode = freeze({ createFrom( fromItems: ReadonlyArray, - withNode?: WithNode + withNode?: WithNode, ): SelectQueryNode { return freeze({ kind: 'SelectQueryNode', @@ -63,7 +65,7 @@ export const SelectQueryNode = freeze({ cloneWithSelections( select: SelectQueryNode, - selections: ReadonlyArray + selections: ReadonlyArray, ): SelectQueryNode { return freeze({ ...select, @@ -75,7 +77,7 @@ export const SelectQueryNode = freeze({ cloneWithDistinctOn( select: SelectQueryNode, - expressions: ReadonlyArray + expressions: ReadonlyArray, ): SelectQueryNode { return freeze({ ...select, @@ -87,7 +89,7 @@ export const SelectQueryNode = freeze({ cloneWithFrontModifier( select: SelectQueryNode, - modifier: SelectModifierNode + modifier: SelectModifierNode, ): SelectQueryNode { return freeze({ ...select, @@ -99,7 +101,7 @@ export const SelectQueryNode = freeze({ cloneWithEndModifier( select: SelectQueryNode, - modifier: SelectModifierNode + modifier: SelectModifierNode, ): SelectQueryNode { return freeze({ ...select, @@ -111,7 +113,7 @@ export const SelectQueryNode = freeze({ cloneWithOrderByItems( selectNode: SelectQueryNode, - items: ReadonlyArray + items: ReadonlyArray, ): SelectQueryNode { return freeze({ ...selectNode, @@ -123,7 +125,7 @@ export const SelectQueryNode = freeze({ cloneWithGroupByItems( selectNode: SelectQueryNode, - items: ReadonlyArray + items: ReadonlyArray, ): SelectQueryNode { return freeze({ ...selectNode, @@ -135,7 +137,7 @@ export const SelectQueryNode = freeze({ cloneWithLimit( selectNode: SelectQueryNode, - limit: LimitNode + limit: LimitNode, ): SelectQueryNode { return freeze({ ...selectNode, @@ -145,7 +147,7 @@ export const SelectQueryNode = freeze({ cloneWithOffset( selectNode: SelectQueryNode, - offset: OffsetNode + offset: OffsetNode, ): SelectQueryNode { return freeze({ ...selectNode, @@ -155,7 +157,7 @@ export const SelectQueryNode = freeze({ cloneWithHaving( selectNode: SelectQueryNode, - operation: OperationNode + operation: OperationNode, ): SelectQueryNode { return freeze({ ...selectNode, @@ -167,7 +169,7 @@ export const SelectQueryNode = freeze({ cloneWithSetOperations( selectNode: SelectQueryNode, - setOperations: ReadonlyArray + setOperations: ReadonlyArray, ): SelectQueryNode { return freeze({ ...selectNode, @@ -177,6 +179,13 @@ export const SelectQueryNode = freeze({ }) }, + cloneWithTop(selectNode: SelectQueryNode, top: TopNode): SelectQueryNode { + return freeze({ + ...selectNode, + top, + }) + }, + cloneWithoutSelections(select: SelectQueryNode): SelectQueryNode { return freeze({ ...select, diff --git a/src/operation-node/top-node.ts b/src/operation-node/top-node.ts new file mode 100644 index 000000000..86bfe4341 --- /dev/null +++ b/src/operation-node/top-node.ts @@ -0,0 +1,27 @@ +import { freeze } from '../util/object-utils.js' +import { OperationNode } from './operation-node.js' + +export interface TopNode extends OperationNode { + readonly kind: 'TopNode' + readonly expression: number + readonly percent: boolean + readonly withTies: boolean +} + +/** + * @internal + */ +export const TopNode = freeze({ + is(node: OperationNode): node is TopNode { + return node.kind === 'TopNode' + }, + + create(expression: number, percent: boolean, withTies: boolean): TopNode { + return freeze({ + kind: 'TopNode', + expression, + percent, + withTies, + }) + }, +}) diff --git a/src/query-compiler/default-query-compiler.ts b/src/query-compiler/default-query-compiler.ts index 50f025709..e2cc952f6 100644 --- a/src/query-compiler/default-query-compiler.ts +++ b/src/query-compiler/default-query-compiler.ts @@ -105,6 +105,7 @@ import { JSONPathLegNode } from '../operation-node/json-path-leg-node.js' import { JSONOperatorChainNode } from '../operation-node/json-operator-chain-node.js' import { TupleNode } from '../operation-node/tuple-node.js' import { AddIndexNode } from '../operation-node/add-index-node.js' +import { TopNode } from '../operation-node/top-node.js' export class DefaultQueryCompiler extends OperationNodeVisitor @@ -250,7 +251,7 @@ export class DefaultQueryCompiler protected compileList( nodes: ReadonlyArray, - separator = ', ' + separator = ', ', ): void { const lastIndex = nodes.length - 1 @@ -423,7 +424,7 @@ export class DefaultQueryCompiler protected compileUnwrappedIdentifier(node: IdentifierNode): void { if (!isString(node.name)) { throw new Error( - 'a non-string identifier was passed to compileUnwrappedIdentifier.' + 'a non-string identifier was passed to compileUnwrappedIdentifier.', ) } @@ -463,7 +464,7 @@ export class DefaultQueryCompiler } protected override visitPrimitiveValueList( - node: PrimitiveValueListNode + node: PrimitiveValueListNode, ): void { this.append('(') @@ -522,7 +523,7 @@ export class DefaultQueryCompiler } protected override visitSchemableIdentifier( - node: SchemableIdentifierNode + node: SchemableIdentifierNode, ): void { if (node.schema) { this.visitNode(node.schema) @@ -887,7 +888,7 @@ export class DefaultQueryCompiler } protected override visitPrimaryKeyConstraint( - node: PrimaryKeyConstraintNode + node: PrimaryKeyConstraintNode, ): void { if (node.name) { this.append('constraint ') @@ -931,7 +932,7 @@ export class DefaultQueryCompiler } protected override visitForeignKeyConstraint( - node: ForeignKeyConstraintNode + node: ForeignKeyConstraintNode, ): void { if (node.name) { this.append('constraint ') @@ -970,7 +971,7 @@ export class DefaultQueryCompiler } protected override visitCommonTableExpression( - node: CommonTableExpressionNode + node: CommonTableExpressionNode, ): void { this.visitNode(node.name) this.append(' as ') @@ -987,7 +988,7 @@ export class DefaultQueryCompiler } protected override visitCommonTableExpressionName( - node: CommonTableExpressionNameNode + node: CommonTableExpressionNameNode, ): void { this.visitNode(node.table) @@ -1456,6 +1457,18 @@ export class DefaultQueryCompiler } } + protected override visitTop(node: TopNode): void { + this.append(`top(${node.expression})`) + + if (node.percent) { + this.append(' percent') + } + + if (node.withTies) { + this.append(' with ties') + } + } + protected append(str: string): void { this.#sql += str } @@ -1532,20 +1545,20 @@ export class DefaultQueryCompiler } protected sortSelectModifiers( - arr: SelectModifierNode[] + arr: SelectModifierNode[], ): ReadonlyArray { arr.sort((left, right) => left.modifier && right.modifier ? SELECT_MODIFIER_PRIORITY[left.modifier] - SELECT_MODIFIER_PRIORITY[right.modifier] - : 1 + : 1, ) return freeze(arr) } protected compileColumnAlterations( - columnAlterations: readonly AlterTableColumnAlterationNode[] + columnAlterations: readonly AlterTableColumnAlterationNode[], ) { this.compileList(columnAlterations) } From bc28062786d4fa1b2074cc18f9b5962db5aa4fa6 Mon Sep 17 00:00:00 2001 From: igalklebanov Date: Fri, 29 Dec 2023 21:05:22 +0200 Subject: [PATCH 02/18] simplify top modifiers. --- src/operation-node/operation-node-transformer.ts | 3 +-- src/operation-node/top-node.ts | 12 ++++++------ src/query-compiler/default-query-compiler.ts | 8 ++------ 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/operation-node/operation-node-transformer.ts b/src/operation-node/operation-node-transformer.ts index ebaf4186f..97d6f2660 100644 --- a/src/operation-node/operation-node-transformer.ts +++ b/src/operation-node/operation-node-transformer.ts @@ -998,8 +998,7 @@ export class OperationNodeTransformer { return requireAllProps({ kind: 'TopNode', expression: node.expression, - percent: node.percent, - withTies: node.withTies, + modifiers: node.modifiers, }) } diff --git a/src/operation-node/top-node.ts b/src/operation-node/top-node.ts index 86bfe4341..06692611f 100644 --- a/src/operation-node/top-node.ts +++ b/src/operation-node/top-node.ts @@ -1,11 +1,12 @@ import { freeze } from '../util/object-utils.js' import { OperationNode } from './operation-node.js' +export type TopModifier = 'percent' | 'with ties' | 'percent with ties' + export interface TopNode extends OperationNode { readonly kind: 'TopNode' - readonly expression: number - readonly percent: boolean - readonly withTies: boolean + readonly expression: number | bigint + readonly modifiers?: TopModifier } /** @@ -16,12 +17,11 @@ export const TopNode = freeze({ return node.kind === 'TopNode' }, - create(expression: number, percent: boolean, withTies: boolean): TopNode { + create(expression: number | bigint, modifiers?: TopModifier): TopNode { return freeze({ kind: 'TopNode', expression, - percent, - withTies, + modifiers, }) }, }) diff --git a/src/query-compiler/default-query-compiler.ts b/src/query-compiler/default-query-compiler.ts index e2cc952f6..4aa0001a3 100644 --- a/src/query-compiler/default-query-compiler.ts +++ b/src/query-compiler/default-query-compiler.ts @@ -1460,12 +1460,8 @@ export class DefaultQueryCompiler protected override visitTop(node: TopNode): void { this.append(`top(${node.expression})`) - if (node.percent) { - this.append(' percent') - } - - if (node.withTies) { - this.append(' with ties') + if (node.modifiers) { + this.append(` ${node.modifiers}`) } } From 296ffe59bc993aaa307b7a6561d1a4fd72fffaee Mon Sep 17 00:00:00 2001 From: igalklebanov Date: Fri, 29 Dec 2023 21:13:10 +0200 Subject: [PATCH 03/18] add to select query builder. --- src/query-builder/select-query-builder.ts | 82 ++++++++++++++++++++++- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/src/query-builder/select-query-builder.ts b/src/query-builder/select-query-builder.ts index c46814414..dc898334b 100644 --- a/src/query-builder/select-query-builder.ts +++ b/src/query-builder/select-query-builder.ts @@ -75,6 +75,7 @@ import { Streamable } from '../util/streamable.js' import { ExpressionOrFactory } from '../parser/expression-parser.js' import { ExpressionWrapper } from '../expression/expression-wrapper.js' import { SelectQueryBuilderExpression } from './select-query-builder-expression.js' +import { TopModifier, TopNode } from '../operation-node/top-node.js' export interface SelectQueryBuilder extends WhereInterface, @@ -1026,6 +1027,13 @@ export interface SelectQueryBuilder * .selectFrom('person') * .select('first_name') * .limit(10) + * .execute() + * ``` + * + * The generated SQL (PostgreSQL): + * + * ```sql + * select "first_name" from "person" limit $1 * ``` * * Select rows from index 10 to index 19 of the result: @@ -1034,8 +1042,15 @@ export interface SelectQueryBuilder * return await db * .selectFrom('person') * .select('first_name') - * .offset(10) * .limit(10) + * .offset(10) + * .execute() + * ``` + * + * The generated SQL (PostgreSQL): + * + * ```sql + * select "first_name" from "person" limit $1 offset $2 * ``` */ limit(limit: number): SelectQueryBuilder @@ -1051,12 +1066,62 @@ export interface SelectQueryBuilder * return await db * .selectFrom('person') * .select('first_name') - * .offset(10) * .limit(10) + * .offset(10) + * .execute() + * ``` + * + * The generated SQL (PostgreSQL): + * + * ```sql + * select "first_name" from "person" limit $1 offset $2 * ``` */ offset(offset: number): SelectQueryBuilder + /** + * Adds a top clause to the query. + * + * ### Examples + * + * Select 10 biggest ages: + * + * ```ts + * return await db + * .selectFrom('person') + * .select('age') + * .top(10) + * .orderBy('age desc') + * .execute() + * ``` + * + * The generated SQL (MS SQL Server): + * + * ```sql + * select top(10) "age" from "person" order by "age" desc + * ``` + * + * Select 10% first rows: + * + * ```ts + * return await db + * .selectFrom('person') + * .selectAll() + * .top(10, 'percent') + * .execute() + * ``` + * + * The generated SQL (MS SQL Server): + * + * ```sql + * select top(10) percent * from "person" + * ``` + */ + top( + expression: number | bigint, + modifiers?: TopModifier + ): SelectQueryBuilder + /** * Combines another select query or raw expression to this query using `union`. * @@ -1967,6 +2032,19 @@ class SelectQueryBuilderImpl }) } + top( + expression: number | bigint, + modifiers?: TopModifier + ): SelectQueryBuilder { + return new SelectQueryBuilderImpl({ + ...this.#props, + queryNode: SelectQueryNode.cloneWithTop( + this.#props.queryNode, + TopNode.create(expression, modifiers) + ), + }) + } + union( expression: SetOperandExpression ): SelectQueryBuilder { From dd9a9e2328186790e8487cfff52b6301572a2c9d Mon Sep 17 00:00:00 2001 From: igalklebanov Date: Fri, 29 Dec 2023 21:39:24 +0200 Subject: [PATCH 04/18] forgot to handle it in select visitor. --- src/query-compiler/default-query-compiler.ts | 27 ++++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/query-compiler/default-query-compiler.ts b/src/query-compiler/default-query-compiler.ts index 4aa0001a3..59f192679 100644 --- a/src/query-compiler/default-query-compiler.ts +++ b/src/query-compiler/default-query-compiler.ts @@ -170,6 +170,11 @@ export class DefaultQueryCompiler this.compileList(node.frontModifiers, ' ') } + if (node.top) { + this.append(' ') + this.visitNode(node.top) + } + if (node.selections) { this.append(' ') this.compileList(node.selections) @@ -251,7 +256,7 @@ export class DefaultQueryCompiler protected compileList( nodes: ReadonlyArray, - separator = ', ', + separator = ', ' ): void { const lastIndex = nodes.length - 1 @@ -424,7 +429,7 @@ export class DefaultQueryCompiler protected compileUnwrappedIdentifier(node: IdentifierNode): void { if (!isString(node.name)) { throw new Error( - 'a non-string identifier was passed to compileUnwrappedIdentifier.', + 'a non-string identifier was passed to compileUnwrappedIdentifier.' ) } @@ -464,7 +469,7 @@ export class DefaultQueryCompiler } protected override visitPrimitiveValueList( - node: PrimitiveValueListNode, + node: PrimitiveValueListNode ): void { this.append('(') @@ -523,7 +528,7 @@ export class DefaultQueryCompiler } protected override visitSchemableIdentifier( - node: SchemableIdentifierNode, + node: SchemableIdentifierNode ): void { if (node.schema) { this.visitNode(node.schema) @@ -888,7 +893,7 @@ export class DefaultQueryCompiler } protected override visitPrimaryKeyConstraint( - node: PrimaryKeyConstraintNode, + node: PrimaryKeyConstraintNode ): void { if (node.name) { this.append('constraint ') @@ -932,7 +937,7 @@ export class DefaultQueryCompiler } protected override visitForeignKeyConstraint( - node: ForeignKeyConstraintNode, + node: ForeignKeyConstraintNode ): void { if (node.name) { this.append('constraint ') @@ -971,7 +976,7 @@ export class DefaultQueryCompiler } protected override visitCommonTableExpression( - node: CommonTableExpressionNode, + node: CommonTableExpressionNode ): void { this.visitNode(node.name) this.append(' as ') @@ -988,7 +993,7 @@ export class DefaultQueryCompiler } protected override visitCommonTableExpressionName( - node: CommonTableExpressionNameNode, + node: CommonTableExpressionNameNode ): void { this.visitNode(node.table) @@ -1541,20 +1546,20 @@ export class DefaultQueryCompiler } protected sortSelectModifiers( - arr: SelectModifierNode[], + arr: SelectModifierNode[] ): ReadonlyArray { arr.sort((left, right) => left.modifier && right.modifier ? SELECT_MODIFIER_PRIORITY[left.modifier] - SELECT_MODIFIER_PRIORITY[right.modifier] - : 1, + : 1 ) return freeze(arr) } protected compileColumnAlterations( - columnAlterations: readonly AlterTableColumnAlterationNode[], + columnAlterations: readonly AlterTableColumnAlterationNode[] ) { this.compileList(columnAlterations) } From 4b7c4fd7487e4f8f4687622d671b464e8ddfbd10 Mon Sep 17 00:00:00 2001 From: igalklebanov Date: Fri, 29 Dec 2023 21:39:31 +0200 Subject: [PATCH 05/18] select test cases. --- test/node/src/select.test.ts | 97 ++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/test/node/src/select.test.ts b/test/node/src/select.test.ts index e8515a712..71b0a8eb1 100644 --- a/test/node/src/select.test.ts +++ b/test/node/src/select.test.ts @@ -1052,5 +1052,102 @@ for (const dialect of DIALECTS) { expect(result[0]).to.eql({ person_first_name: 'Arnold' }) } }) + + if (dialect === 'mssql') { + it('should create a select query with top', async () => { + const query = ctx.db.selectFrom('person').select('first_name').top(2) + + testSql(query, dialect, { + postgres: NOT_SUPPORTED, + mysql: NOT_SUPPORTED, + mssql: { + sql: 'select top(2) "first_name" from "person"', + parameters: [], + }, + sqlite: NOT_SUPPORTED, + }) + + await query.execute() + }) + + it('should create a select query with top and order by', async () => { + const query = ctx.db + .selectFrom('person') + .select('first_name') + .top(2) + .orderBy('first_name') + + testSql(query, dialect, { + postgres: NOT_SUPPORTED, + mysql: NOT_SUPPORTED, + mssql: { + sql: 'select top(2) "first_name" from "person" order by "first_name"', + parameters: [], + }, + sqlite: NOT_SUPPORTED, + }) + + await query.execute() + }) + + it('should create a select query with top percent', async () => { + const query = ctx.db + .selectFrom('person') + .select('first_name') + .top(50, 'percent') + + testSql(query, dialect, { + postgres: NOT_SUPPORTED, + mysql: NOT_SUPPORTED, + mssql: { + sql: 'select top(50) percent "first_name" from "person"', + parameters: [], + }, + sqlite: NOT_SUPPORTED, + }) + + await query.execute() + }) + + it('should create a select query with top with ties', async () => { + const query = ctx.db + .selectFrom('person') + .select('first_name') + .top(2, 'with ties') + .orderBy('first_name') + + testSql(query, dialect, { + postgres: NOT_SUPPORTED, + mysql: NOT_SUPPORTED, + mssql: { + sql: 'select top(2) with ties "first_name" from "person" order by "first_name"', + parameters: [], + }, + sqlite: NOT_SUPPORTED, + }) + + await query.execute() + }) + + it('should create a select query with top percent with ties', async () => { + const query = ctx.db + .selectFrom('person') + .select('first_name') + .top(50, 'percent with ties') + .orderBy('first_name') + + testSql(query, dialect, { + postgres: NOT_SUPPORTED, + mysql: NOT_SUPPORTED, + mssql: { + sql: 'select top(50) percent with ties "first_name" from "person" order by "first_name"', + parameters: [], + }, + sqlite: NOT_SUPPORTED, + }) + + await query.execute() + }) + } }) } From 343fc30f958cc33d6c59b92ebdbe5306811f57a1 Mon Sep 17 00:00:00 2001 From: igalklebanov Date: Fri, 29 Dec 2023 21:44:58 +0200 Subject: [PATCH 06/18] use .top instead of raw in tests. --- test/node/src/clear.test.ts | 2 +- test/node/src/join.test.ts | 6 +++--- test/node/src/select.test.ts | 2 +- test/node/src/test-setup.ts | 16 ++++++++++++---- test/node/src/update.test.ts | 2 +- 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/test/node/src/clear.test.ts b/test/node/src/clear.test.ts index 8d1b88c32..3351a1f34 100644 --- a/test/node/src/clear.test.ts +++ b/test/node/src/clear.test.ts @@ -253,7 +253,7 @@ for (const dialect of DIALECTS) { parameters: [1], }, mssql: { - sql: `select top 1 * from "person"`, + sql: `select top(1) * from "person"`, parameters: [], }, sqlite: { diff --git a/test/node/src/join.test.ts b/test/node/src/join.test.ts index c9b44df0b..5b1054bf0 100644 --- a/test/node/src/join.test.ts +++ b/test/node/src/join.test.ts @@ -273,7 +273,7 @@ for (const dialect of DIALECTS) { `inner join "pet"`, `on "pet"."owner_id" = "person"."id"`, `and "pet"."name" in (@1, @2, @3)`, - `and ("pet"."species" = @4 or "species" = @5 or "species" = (select top 1 'hamster' as "hamster" from "pet"))`, + `and ("pet"."species" = @4 or "species" = @5 or "species" = (select top(1) 'hamster' as "hamster" from "pet"))`, `order by "person"."first_name"`, ], parameters: ['Catto', 'Doggo', 'Hammo', 'cat', 'dog'], @@ -348,7 +348,7 @@ for (const dialect of DIALECTS) { `inner join "pet"`, `on "pet"."owner_id" = "person"."id"`, `and "pet"."name" in (@1, @2, @3)`, - `and ("pet"."species" = @4 or "species" = @5 or "species" = (select top 1 'hamster' as "hamster" from "pet"))`, + `and ("pet"."species" = @4 or "species" = @5 or "species" = (select top(1) 'hamster' as "hamster" from "pet"))`, `order by "person"."first_name"`, ], parameters: ['Catto', 'Doggo', 'Hammo', 'cat', 'dog'], @@ -593,7 +593,7 @@ for (const dialect of DIALECTS) { `left join "pet"`, `on "pet"."owner_id" = "person"."id"`, `and "pet"."name" in (@1, @2, @3)`, - `and ("pet"."species" = @4 or "species" = @5 or "species" = (select top 1 'hamster' as "hamster" from "pet"))`, + `and ("pet"."species" = @4 or "species" = @5 or "species" = (select top(1) 'hamster' as "hamster" from "pet"))`, `order by "person"."first_name"`, ], parameters: ['Catto', 'Doggo', 'Hammo', 'cat', 'dog'], diff --git a/test/node/src/select.test.ts b/test/node/src/select.test.ts index 71b0a8eb1..3f52c2819 100644 --- a/test/node/src/select.test.ts +++ b/test/node/src/select.test.ts @@ -1033,7 +1033,7 @@ for (const dialect of DIALECTS) { parameters: [1], }, mssql: { - sql: `select (select top 1 "first_name" from "person" order by "first_name") as "person_first_name"`, + sql: `select (select top(1) "first_name" from "person" order by "first_name") as "person_first_name"`, parameters: [], }, sqlite: { diff --git a/test/node/src/test-setup.ts b/test/node/src/test-setup.ts index ce11edb5c..c7eea98de 100644 --- a/test/node/src/test-setup.ts +++ b/test/node/src/test-setup.ts @@ -37,7 +37,10 @@ import { MssqlDialect, SelectQueryBuilder, } from '../../../' -import { OrderByDirection, UndirectedOrderByExpression } from '../../../dist/cjs/parser/order-by-parser' +import { + OrderByDirection, + UndirectedOrderByExpression, +} from '../../../dist/cjs/parser/order-by-parser' export type Gender = 'male' | 'female' | 'other' export type MaritalStatus = 'single' | 'married' | 'divorced' | 'widowed' @@ -476,7 +479,7 @@ export function limit>( ): (qb: QB) => QB { return (qb) => { if (dialect === 'mssql') { - return qb.modifyFront(sql`top ${sql.lit(limit)}`) as QB + return qb.top(limit) as QB } return qb.limit(limit) as QB @@ -492,9 +495,14 @@ export function orderBy>( ): (qb: QB) => QB { return (qb) => { if (dialect === 'mssql') { - return qb.orderBy(orderBy, sql`${sql.raw(direction ? `${direction} ` : '')}${sql.raw('offset 0 rows')}`) as QB + return qb.orderBy( + orderBy, + sql`${sql.raw(direction ? `${direction} ` : '')}${sql.raw( + 'offset 0 rows' + )}` + ) as QB } return qb.orderBy(orderBy, direction) as QB } -} \ No newline at end of file +} diff --git a/test/node/src/update.test.ts b/test/node/src/update.test.ts index 952594cc0..4b5f75030 100644 --- a/test/node/src/update.test.ts +++ b/test/node/src/update.test.ts @@ -544,7 +544,7 @@ for (const dialect of DIALECTS) { parameters: ['Jennifer', 1], }, mssql: { - sql: 'with "jennifer_id" as (select top 1 "id" from "person" where "first_name" = @1) update "pet" set "owner_id" = (select "id" from "jennifer_id")', + sql: 'with "jennifer_id" as (select top(1) "id" from "person" where "first_name" = @1) update "pet" set "owner_id" = (select "id" from "jennifer_id")', parameters: ['Jennifer'], }, sqlite: { From 582e049e47bc9dc09befc97793a5a18d619566b4 Mon Sep 17 00:00:00 2001 From: igalklebanov Date: Fri, 29 Dec 2023 22:20:03 +0200 Subject: [PATCH 07/18] add to delete query builder. --- src/operation-node/delete-query-node.ts | 9 ++++ .../operation-node-transformer.ts | 39 +++++++------- src/query-builder/delete-query-builder.ts | 53 +++++++++++++++++++ src/query-builder/select-query-builder.ts | 2 + src/query-compiler/default-query-compiler.ts | 6 +++ test/node/src/delete.test.ts | 45 ++++++++++++++++ 6 files changed, 135 insertions(+), 19 deletions(-) diff --git a/src/operation-node/delete-query-node.ts b/src/operation-node/delete-query-node.ts index 977dde1f4..5be7e29b9 100644 --- a/src/operation-node/delete-query-node.ts +++ b/src/operation-node/delete-query-node.ts @@ -10,6 +10,7 @@ import { OrderByNode } from './order-by-node.js' import { OrderByItemNode } from './order-by-item-node.js' import { ExplainNode } from './explain-node.js' import { UsingNode } from './using-node.js' +import { TopNode } from './top-node.js' export interface DeleteQueryNode extends OperationNode { readonly kind: 'DeleteQueryNode' @@ -22,6 +23,7 @@ export interface DeleteQueryNode extends OperationNode { readonly orderBy?: OrderByNode readonly limit?: LimitNode readonly explain?: ExplainNode + readonly top?: TopNode } /** @@ -74,4 +76,11 @@ export const DeleteQueryNode = freeze({ : UsingNode.create(tables), }) }, + + cloneWithTop(deleteNode: DeleteQueryNode, top: TopNode): DeleteQueryNode { + return freeze({ + ...deleteNode, + top, + }) + }, }) diff --git a/src/operation-node/operation-node-transformer.ts b/src/operation-node/operation-node-transformer.ts index 97d6f2660..f18e2945e 100644 --- a/src/operation-node/operation-node-transformer.ts +++ b/src/operation-node/operation-node-transformer.ts @@ -231,7 +231,7 @@ export class OperationNodeTransformer { } protected transformNodeList< - T extends ReadonlyArray | undefined, + T extends ReadonlyArray | undefined >(list: T): T { if (!list) { return list @@ -395,6 +395,7 @@ export class OperationNodeTransformer { orderBy: this.transformNode(node.orderBy), limit: this.transformNode(node.limit), explain: this.transformNode(node.explain), + top: this.transformNode(node.top), }) } @@ -421,7 +422,7 @@ export class OperationNodeTransformer { } protected transformColumnDefinition( - node: ColumnDefinitionNode, + node: ColumnDefinitionNode ): ColumnDefinitionNode { return requireAllProps({ kind: 'ColumnDefinitionNode', @@ -537,7 +538,7 @@ export class OperationNodeTransformer { } protected transformOnDuplicateKey( - node: OnDuplicateKeyNode, + node: OnDuplicateKeyNode ): OnDuplicateKeyNode { return requireAllProps({ kind: 'OnDuplicateKeyNode', @@ -577,7 +578,7 @@ export class OperationNodeTransformer { } protected transformPrimaryKeyConstraint( - node: PrimaryKeyConstraintNode, + node: PrimaryKeyConstraintNode ): PrimaryKeyConstraintNode { return requireAllProps({ kind: 'PrimaryKeyConstraintNode', @@ -587,7 +588,7 @@ export class OperationNodeTransformer { } protected transformUniqueConstraint( - node: UniqueConstraintNode, + node: UniqueConstraintNode ): UniqueConstraintNode { return requireAllProps({ kind: 'UniqueConstraintNode', @@ -598,7 +599,7 @@ export class OperationNodeTransformer { } protected transformForeignKeyConstraint( - node: ForeignKeyConstraintNode, + node: ForeignKeyConstraintNode ): ForeignKeyConstraintNode { return requireAllProps({ kind: 'ForeignKeyConstraintNode', @@ -630,7 +631,7 @@ export class OperationNodeTransformer { } protected transformCheckConstraint( - node: CheckConstraintNode, + node: CheckConstraintNode ): CheckConstraintNode { return requireAllProps({ kind: 'CheckConstraintNode', @@ -648,7 +649,7 @@ export class OperationNodeTransformer { } protected transformCommonTableExpression( - node: CommonTableExpressionNode, + node: CommonTableExpressionNode ): CommonTableExpressionNode { return requireAllProps({ kind: 'CommonTableExpressionNode', @@ -659,7 +660,7 @@ export class OperationNodeTransformer { } protected transformCommonTableExpressionName( - node: CommonTableExpressionNameNode, + node: CommonTableExpressionNameNode ): CommonTableExpressionNameNode { return requireAllProps({ kind: 'CommonTableExpressionNameNode', @@ -749,7 +750,7 @@ export class OperationNodeTransformer { } protected transformDropConstraint( - node: DropConstraintNode, + node: DropConstraintNode ): DropConstraintNode { return requireAllProps({ kind: 'DropConstraintNode', @@ -808,7 +809,7 @@ export class OperationNodeTransformer { } protected transformSelectModifier( - node: SelectModifierNode, + node: SelectModifierNode ): SelectModifierNode { return requireAllProps({ kind: 'SelectModifierNode', @@ -842,7 +843,7 @@ export class OperationNodeTransformer { } protected transformSchemableIdentifier( - node: SchemableIdentifierNode, + node: SchemableIdentifierNode ): SchemableIdentifierNode { return requireAllProps({ kind: 'SchemableIdentifierNode', @@ -852,7 +853,7 @@ export class OperationNodeTransformer { } protected transformAggregateFunction( - node: AggregateFunctionNode, + node: AggregateFunctionNode ): AggregateFunctionNode { return requireAllProps({ kind: 'AggregateFunctionNode', @@ -880,7 +881,7 @@ export class OperationNodeTransformer { } protected transformPartitionByItem( - node: PartitionByItemNode, + node: PartitionByItemNode ): PartitionByItemNode { return requireAllProps({ kind: 'PartitionByItemNode', @@ -889,7 +890,7 @@ export class OperationNodeTransformer { } protected transformBinaryOperation( - node: BinaryOperationNode, + node: BinaryOperationNode ): BinaryOperationNode { return requireAllProps({ kind: 'BinaryOperationNode', @@ -900,7 +901,7 @@ export class OperationNodeTransformer { } protected transformUnaryOperation( - node: UnaryOperationNode, + node: UnaryOperationNode ): UnaryOperationNode { return requireAllProps({ kind: 'UnaryOperationNode', @@ -967,7 +968,7 @@ export class OperationNodeTransformer { } protected transformJSONOperatorChain( - node: JSONOperatorChainNode, + node: JSONOperatorChainNode ): JSONOperatorChainNode { return requireAllProps({ kind: 'JSONOperatorChainNode', @@ -1023,7 +1024,7 @@ export class OperationNodeTransformer { } protected transformPrimitiveValueList( - node: PrimitiveValueListNode, + node: PrimitiveValueListNode ): PrimitiveValueListNode { // An Object.freezed leaf node. No need to clone. return node @@ -1035,7 +1036,7 @@ export class OperationNodeTransformer { } protected transformDefaultInsertValue( - node: DefaultInsertValueNode, + node: DefaultInsertValueNode ): DefaultInsertValueNode { // An Object.freezed leaf node. No need to clone. return node diff --git a/src/query-builder/delete-query-builder.ts b/src/query-builder/delete-query-builder.ts index 8197851ee..2e1794731 100644 --- a/src/query-builder/delete-query-builder.ts +++ b/src/query-builder/delete-query-builder.ts @@ -67,6 +67,7 @@ import { import { KyselyTypeError } from '../util/type-error.js' import { Streamable } from '../util/streamable.js' import { ExpressionOrFactory } from '../parser/expression-parser.js' +import { TopNode } from '../operation-node/top-node.js' export class DeleteQueryBuilder implements @@ -130,6 +131,58 @@ export class DeleteQueryBuilder }) } + /** + * Adds a `top` clause to the query. + * + * This clause is only supported by some dialects like MS SQL Server. + * + * ### Examples + * + * Delete the first 5 rows: + * + * ```ts + * await db + * .deleteFrom('person') + * .top(5) + * .where('age', '>', 18) + * .executeTakeFirstOrThrow() + * ``` + * + * The generated SQL (MS SQL Server): + * + * ```sql + * delete top(5) from "person" where "age" > @1 + * ``` + * + * Delete the first 50% of rows: + * + * ```ts + * await db + * .deleteFrom('person') + * .top(50, 'percent') + * .where('age', '>', 18) + * .executeTakeFirstOrThrow() + * ``` + * + * The generated SQL (MS SQL Server): + * + * ```sql + * delete top(50) percent from "person" where "age" > @1 + * ``` + */ + top( + top: number | bigint, + modifiers?: 'percent' + ): DeleteQueryBuilder { + return new DeleteQueryBuilder({ + ...this.#props, + queryNode: DeleteQueryNode.cloneWithTop( + this.#props.queryNode, + TopNode.create(top, modifiers) + ), + }) + } + /** * Adds a `using` clause to the query. * diff --git a/src/query-builder/select-query-builder.ts b/src/query-builder/select-query-builder.ts index dc898334b..718bf3e47 100644 --- a/src/query-builder/select-query-builder.ts +++ b/src/query-builder/select-query-builder.ts @@ -1082,6 +1082,8 @@ export interface SelectQueryBuilder /** * Adds a top clause to the query. * + * This clause is only supported by some dialects like MS SQL Server. + * * ### Examples * * Select 10 biggest ages: diff --git a/src/query-compiler/default-query-compiler.ts b/src/query-compiler/default-query-compiler.ts index 59f192679..ef2630176 100644 --- a/src/query-compiler/default-query-compiler.ts +++ b/src/query-compiler/default-query-compiler.ts @@ -359,6 +359,12 @@ export class DefaultQueryCompiler } this.append('delete ') + + if (node.top) { + this.visitNode(node.top) + this.append(' ') + } + this.visitNode(node.from) if (node.using) { diff --git a/test/node/src/delete.test.ts b/test/node/src/delete.test.ts index c9a49c409..352c21e5a 100644 --- a/test/node/src/delete.test.ts +++ b/test/node/src/delete.test.ts @@ -867,5 +867,50 @@ for (const dialect of DIALECTS) { ) }) } + + if (dialect === 'mssql') { + it('should delete first row', async () => { + const query = ctx.db + .deleteFrom('person') + .top(1) + .where('gender', '=', 'male') + + testSql(query, dialect, { + postgres: NOT_SUPPORTED, + mysql: NOT_SUPPORTED, + mssql: { + sql: 'delete top(1) from "person" where "gender" = @1', + parameters: ['male'], + }, + sqlite: NOT_SUPPORTED, + }) + + const result = await query.executeTakeFirst() + + expect(result).to.be.instanceOf(DeleteResult) + expect(result.numDeletedRows).to.equal(1n) + }) + + it('should delete first 50% rows', async () => { + const query = ctx.db + .deleteFrom('person') + .top(50, 'percent') + .where('gender', '=', 'male') + + testSql(query, dialect, { + postgres: NOT_SUPPORTED, + mysql: NOT_SUPPORTED, + mssql: { + sql: 'delete top(50) percent from "person" where "gender" = @1', + parameters: ['male'], + }, + sqlite: NOT_SUPPORTED, + }) + + const result = await query.executeTakeFirst() + + expect(result).to.be.instanceOf(DeleteResult) + }) + } }) } From 132f3e70567f8d1d0bbea0e645913c9b68133351 Mon Sep 17 00:00:00 2001 From: igalklebanov Date: Fri, 29 Dec 2023 22:55:18 +0200 Subject: [PATCH 08/18] add to update query builder. --- .../operation-node-transformer.ts | 1 + src/operation-node/query-node.ts | 13 +++++ src/operation-node/update-query-node.ts | 9 ++++ src/query-builder/delete-query-builder.ts | 5 +- src/query-builder/select-query-builder.ts | 5 +- src/query-builder/update-query-builder.ts | 53 +++++++++++++++++++ src/query-compiler/default-query-compiler.ts | 6 +++ test/node/src/delete.test.ts | 4 +- test/node/src/update.test.ts | 40 ++++++++++++++ 9 files changed, 128 insertions(+), 8 deletions(-) diff --git a/src/operation-node/operation-node-transformer.ts b/src/operation-node/operation-node-transformer.ts index f18e2945e..b6d6bf57f 100644 --- a/src/operation-node/operation-node-transformer.ts +++ b/src/operation-node/operation-node-transformer.ts @@ -499,6 +499,7 @@ export class OperationNodeTransformer { returning: this.transformNode(node.returning), with: this.transformNode(node.with), explain: this.transformNode(node.explain), + top: this.transformNode(node.top), }) } diff --git a/src/operation-node/query-node.ts b/src/operation-node/query-node.ts index 90c3a5565..cc5c66ed5 100644 --- a/src/operation-node/query-node.ts +++ b/src/operation-node/query-node.ts @@ -11,6 +11,7 @@ import { OperationNode } from './operation-node.js' import { ExplainNode } from './explain-node.js' import { ExplainFormat } from '../util/explainable.js' import { Expression } from '../expression/expression.js' +import { TopModifier, TopNode } from './top-node.js' export type QueryNode = | SelectQueryNode @@ -22,6 +23,7 @@ type HasJoins = { joins?: ReadonlyArray } type HasWhere = { where?: WhereNode } type HasReturning = { returning?: ReturningNode } type HasExplain = { explain?: ExplainNode } +type HasTop = { top?: TopNode } /** * @internal @@ -81,4 +83,15 @@ export const QueryNode = freeze({ explain: ExplainNode.create(format, options?.toOperationNode()), }) }, + + cloneWithTop( + node: T, + expression: number | bigint, + modifiers?: TopModifier + ): T { + return freeze({ + ...node, + top: TopNode.create(expression, modifiers), + }) + }, }) diff --git a/src/operation-node/update-query-node.ts b/src/operation-node/update-query-node.ts index d249c8cc0..3500a5d7d 100644 --- a/src/operation-node/update-query-node.ts +++ b/src/operation-node/update-query-node.ts @@ -9,6 +9,7 @@ import { WhereNode } from './where-node.js' import { WithNode } from './with-node.js' import { FromNode } from './from-node.js' import { ExplainNode } from './explain-node.js' +import { TopNode } from './top-node.js' export type UpdateValuesNode = ValueListNode | PrimitiveValueListNode @@ -22,6 +23,7 @@ export interface UpdateQueryNode extends OperationNode { readonly returning?: ReturningNode readonly with?: WithNode readonly explain?: ExplainNode + readonly top?: TopNode } /** @@ -63,4 +65,11 @@ export const UpdateQueryNode = freeze({ : updates, }) }, + + cloneWithTop(updateQuery: UpdateQueryNode, top: TopNode): UpdateQueryNode { + return freeze({ + ...updateQuery, + top, + }) + }, }) diff --git a/src/query-builder/delete-query-builder.ts b/src/query-builder/delete-query-builder.ts index 2e1794731..8cdeb77cf 100644 --- a/src/query-builder/delete-query-builder.ts +++ b/src/query-builder/delete-query-builder.ts @@ -176,10 +176,7 @@ export class DeleteQueryBuilder ): DeleteQueryBuilder { return new DeleteQueryBuilder({ ...this.#props, - queryNode: DeleteQueryNode.cloneWithTop( - this.#props.queryNode, - TopNode.create(top, modifiers) - ), + queryNode: QueryNode.cloneWithTop(this.#props.queryNode, top, modifiers), }) } diff --git a/src/query-builder/select-query-builder.ts b/src/query-builder/select-query-builder.ts index 718bf3e47..63808889f 100644 --- a/src/query-builder/select-query-builder.ts +++ b/src/query-builder/select-query-builder.ts @@ -2040,9 +2040,10 @@ class SelectQueryBuilderImpl ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, - queryNode: SelectQueryNode.cloneWithTop( + queryNode: QueryNode.cloneWithTop( this.#props.queryNode, - TopNode.create(expression, modifiers) + expression, + modifiers ), }) } diff --git a/src/query-builder/update-query-builder.ts b/src/query-builder/update-query-builder.ts index 2f51eea46..dcb3316f9 100644 --- a/src/query-builder/update-query-builder.ts +++ b/src/query-builder/update-query-builder.ts @@ -132,6 +132,59 @@ export class UpdateQueryBuilder }) } + /** + * Adds a `top` clause to the query. + * + * This clause is only supported by some dialects like MS SQL Server. + * + * ### Examples + * + * Update the first row: + * + * ```ts + * await db.updateTable('person') + * .top(1) + * .set({ first_name: 'Foo' }) + * .where('age', '>', 18) + * .executeTakeFirstOrThrow() + * ``` + * + * The generated SQL (MS SQL Server): + * + * ```sql + * update top(1) "person" set "first_name" = @1 where "age" > @2 + * ``` + * + * Update the 50% first rows: + * + * ```ts + * await db.updateTable('person') + * .top(50, 'percent') + * .set({ first_name: 'Foo' }) + * .where('age', '>', 18) + * .executeTakeFirstOrThrow() + * ``` + * + * The generated SQL (MS SQL Server): + * + * ```sql + * update top(50) percent "person" set "first_name" = @1 where "age" > @2 + * ``` + */ + top( + expression: number | bigint, + modifiers?: 'percent' + ): UpdateQueryBuilder { + return new UpdateQueryBuilder({ + ...this.#props, + queryNode: QueryNode.cloneWithTop( + this.#props.queryNode, + expression, + modifiers + ), + }) + } + /** * Adds a from clause to the update query. * diff --git a/src/query-compiler/default-query-compiler.ts b/src/query-compiler/default-query-compiler.ts index ef2630176..c466cfe2c 100644 --- a/src/query-compiler/default-query-compiler.ts +++ b/src/query-compiler/default-query-compiler.ts @@ -727,6 +727,12 @@ export class DefaultQueryCompiler } this.append('update ') + + if (node.top) { + this.visitNode(node.top) + this.append(' ') + } + this.visitNode(node.table) this.append(' set ') diff --git a/test/node/src/delete.test.ts b/test/node/src/delete.test.ts index 352c21e5a..483bf38af 100644 --- a/test/node/src/delete.test.ts +++ b/test/node/src/delete.test.ts @@ -869,7 +869,7 @@ for (const dialect of DIALECTS) { } if (dialect === 'mssql') { - it('should delete first row', async () => { + it('should delete top', async () => { const query = ctx.db .deleteFrom('person') .top(1) @@ -891,7 +891,7 @@ for (const dialect of DIALECTS) { expect(result.numDeletedRows).to.equal(1n) }) - it('should delete first 50% rows', async () => { + it('should delete top percent', async () => { const query = ctx.db .deleteFrom('person') .top(50, 'percent') diff --git a/test/node/src/update.test.ts b/test/node/src/update.test.ts index 4b5f75030..e75387e5e 100644 --- a/test/node/src/update.test.ts +++ b/test/node/src/update.test.ts @@ -639,6 +639,46 @@ for (const dialect of DIALECTS) { expect(pet.person_name).to.equal(pet.pet_name) } }) + + it('should update top', async () => { + const query = ctx.db + .updateTable('pet') + .top(1) + .set({ name: 'Lucky' }) + .where('species', '=', 'dog') + + testSql(query, dialect, { + postgres: NOT_SUPPORTED, + mysql: NOT_SUPPORTED, + mssql: { + sql: 'update top(1) "pet" set "name" = @1 where "species" = @2', + parameters: ['Lucky', 'dog'], + }, + sqlite: NOT_SUPPORTED, + }) + + await query.execute() + }) + + it('should update top percent', async () => { + const query = ctx.db + .updateTable('pet') + .top(50, 'percent') + .set({ name: 'Lucky' }) + .where('species', '=', 'dog') + + testSql(query, dialect, { + postgres: NOT_SUPPORTED, + mysql: NOT_SUPPORTED, + mssql: { + sql: 'update top(50) percent "pet" set "name" = @1 where "species" = @2', + parameters: ['Lucky', 'dog'], + }, + sqlite: NOT_SUPPORTED, + }) + + await query.execute() + }) } }) } From d26ac31dd3a51d706da4c310bfe785076c991660 Mon Sep 17 00:00:00 2001 From: igalklebanov Date: Fri, 29 Dec 2023 23:21:38 +0200 Subject: [PATCH 09/18] add to insert query builder. --- src/operation-node/insert-query-node.ts | 2 + .../operation-node-transformer.ts | 1 + src/query-builder/delete-query-builder.ts | 4 +- src/query-builder/insert-query-builder.ts | 57 +++++++++++++++++++ src/query-builder/select-query-builder.ts | 2 +- src/query-builder/update-query-builder.ts | 4 +- src/query-compiler/default-query-compiler.ts | 5 ++ test/node/src/insert.test.ts | 46 +++++++++++++++ 8 files changed, 116 insertions(+), 5 deletions(-) diff --git a/src/operation-node/insert-query-node.ts b/src/operation-node/insert-query-node.ts index eb6553b96..936c9b6a0 100644 --- a/src/operation-node/insert-query-node.ts +++ b/src/operation-node/insert-query-node.ts @@ -6,6 +6,7 @@ import { OnDuplicateKeyNode } from './on-duplicate-key-node.js' import { OperationNode } from './operation-node.js' import { ReturningNode } from './returning-node.js' import { TableNode } from './table-node.js' +import { TopNode } from './top-node.js' import { WithNode } from './with-node.js' export type InsertQueryNodeProps = Omit @@ -22,6 +23,7 @@ export interface InsertQueryNode extends OperationNode { readonly ignore?: boolean readonly replace?: boolean readonly explain?: ExplainNode + readonly top?: TopNode } /** diff --git a/src/operation-node/operation-node-transformer.ts b/src/operation-node/operation-node-transformer.ts index b6d6bf57f..bbfb421f5 100644 --- a/src/operation-node/operation-node-transformer.ts +++ b/src/operation-node/operation-node-transformer.ts @@ -373,6 +373,7 @@ export class OperationNodeTransformer { ignore: node.ignore, replace: node.replace, explain: this.transformNode(node.explain), + top: this.transformNode(node.top), }) } diff --git a/src/query-builder/delete-query-builder.ts b/src/query-builder/delete-query-builder.ts index 8cdeb77cf..79cc84b9d 100644 --- a/src/query-builder/delete-query-builder.ts +++ b/src/query-builder/delete-query-builder.ts @@ -132,9 +132,9 @@ export class DeleteQueryBuilder } /** - * Adds a `top` clause to the query. + * Changes a `delete from` query into a `delete top from` query. * - * This clause is only supported by some dialects like MS SQL Server. + * `top` clause is only supported by some dialects like MS SQL Server. * * ### Examples * diff --git a/src/query-builder/insert-query-builder.ts b/src/query-builder/insert-query-builder.ts index 46ec4c0ce..2be48c981 100644 --- a/src/query-builder/insert-query-builder.ts +++ b/src/query-builder/insert-query-builder.ts @@ -357,6 +357,63 @@ export class InsertQueryBuilder }) } + /** + * Changes an `insert into` query to an `insert top into` query. + * + * `top` clause is only supported by some dialects like MS SQL Server. + * + * ### Examples + * + * Insert the first 5 rows: + * + * ```ts + * await db.insertInto('person') + * .top(5) + * .columns(['first_name', 'gender']) + * .expression( + * (eb) => eb.selectFrom('pet').select(['name', sql.lit('other').as('gender')]) + * ) + * .execute() + * ``` + * + * The generated SQL (MS SQL Server): + * + * ```sql + * insert top(5) into "person" ("first_name", "gender") select "name", 'other' as "gender" from "pet" + * ``` + * + * Insert the first 50 percent of rows: + * + * ```ts + * await db.insertInto('person') + * .top(50, 'percent') + * .columns(['first_name', 'gender']) + * .expression( + * (eb) => eb.selectFrom('pet').select(['name', sql.lit('other').as('gender')]) + * ) + * .execute() + * ``` + * + * The generated SQL (MS SQL Server): + * + * ```sql + * insert top(50) percent into "person" ("first_name", "gender") select "name", 'other' as "gender" from "pet" + * ``` + */ + top( + expression: number | bigint, + modifiers?: 'percent' + ): InsertQueryBuilder { + return new InsertQueryBuilder({ + ...this.#props, + queryNode: QueryNode.cloneWithTop( + this.#props.queryNode, + expression, + modifiers + ), + }) + } + /** * Adds an `on conflict` clause to the query. * diff --git a/src/query-builder/select-query-builder.ts b/src/query-builder/select-query-builder.ts index 63808889f..1d0ab5c2e 100644 --- a/src/query-builder/select-query-builder.ts +++ b/src/query-builder/select-query-builder.ts @@ -1080,7 +1080,7 @@ export interface SelectQueryBuilder offset(offset: number): SelectQueryBuilder /** - * Adds a top clause to the query. + * Adds a `top` clause to the query. * * This clause is only supported by some dialects like MS SQL Server. * diff --git a/src/query-builder/update-query-builder.ts b/src/query-builder/update-query-builder.ts index dcb3316f9..e12f64f3a 100644 --- a/src/query-builder/update-query-builder.ts +++ b/src/query-builder/update-query-builder.ts @@ -133,9 +133,9 @@ export class UpdateQueryBuilder } /** - * Adds a `top` clause to the query. + * Changes an `update` query into a `update top` query. * - * This clause is only supported by some dialects like MS SQL Server. + * `top` clause is only supported by some dialects like MS SQL Server. * * ### Examples * diff --git a/src/query-compiler/default-query-compiler.ts b/src/query-compiler/default-query-compiler.ts index c466cfe2c..fef96021e 100644 --- a/src/query-compiler/default-query-compiler.ts +++ b/src/query-compiler/default-query-compiler.ts @@ -302,6 +302,11 @@ export class DefaultQueryCompiler this.append(' ignore') } + if (node.top) { + this.append(' ') + this.visitNode(node.top) + } + this.append(' into ') this.visitNode(node.into) diff --git a/test/node/src/insert.test.ts b/test/node/src/insert.test.ts index ed32f4136..d96f11e55 100644 --- a/test/node/src/insert.test.ts +++ b/test/node/src/insert.test.ts @@ -880,6 +880,52 @@ for (const dialect of DIALECTS) { expect(people).to.eql(values) }) } + + if (dialect === 'mssql') { + it('should insert top', async () => { + const query = ctx.db + .insertInto('person') + .top(1) + .columns(['first_name', 'gender']) + .expression((eb) => + eb.selectFrom('pet').select(['name', eb.val('other').as('gender')]) + ) + + testSql(query, dialect, { + postgres: NOT_SUPPORTED, + mysql: NOT_SUPPORTED, + mssql: { + sql: 'insert top(1) into "person" ("first_name", "gender") select "name", @1 as "gender" from "pet"', + parameters: ['other'], + }, + sqlite: NOT_SUPPORTED, + }) + + await query.executeTakeFirstOrThrow() + }) + + it('should insert top percent', async () => { + const query = ctx.db + .insertInto('person') + .top(50, 'percent') + .columns(['first_name', 'gender']) + .expression((eb) => + eb.selectFrom('pet').select(['name', eb.val('other').as('gender')]) + ) + + testSql(query, dialect, { + postgres: NOT_SUPPORTED, + mysql: NOT_SUPPORTED, + mssql: { + sql: 'insert top(50) percent into "person" ("first_name", "gender") select "name", @1 as "gender" from "pet"', + parameters: ['other'], + }, + sqlite: NOT_SUPPORTED, + }) + + await query.executeTakeFirstOrThrow() + }) + } }) async function getNewestPerson( From eea88a958f482eef75c1e0d3c5f1ede2c3439135 Mon Sep 17 00:00:00 2001 From: igalklebanov Date: Fri, 29 Dec 2023 23:46:40 +0200 Subject: [PATCH 10/18] removed unused cloneWithTop. --- src/operation-node/delete-query-node.ts | 7 ------ src/operation-node/select-query-node.ts | 29 ++++++++++--------------- src/operation-node/update-query-node.ts | 7 ------ 3 files changed, 11 insertions(+), 32 deletions(-) diff --git a/src/operation-node/delete-query-node.ts b/src/operation-node/delete-query-node.ts index 5be7e29b9..bcd8b536c 100644 --- a/src/operation-node/delete-query-node.ts +++ b/src/operation-node/delete-query-node.ts @@ -76,11 +76,4 @@ export const DeleteQueryNode = freeze({ : UsingNode.create(tables), }) }, - - cloneWithTop(deleteNode: DeleteQueryNode, top: TopNode): DeleteQueryNode { - return freeze({ - ...deleteNode, - top, - }) - }, }) diff --git a/src/operation-node/select-query-node.ts b/src/operation-node/select-query-node.ts index 2d239e6ce..ae6bd0590 100644 --- a/src/operation-node/select-query-node.ts +++ b/src/operation-node/select-query-node.ts @@ -54,7 +54,7 @@ export const SelectQueryNode = freeze({ createFrom( fromItems: ReadonlyArray, - withNode?: WithNode, + withNode?: WithNode ): SelectQueryNode { return freeze({ kind: 'SelectQueryNode', @@ -65,7 +65,7 @@ export const SelectQueryNode = freeze({ cloneWithSelections( select: SelectQueryNode, - selections: ReadonlyArray, + selections: ReadonlyArray ): SelectQueryNode { return freeze({ ...select, @@ -77,7 +77,7 @@ export const SelectQueryNode = freeze({ cloneWithDistinctOn( select: SelectQueryNode, - expressions: ReadonlyArray, + expressions: ReadonlyArray ): SelectQueryNode { return freeze({ ...select, @@ -89,7 +89,7 @@ export const SelectQueryNode = freeze({ cloneWithFrontModifier( select: SelectQueryNode, - modifier: SelectModifierNode, + modifier: SelectModifierNode ): SelectQueryNode { return freeze({ ...select, @@ -101,7 +101,7 @@ export const SelectQueryNode = freeze({ cloneWithEndModifier( select: SelectQueryNode, - modifier: SelectModifierNode, + modifier: SelectModifierNode ): SelectQueryNode { return freeze({ ...select, @@ -113,7 +113,7 @@ export const SelectQueryNode = freeze({ cloneWithOrderByItems( selectNode: SelectQueryNode, - items: ReadonlyArray, + items: ReadonlyArray ): SelectQueryNode { return freeze({ ...selectNode, @@ -125,7 +125,7 @@ export const SelectQueryNode = freeze({ cloneWithGroupByItems( selectNode: SelectQueryNode, - items: ReadonlyArray, + items: ReadonlyArray ): SelectQueryNode { return freeze({ ...selectNode, @@ -137,7 +137,7 @@ export const SelectQueryNode = freeze({ cloneWithLimit( selectNode: SelectQueryNode, - limit: LimitNode, + limit: LimitNode ): SelectQueryNode { return freeze({ ...selectNode, @@ -147,7 +147,7 @@ export const SelectQueryNode = freeze({ cloneWithOffset( selectNode: SelectQueryNode, - offset: OffsetNode, + offset: OffsetNode ): SelectQueryNode { return freeze({ ...selectNode, @@ -157,7 +157,7 @@ export const SelectQueryNode = freeze({ cloneWithHaving( selectNode: SelectQueryNode, - operation: OperationNode, + operation: OperationNode ): SelectQueryNode { return freeze({ ...selectNode, @@ -169,7 +169,7 @@ export const SelectQueryNode = freeze({ cloneWithSetOperations( selectNode: SelectQueryNode, - setOperations: ReadonlyArray, + setOperations: ReadonlyArray ): SelectQueryNode { return freeze({ ...selectNode, @@ -179,13 +179,6 @@ export const SelectQueryNode = freeze({ }) }, - cloneWithTop(selectNode: SelectQueryNode, top: TopNode): SelectQueryNode { - return freeze({ - ...selectNode, - top, - }) - }, - cloneWithoutSelections(select: SelectQueryNode): SelectQueryNode { return freeze({ ...select, diff --git a/src/operation-node/update-query-node.ts b/src/operation-node/update-query-node.ts index 3500a5d7d..88cef1382 100644 --- a/src/operation-node/update-query-node.ts +++ b/src/operation-node/update-query-node.ts @@ -65,11 +65,4 @@ export const UpdateQueryNode = freeze({ : updates, }) }, - - cloneWithTop(updateQuery: UpdateQueryNode, top: TopNode): UpdateQueryNode { - return freeze({ - ...updateQuery, - top, - }) - }, }) From 7199c12130b36d9a3a05c2a2afa0d49d9d45ef7d Mon Sep 17 00:00:00 2001 From: igalklebanov Date: Thu, 22 Feb 2024 00:29:10 +0200 Subject: [PATCH 11/18] add top-parser. --- src/operation-node/query-node.ts | 12 +- src/parser/top-parser.ts | 25 ++ src/query-builder/delete-query-builder.ts | 186 ++++++------ src/query-builder/insert-query-builder.ts | 54 ++-- src/query-builder/select-query-builder.ts | 334 +++++++++++----------- src/query-builder/update-query-builder.ts | 190 ++++++------ 6 files changed, 413 insertions(+), 388 deletions(-) create mode 100644 src/parser/top-parser.ts diff --git a/src/operation-node/query-node.ts b/src/operation-node/query-node.ts index ba3307bea..935df9ef3 100644 --- a/src/operation-node/query-node.ts +++ b/src/operation-node/query-node.ts @@ -59,7 +59,7 @@ export const QueryNode = freeze({ cloneWithReturning( node: T, - selections: ReadonlyArray, + selections: ReadonlyArray ): T { return freeze({ ...node, @@ -86,7 +86,7 @@ export const QueryNode = freeze({ cloneWithExplain( node: T, format: ExplainFormat | undefined, - options: Expression | undefined, + options: Expression | undefined ): T { return freeze({ ...node, @@ -94,14 +94,10 @@ export const QueryNode = freeze({ }) }, - cloneWithTop( - node: T, - expression: number | bigint, - modifiers?: TopModifier - ): T { + cloneWithTop(node: T, top: TopNode): T { return freeze({ ...node, - top: TopNode.create(expression, modifiers), + top, }) }, }) diff --git a/src/parser/top-parser.ts b/src/parser/top-parser.ts new file mode 100644 index 000000000..5643adc9f --- /dev/null +++ b/src/parser/top-parser.ts @@ -0,0 +1,25 @@ +import { TopModifier, TopNode } from '../operation-node/top-node' +import { isBigInt, isNumber, isString } from '../util/object-utils' + +export function parseTop( + expression: number | bigint, + modifiers?: TopModifier +): TopNode { + if (!isNumber(expression) && !isBigInt(expression)) { + throw new Error(`Invalid top expression: ${expression}`) + } + + if (!isString(modifiers) || !isTopModifiers(modifiers)) { + throw new Error(`Invalid top modifiers: ${modifiers}`) + } + + return TopNode.create(expression, modifiers) +} + +function isTopModifiers(modifiers: string): modifiers is TopModifier { + return ( + modifiers === 'percent' || + modifiers === 'with ties' || + modifiers === 'percent with ties' + ) +} diff --git a/src/query-builder/delete-query-builder.ts b/src/query-builder/delete-query-builder.ts index 64eec1d34..efd1713ff 100644 --- a/src/query-builder/delete-query-builder.ts +++ b/src/query-builder/delete-query-builder.ts @@ -72,6 +72,7 @@ import { parseValueExpression, } from '../parser/value-parser.js' import { TopNode } from '../operation-node/top-node.js' +import { parseTop } from '../parser/top-parser.js' export class DeleteQueryBuilder implements @@ -90,15 +91,15 @@ export class DeleteQueryBuilder where< RE extends ReferenceExpression, - VE extends OperandValueExpressionOrList, + VE extends OperandValueExpressionOrList >( lhs: RE, op: ComparisonOperatorExpression, - rhs: VE, + rhs: VE ): DeleteQueryBuilder where>( - expression: E, + expression: E ): DeleteQueryBuilder where(...args: any[]): any { @@ -106,24 +107,24 @@ export class DeleteQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithWhere( this.#props.queryNode, - parseValueBinaryOperationOrExpression(args), + parseValueBinaryOperationOrExpression(args) ), }) } whereRef< LRE extends ReferenceExpression, - RRE extends ReferenceExpression, + RRE extends ReferenceExpression >( lhs: LRE, op: ComparisonOperatorExpression, - rhs: RRE, + rhs: RRE ): DeleteQueryBuilder { return new DeleteQueryBuilder({ ...this.#props, queryNode: QueryNode.cloneWithWhere( this.#props.queryNode, - parseReferentialBinaryOperation(lhs, op, rhs), + parseReferentialBinaryOperation(lhs, op, rhs) ), }) } @@ -175,12 +176,15 @@ export class DeleteQueryBuilder * ``` */ top( - top: number | bigint, + expression: number | bigint, modifiers?: 'percent' ): DeleteQueryBuilder { return new DeleteQueryBuilder({ ...this.#props, - queryNode: QueryNode.cloneWithTop(this.#props.queryNode, top, modifiers), + queryNode: QueryNode.cloneWithTop( + this.#props.queryNode, + parseTop(expression, modifiers) + ), }) } @@ -259,11 +263,11 @@ export class DeleteQueryBuilder * ``` */ using>( - tables: TE[], + tables: TE[] ): DeleteQueryBuilder, FromTables, O> using>( - table: TE, + table: TE ): DeleteQueryBuilder, FromTables, O> using(tables: TableExpressionOrList): any { @@ -271,7 +275,7 @@ export class DeleteQueryBuilder ...this.#props, queryNode: DeleteQueryNode.cloneWithUsing( this.#props.queryNode, - parseTableExpressionOrList(tables), + parseTableExpressionOrList(tables) ), }) } @@ -388,12 +392,12 @@ export class DeleteQueryBuilder innerJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression, + K2 extends JoinReferenceExpression >(table: TE, k1: K1, k2: K2): DeleteQueryBuilderWithInnerJoin innerJoin< TE extends TableExpression, - FN extends JoinCallbackExpression, + FN extends JoinCallbackExpression >(table: TE, callback: FN): DeleteQueryBuilderWithInnerJoin innerJoin(...args: any): any { @@ -401,7 +405,7 @@ export class DeleteQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('InnerJoin', args), + parseJoin('InnerJoin', args) ), }) } @@ -412,12 +416,12 @@ export class DeleteQueryBuilder leftJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression, + K2 extends JoinReferenceExpression >(table: TE, k1: K1, k2: K2): DeleteQueryBuilderWithLeftJoin leftJoin< TE extends TableExpression, - FN extends JoinCallbackExpression, + FN extends JoinCallbackExpression >(table: TE, callback: FN): DeleteQueryBuilderWithLeftJoin leftJoin(...args: any): any { @@ -425,7 +429,7 @@ export class DeleteQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('LeftJoin', args), + parseJoin('LeftJoin', args) ), }) } @@ -436,12 +440,12 @@ export class DeleteQueryBuilder rightJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression, + K2 extends JoinReferenceExpression >(table: TE, k1: K1, k2: K2): DeleteQueryBuilderWithRightJoin rightJoin< TE extends TableExpression, - FN extends JoinCallbackExpression, + FN extends JoinCallbackExpression >(table: TE, callback: FN): DeleteQueryBuilderWithRightJoin rightJoin(...args: any): any { @@ -449,7 +453,7 @@ export class DeleteQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('RightJoin', args), + parseJoin('RightJoin', args) ), }) } @@ -460,12 +464,12 @@ export class DeleteQueryBuilder fullJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression, + K2 extends JoinReferenceExpression >(table: TE, k1: K1, k2: K2): DeleteQueryBuilderWithFullJoin fullJoin< TE extends TableExpression, - FN extends JoinCallbackExpression, + FN extends JoinCallbackExpression >(table: TE, callback: FN): DeleteQueryBuilderWithFullJoin fullJoin(...args: any): any { @@ -473,31 +477,31 @@ export class DeleteQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('FullJoin', args), + parseJoin('FullJoin', args) ), }) } returning>( - selections: ReadonlyArray, + selections: ReadonlyArray ): DeleteQueryBuilder> returning>( - callback: CB, + callback: CB ): DeleteQueryBuilder> returning>( - selection: SE, + selection: SE ): DeleteQueryBuilder> returning>( - selection: SelectArg, + selection: SelectArg ): DeleteQueryBuilder> { return new DeleteQueryBuilder({ ...this.#props, queryNode: QueryNode.cloneWithReturning( this.#props.queryNode, - parseSelectArg(selection), + parseSelectArg(selection) ), }) } @@ -595,11 +599,11 @@ export class DeleteQueryBuilder * ``` */ returningAll( - tables: ReadonlyArray, + tables: ReadonlyArray ): DeleteQueryBuilder> returningAll( - table: T, + table: T ): DeleteQueryBuilder> returningAll(): DeleteQueryBuilder> @@ -609,7 +613,7 @@ export class DeleteQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithReturning( this.#props.queryNode, - parseSelectAll(table), + parseSelectAll(table) ), }) } @@ -727,13 +731,13 @@ export class DeleteQueryBuilder */ orderBy( orderBy: OrderByExpression, - direction?: OrderByDirectionExpression, + direction?: OrderByDirectionExpression ): DeleteQueryBuilder { return new DeleteQueryBuilder({ ...this.#props, queryNode: DeleteQueryNode.cloneWithOrderByItems( this.#props.queryNode, - parseOrderBy([orderBy, direction]), + parseOrderBy([orderBy, direction]) ), }) } @@ -761,7 +765,7 @@ export class DeleteQueryBuilder ...this.#props, queryNode: DeleteQueryNode.cloneWithLimit( this.#props.queryNode, - LimitNode.create(parseValueExpression(limit)), + LimitNode.create(parseValueExpression(limit)) ), }) } @@ -829,12 +833,12 @@ export class DeleteQueryBuilder */ $if( condition: boolean, - func: (qb: this) => DeleteQueryBuilder, + func: (qb: this) => DeleteQueryBuilder ): O2 extends DeleteResult ? DeleteQueryBuilder : O2 extends O & infer E - ? DeleteQueryBuilder> - : DeleteQueryBuilder> { + ? DeleteQueryBuilder> + : DeleteQueryBuilder> { if (condition) { return func(this) as any } @@ -959,14 +963,14 @@ export class DeleteQueryBuilder toOperationNode(): DeleteQueryNode { return this.#props.executor.transformQuery( this.#props.queryNode, - this.#props.queryId, + this.#props.queryId ) } compile(): CompiledQuery> { return this.#props.executor.compileQuery( this.toOperationNode(), - this.#props.queryId, + this.#props.queryId ) } @@ -981,7 +985,7 @@ export class DeleteQueryBuilder const result = await this.#props.executor.executeQuery( compiledQuery, - this.#props.queryId, + this.#props.queryId ) if (this.#props.executor.adapter.supportsReturning && query.returning) { @@ -991,7 +995,7 @@ export class DeleteQueryBuilder return [ new DeleteResult( // TODO: remove numUpdatedOrDeletedRows. - result.numAffectedRows ?? result.numUpdatedOrDeletedRows ?? BigInt(0), + result.numAffectedRows ?? result.numUpdatedOrDeletedRows ?? BigInt(0) ) as any, ] } @@ -1016,7 +1020,7 @@ export class DeleteQueryBuilder async executeTakeFirstOrThrow( errorConstructor: | NoResultErrorConstructor - | ((node: QueryNode) => Error) = NoResultError, + | ((node: QueryNode) => Error) = NoResultError ): Promise> { const result = await this.executeTakeFirst() @@ -1037,7 +1041,7 @@ export class DeleteQueryBuilder const stream = this.#props.executor.stream( compiledQuery, chunkSize, - this.#props.queryId, + this.#props.queryId ) for await (const item of stream) { @@ -1047,14 +1051,14 @@ export class DeleteQueryBuilder async explain = Record>( format?: ExplainFormat, - options?: Expression, + options?: Expression ): Promise { const builder = new DeleteQueryBuilder({ ...this.#props, queryNode: QueryNode.cloneWithExplain( this.#props.queryNode, format, - options, + options ), }) @@ -1064,7 +1068,7 @@ export class DeleteQueryBuilder preventAwait( DeleteQueryBuilder, - "don't await DeleteQueryBuilder instances directly. To execute the query you need to call `execute` or `executeTakeFirst`.", + "don't await DeleteQueryBuilder instances directly. To execute the query you need to call `execute` or `executeTakeFirst`." ) export interface DeleteQueryBuilderProps { @@ -1077,25 +1081,25 @@ export type DeleteQueryBuilderWithInnerJoin< DB, TB extends keyof DB, O, - TE extends TableExpression, + TE extends TableExpression > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? InnerJoinedBuilder : never : TE extends keyof DB - ? DeleteQueryBuilder - : TE extends AliasedExpression - ? InnerJoinedBuilder - : TE extends (qb: any) => AliasedExpression - ? InnerJoinedBuilder - : never + ? DeleteQueryBuilder + : TE extends AliasedExpression + ? InnerJoinedBuilder + : TE extends (qb: any) => AliasedExpression + ? InnerJoinedBuilder + : never type InnerJoinedBuilder< DB, TB extends keyof DB, O, A extends string, - R, + R > = A extends keyof DB ? DeleteQueryBuilder, TB | A, O> : // Much faster non-recursive solution for the simple case. @@ -1109,25 +1113,25 @@ export type DeleteQueryBuilderWithLeftJoin< DB, TB extends keyof DB, O, - TE extends TableExpression, + TE extends TableExpression > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? LeftJoinedBuilder : never : TE extends keyof DB - ? LeftJoinedBuilder - : TE extends AliasedExpression - ? LeftJoinedBuilder - : TE extends (qb: any) => AliasedExpression - ? LeftJoinedBuilder - : never + ? LeftJoinedBuilder + : TE extends AliasedExpression + ? LeftJoinedBuilder + : TE extends (qb: any) => AliasedExpression + ? LeftJoinedBuilder + : never type LeftJoinedBuilder< DB, TB extends keyof DB, O, A extends keyof any, - R, + R > = A extends keyof DB ? DeleteQueryBuilder, TB | A, O> : // Much faster non-recursive solution for the simple case. @@ -1137,86 +1141,86 @@ type LeftJoinedDB = DrainOuterGeneric<{ [C in keyof DB | A]: C extends A ? Nullable : C extends keyof DB - ? DB[C] - : never + ? DB[C] + : never }> export type DeleteQueryBuilderWithRightJoin< DB, TB extends keyof DB, O, - TE extends TableExpression, + TE extends TableExpression > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? RightJoinedBuilder : never : TE extends keyof DB - ? RightJoinedBuilder - : TE extends AliasedExpression - ? RightJoinedBuilder - : TE extends (qb: any) => AliasedExpression - ? RightJoinedBuilder - : never + ? RightJoinedBuilder + : TE extends AliasedExpression + ? RightJoinedBuilder + : TE extends (qb: any) => AliasedExpression + ? RightJoinedBuilder + : never type RightJoinedBuilder< DB, TB extends keyof DB, O, A extends keyof any, - R, + R > = DeleteQueryBuilder, TB | A, O> type RightJoinedDB< DB, TB extends keyof DB, A extends keyof any, - R, + R > = DrainOuterGeneric<{ [C in keyof DB | A]: C extends A ? R : C extends TB - ? Nullable - : C extends keyof DB - ? DB[C] - : never + ? Nullable + : C extends keyof DB + ? DB[C] + : never }> export type DeleteQueryBuilderWithFullJoin< DB, TB extends keyof DB, O, - TE extends TableExpression, + TE extends TableExpression > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? OuterJoinedBuilder : never : TE extends keyof DB - ? OuterJoinedBuilder - : TE extends AliasedExpression - ? OuterJoinedBuilder - : TE extends (qb: any) => AliasedExpression - ? OuterJoinedBuilder - : never + ? OuterJoinedBuilder + : TE extends AliasedExpression + ? OuterJoinedBuilder + : TE extends (qb: any) => AliasedExpression + ? OuterJoinedBuilder + : never type OuterJoinedBuilder< DB, TB extends keyof DB, O, A extends keyof any, - R, + R > = DeleteQueryBuilder, TB | A, O> type OuterJoinedBuilderDB< DB, TB extends keyof DB, A extends keyof any, - R, + R > = DrainOuterGeneric<{ [C in keyof DB | A]: C extends A ? Nullable : C extends TB - ? Nullable - : C extends keyof DB - ? DB[C] - : never + ? Nullable + : C extends keyof DB + ? DB[C] + : never }> diff --git a/src/query-builder/insert-query-builder.ts b/src/query-builder/insert-query-builder.ts index 65377eedb..1b62bc488 100644 --- a/src/query-builder/insert-query-builder.ts +++ b/src/query-builder/insert-query-builder.ts @@ -58,6 +58,7 @@ import { Explainable, ExplainFormat } from '../util/explainable.js' import { Expression } from '../expression/expression.js' import { KyselyTypeError } from '../util/type-error.js' import { Streamable } from '../util/streamable.js' +import { parseTop } from '../parser/top-parser.js' export class InsertQueryBuilder implements @@ -268,7 +269,7 @@ export class InsertQueryBuilder * ``` */ columns( - columns: ReadonlyArray, + columns: ReadonlyArray ): InsertQueryBuilder { return new InsertQueryBuilder({ ...this.#props, @@ -309,7 +310,7 @@ export class InsertQueryBuilder * ``` */ expression( - expression: ExpressionOrFactory, + expression: ExpressionOrFactory ): InsertQueryBuilder { return new InsertQueryBuilder({ ...this.#props, @@ -420,8 +421,7 @@ export class InsertQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithTop( this.#props.queryNode, - expression, - modifiers + parseTop(expression, modifiers) ), }) } @@ -579,13 +579,13 @@ export class InsertQueryBuilder */ onConflict( callback: ( - builder: OnConflictBuilder, + builder: OnConflictBuilder ) => | OnConflictUpdateBuilder< OnConflictDatabase, OnConflictTables > - | OnConflictDoNothingBuilder, + | OnConflictDoNothingBuilder ): InsertQueryBuilder { return new InsertQueryBuilder({ ...this.#props, @@ -593,7 +593,7 @@ export class InsertQueryBuilder onConflict: callback( new OnConflictBuilder({ onConflictNode: OnConflictNode.create(), - }), + }) ).toOperationNode(), }), }) @@ -618,38 +618,38 @@ export class InsertQueryBuilder * ``` */ onDuplicateKeyUpdate( - update: UpdateObjectExpression, + update: UpdateObjectExpression ): InsertQueryBuilder { return new InsertQueryBuilder({ ...this.#props, queryNode: InsertQueryNode.cloneWith(this.#props.queryNode, { onDuplicateKey: OnDuplicateKeyNode.create( - parseUpdateObjectExpression(update), + parseUpdateObjectExpression(update) ), }), }) } returning>( - selections: ReadonlyArray, + selections: ReadonlyArray ): InsertQueryBuilder> returning>( - callback: CB, + callback: CB ): InsertQueryBuilder> returning>( - selection: SE, + selection: SE ): InsertQueryBuilder> returning>( - selection: SelectArg, + selection: SelectArg ): InsertQueryBuilder> { return new InsertQueryBuilder({ ...this.#props, queryNode: QueryNode.cloneWithReturning( this.#props.queryNode, - parseSelectArg(selection), + parseSelectArg(selection) ), }) } @@ -659,7 +659,7 @@ export class InsertQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithReturning( this.#props.queryNode, - parseSelectAll(), + parseSelectAll() ), }) } @@ -753,12 +753,12 @@ export class InsertQueryBuilder */ $if( condition: boolean, - func: (qb: this) => InsertQueryBuilder, + func: (qb: this) => InsertQueryBuilder ): O2 extends InsertResult ? InsertQueryBuilder : O2 extends O & infer E - ? InsertQueryBuilder> - : InsertQueryBuilder> { + ? InsertQueryBuilder> + : InsertQueryBuilder> { if (condition) { return func(this) as any } @@ -882,14 +882,14 @@ export class InsertQueryBuilder toOperationNode(): InsertQueryNode { return this.#props.executor.transformQuery( this.#props.queryNode, - this.#props.queryId, + this.#props.queryId ) } compile(): CompiledQuery { return this.#props.executor.compileQuery( this.toOperationNode(), - this.#props.queryId, + this.#props.queryId ) } @@ -904,7 +904,7 @@ export class InsertQueryBuilder const result = await this.#props.executor.executeQuery( compiledQuery, - this.#props.queryId, + this.#props.queryId ) if (this.#props.executor.adapter.supportsReturning && query.returning) { @@ -915,7 +915,7 @@ export class InsertQueryBuilder new InsertResult( result.insertId, // TODO: remove numUpdatedOrDeletedRows. - result.numAffectedRows ?? result.numUpdatedOrDeletedRows, + result.numAffectedRows ?? result.numUpdatedOrDeletedRows ) as any, ] } @@ -940,7 +940,7 @@ export class InsertQueryBuilder async executeTakeFirstOrThrow( errorConstructor: | NoResultErrorConstructor - | ((node: QueryNode) => Error) = NoResultError, + | ((node: QueryNode) => Error) = NoResultError ): Promise> { const result = await this.executeTakeFirst() @@ -961,7 +961,7 @@ export class InsertQueryBuilder const stream = this.#props.executor.stream( compiledQuery, chunkSize, - this.#props.queryId, + this.#props.queryId ) for await (const item of stream) { @@ -971,14 +971,14 @@ export class InsertQueryBuilder async explain = Record>( format?: ExplainFormat, - options?: Expression, + options?: Expression ): Promise { const builder = new InsertQueryBuilder({ ...this.#props, queryNode: QueryNode.cloneWithExplain( this.#props.queryNode, format, - options, + options ), }) @@ -988,7 +988,7 @@ export class InsertQueryBuilder preventAwait( InsertQueryBuilder, - "don't await InsertQueryBuilder instances directly. To execute the query you need to call `execute` or `executeTakeFirst`.", + "don't await InsertQueryBuilder instances directly. To execute the query you need to call `execute` or `executeTakeFirst`." ) export interface InsertQueryBuilderProps { diff --git a/src/query-builder/select-query-builder.ts b/src/query-builder/select-query-builder.ts index 71c277f6d..0db13f7ec 100644 --- a/src/query-builder/select-query-builder.ts +++ b/src/query-builder/select-query-builder.ts @@ -80,6 +80,7 @@ import { parseValueExpression, } from '../parser/value-parser.js' import { TopModifier, TopNode } from '../operation-node/top-node.js' +import { parseTop } from '../parser/top-parser.js' export interface SelectQueryBuilder extends WhereInterface, @@ -90,46 +91,46 @@ export interface SelectQueryBuilder Streamable { where< RE extends ReferenceExpression, - VE extends OperandValueExpressionOrList, + VE extends OperandValueExpressionOrList >( lhs: RE, op: ComparisonOperatorExpression, - rhs: VE, + rhs: VE ): SelectQueryBuilder where>( - expression: E, + expression: E ): SelectQueryBuilder whereRef< LRE extends ReferenceExpression, - RRE extends ReferenceExpression, + RRE extends ReferenceExpression >( lhs: LRE, op: ComparisonOperatorExpression, - rhs: RRE, + rhs: RRE ): SelectQueryBuilder having< RE extends ReferenceExpression, - VE extends OperandValueExpressionOrList, + VE extends OperandValueExpressionOrList >( lhs: RE, op: ComparisonOperatorExpression, - rhs: VE, + rhs: VE ): SelectQueryBuilder having>( - expression: E, + expression: E ): SelectQueryBuilder havingRef< LRE extends ReferenceExpression, - RRE extends ReferenceExpression, + RRE extends ReferenceExpression >( lhs: LRE, op: ComparisonOperatorExpression, - rhs: RRE, + rhs: RRE ): SelectQueryBuilder /** @@ -319,15 +320,15 @@ export interface SelectQueryBuilder * ``` */ select>( - selections: ReadonlyArray, + selections: ReadonlyArray ): SelectQueryBuilder> select>( - callback: CB, + callback: CB ): SelectQueryBuilder> select>( - selection: SE, + selection: SE ): SelectQueryBuilder> /** @@ -356,11 +357,11 @@ export interface SelectQueryBuilder * ``` */ distinctOn>( - selections: ReadonlyArray, + selections: ReadonlyArray ): SelectQueryBuilder distinctOn>( - selection: RE, + selection: RE ): SelectQueryBuilder /** @@ -516,11 +517,11 @@ export interface SelectQueryBuilder * ``` */ selectAll( - table: ReadonlyArray, + table: ReadonlyArray ): SelectQueryBuilder> selectAll( - table: T, + table: T ): SelectQueryBuilder> selectAll(): SelectQueryBuilder> @@ -645,19 +646,19 @@ export interface SelectQueryBuilder innerJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression, + K2 extends JoinReferenceExpression >( table: TE, k1: K1, - k2: K2, + k2: K2 ): SelectQueryBuilderWithInnerJoin innerJoin< TE extends TableExpression, - FN extends JoinCallbackExpression, + FN extends JoinCallbackExpression >( table: TE, - callback: FN, + callback: FN ): SelectQueryBuilderWithInnerJoin /** @@ -666,19 +667,19 @@ export interface SelectQueryBuilder leftJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression, + K2 extends JoinReferenceExpression >( table: TE, k1: K1, - k2: K2, + k2: K2 ): SelectQueryBuilderWithLeftJoin leftJoin< TE extends TableExpression, - FN extends JoinCallbackExpression, + FN extends JoinCallbackExpression >( table: TE, - callback: FN, + callback: FN ): SelectQueryBuilderWithLeftJoin /** @@ -687,19 +688,19 @@ export interface SelectQueryBuilder rightJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression, + K2 extends JoinReferenceExpression >( table: TE, k1: K1, - k2: K2, + k2: K2 ): SelectQueryBuilderWithRightJoin rightJoin< TE extends TableExpression, - FN extends JoinCallbackExpression, + FN extends JoinCallbackExpression >( table: TE, - callback: FN, + callback: FN ): SelectQueryBuilderWithRightJoin /** @@ -708,19 +709,19 @@ export interface SelectQueryBuilder fullJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression, + K2 extends JoinReferenceExpression >( table: TE, k1: K1, - k2: K2, + k2: K2 ): SelectQueryBuilderWithFullJoin fullJoin< TE extends TableExpression, - FN extends JoinCallbackExpression, + FN extends JoinCallbackExpression >( table: TE, - callback: FN, + callback: FN ): SelectQueryBuilderWithFullJoin /** @@ -745,19 +746,19 @@ export interface SelectQueryBuilder innerJoinLateral< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression, + K2 extends JoinReferenceExpression >( table: TE, k1: K1, - k2: K2, + k2: K2 ): SelectQueryBuilderWithInnerJoin innerJoinLateral< TE extends TableExpression, - FN extends JoinCallbackExpression, + FN extends JoinCallbackExpression >( table: TE, - callback: FN, + callback: FN ): SelectQueryBuilderWithInnerJoin /** @@ -781,19 +782,19 @@ export interface SelectQueryBuilder leftJoinLateral< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression, + K2 extends JoinReferenceExpression >( table: TE, k1: K1, - k2: K2, + k2: K2 ): SelectQueryBuilderWithLeftJoin leftJoinLateral< TE extends TableExpression, - FN extends JoinCallbackExpression, + FN extends JoinCallbackExpression >( table: TE, - callback: FN, + callback: FN ): SelectQueryBuilderWithLeftJoin /** @@ -909,15 +910,15 @@ export interface SelectQueryBuilder */ orderBy>( orderBy: OE, - direction?: OrderByDirectionExpression, + direction?: OrderByDirectionExpression ): SelectQueryBuilder orderBy>( - ref: OE, + ref: OE ): SelectQueryBuilder orderBy>( - refs: ReadonlyArray, + refs: ReadonlyArray ): SelectQueryBuilder /** @@ -1019,7 +1020,7 @@ export interface SelectQueryBuilder * ``` */ groupBy>( - groupBy: GE, + groupBy: GE ): SelectQueryBuilder /** @@ -1158,7 +1159,7 @@ export interface SelectQueryBuilder * ``` */ union>( - expression: E, + expression: E ): SelectQueryBuilder /** @@ -1188,7 +1189,7 @@ export interface SelectQueryBuilder * ``` */ unionAll>( - expression: E, + expression: E ): SelectQueryBuilder /** @@ -1218,7 +1219,7 @@ export interface SelectQueryBuilder * ``` */ intersect>( - expression: E, + expression: E ): SelectQueryBuilder /** @@ -1248,7 +1249,7 @@ export interface SelectQueryBuilder * ``` */ intersectAll>( - expression: E, + expression: E ): SelectQueryBuilder /** @@ -1278,7 +1279,7 @@ export interface SelectQueryBuilder * ``` */ except>( - expression: E, + expression: E ): SelectQueryBuilder /** @@ -1308,7 +1309,7 @@ export interface SelectQueryBuilder * ``` */ exceptAll>( - expression: E, + expression: E ): SelectQueryBuilder /** @@ -1507,7 +1508,7 @@ export interface SelectQueryBuilder */ $if( condition: boolean, - func: (qb: this) => SelectQueryBuilder, + func: (qb: this) => SelectQueryBuilder ): SelectQueryBuilder>> /** @@ -1564,7 +1565,7 @@ export interface SelectQueryBuilder */ $asTuple>( key1: K1, - key2: K2, + key2: K2 ): keyof O extends K1 | K2 ? ExpressionWrapper : KyselyTypeError<'$asTuple() call failed: All selected columns must be provided as arguments'> @@ -1572,11 +1573,11 @@ export interface SelectQueryBuilder $asTuple< K1 extends keyof O, K2 extends Exclude, - K3 extends Exclude, + K3 extends Exclude >( key1: K1, key2: K2, - key3: K3, + key3: K3 ): keyof O extends K1 | K2 | K3 ? ExpressionWrapper : KyselyTypeError<'$asTuple() call failed: All selected columns must be provided as arguments'> @@ -1585,12 +1586,12 @@ export interface SelectQueryBuilder K1 extends keyof O, K2 extends Exclude, K3 extends Exclude, - K4 extends Exclude, + K4 extends Exclude >( key1: K1, key2: K2, key3: K3, - key4: K4, + key4: K4 ): keyof O extends K1 | K2 | K3 | K4 ? ExpressionWrapper : KyselyTypeError<'$asTuple() call failed: All selected columns must be provided as arguments'> @@ -1600,13 +1601,13 @@ export interface SelectQueryBuilder K2 extends Exclude, K3 extends Exclude, K4 extends Exclude, - K5 extends Exclude, + K5 extends Exclude >( key1: K1, key2: K2, key3: K3, key4: K4, - key5: K5, + key5: K5 ): keyof O extends K1 | K2 | K3 | K4 | K5 ? ExpressionWrapper : KyselyTypeError<'$asTuple() call failed: All selected columns must be provided as arguments'> @@ -1743,14 +1744,14 @@ export interface SelectQueryBuilder * error. */ executeTakeFirstOrThrow( - errorConstructor?: NoResultErrorConstructor | ((node: QueryNode) => Error), + errorConstructor?: NoResultErrorConstructor | ((node: QueryNode) => Error) ): Promise> stream(chunkSize?: number): AsyncIterableIterator explain = Record>( format?: ExplainFormat, - options?: Expression, + options?: Expression ): Promise } @@ -1776,7 +1777,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: QueryNode.cloneWithWhere( this.#props.queryNode, - parseValueBinaryOperationOrExpression(args), + parseValueBinaryOperationOrExpression(args) ), }) } @@ -1784,13 +1785,13 @@ class SelectQueryBuilderImpl whereRef( lhs: ReferenceExpression, op: ComparisonOperatorExpression, - rhs: ReferenceExpression, + rhs: ReferenceExpression ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, queryNode: QueryNode.cloneWithWhere( this.#props.queryNode, - parseReferentialBinaryOperation(lhs, op, rhs), + parseReferentialBinaryOperation(lhs, op, rhs) ), }) } @@ -1800,7 +1801,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithHaving( this.#props.queryNode, - parseValueBinaryOperationOrExpression(args), + parseValueBinaryOperationOrExpression(args) ), }) } @@ -1808,25 +1809,25 @@ class SelectQueryBuilderImpl havingRef( lhs: ReferenceExpression, op: ComparisonOperatorExpression, - rhs: ReferenceExpression, + rhs: ReferenceExpression ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, queryNode: SelectQueryNode.cloneWithHaving( this.#props.queryNode, - parseReferentialBinaryOperation(lhs, op, rhs), + parseReferentialBinaryOperation(lhs, op, rhs) ), }) } select>( - selection: SelectArg, + selection: SelectArg ): SelectQueryBuilder> { return new SelectQueryBuilderImpl>({ ...this.#props, queryNode: SelectQueryNode.cloneWithSelections( this.#props.queryNode, - parseSelectArg(selection), + parseSelectArg(selection) ), }) } @@ -1836,7 +1837,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithDistinctOn( this.#props.queryNode, - parseReferenceExpressionOrList(selection), + parseReferenceExpressionOrList(selection) ), }) } @@ -1846,7 +1847,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithFrontModifier( this.#props.queryNode, - SelectModifierNode.createWithExpression(modifier.toOperationNode()), + SelectModifierNode.createWithExpression(modifier.toOperationNode()) ), }) } @@ -1856,7 +1857,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithEndModifier( this.#props.queryNode, - SelectModifierNode.createWithExpression(modifier.toOperationNode()), + SelectModifierNode.createWithExpression(modifier.toOperationNode()) ), }) } @@ -1866,7 +1867,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithFrontModifier( this.#props.queryNode, - SelectModifierNode.create('Distinct'), + SelectModifierNode.create('Distinct') ), }) } @@ -1878,8 +1879,8 @@ class SelectQueryBuilderImpl this.#props.queryNode, SelectModifierNode.create( 'ForUpdate', - of ? asArray(of).map(parseTable) : undefined, - ), + of ? asArray(of).map(parseTable) : undefined + ) ), }) } @@ -1891,8 +1892,8 @@ class SelectQueryBuilderImpl this.#props.queryNode, SelectModifierNode.create( 'ForShare', - of ? asArray(of).map(parseTable) : undefined, - ), + of ? asArray(of).map(parseTable) : undefined + ) ), }) } @@ -1904,8 +1905,8 @@ class SelectQueryBuilderImpl this.#props.queryNode, SelectModifierNode.create( 'ForKeyShare', - of ? asArray(of).map(parseTable) : undefined, - ), + of ? asArray(of).map(parseTable) : undefined + ) ), }) } @@ -1917,8 +1918,8 @@ class SelectQueryBuilderImpl this.#props.queryNode, SelectModifierNode.create( 'ForNoKeyUpdate', - of ? asArray(of).map(parseTable) : undefined, - ), + of ? asArray(of).map(parseTable) : undefined + ) ), }) } @@ -1928,7 +1929,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithEndModifier( this.#props.queryNode, - SelectModifierNode.create('SkipLocked'), + SelectModifierNode.create('SkipLocked') ), }) } @@ -1938,7 +1939,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithEndModifier( this.#props.queryNode, - SelectModifierNode.create('NoWait'), + SelectModifierNode.create('NoWait') ), }) } @@ -1948,7 +1949,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithSelections( this.#props.queryNode, - parseSelectAll(table), + parseSelectAll(table) ), }) } @@ -1958,7 +1959,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('InnerJoin', args), + parseJoin('InnerJoin', args) ), }) } @@ -1968,7 +1969,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('LeftJoin', args), + parseJoin('LeftJoin', args) ), }) } @@ -1978,7 +1979,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('RightJoin', args), + parseJoin('RightJoin', args) ), }) } @@ -1988,7 +1989,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('FullJoin', args), + parseJoin('FullJoin', args) ), }) } @@ -1998,7 +1999,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('LateralInnerJoin', args), + parseJoin('LateralInnerJoin', args) ), }) } @@ -2008,7 +2009,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('LateralLeftJoin', args), + parseJoin('LateralLeftJoin', args) ), }) } @@ -2018,7 +2019,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithOrderByItems( this.#props.queryNode, - parseOrderBy(args), + parseOrderBy(args) ), }) } @@ -2028,7 +2029,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithGroupByItems( this.#props.queryNode, - parseGroupBy(groupBy), + parseGroupBy(groupBy) ), }) } @@ -2038,19 +2039,19 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithLimit( this.#props.queryNode, - LimitNode.create(parseValueExpression(limit)), + LimitNode.create(parseValueExpression(limit)) ), }) } offset( - offset: ValueExpression, + offset: ValueExpression ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, queryNode: SelectQueryNode.cloneWithOffset( this.#props.queryNode, - OffsetNode.create(parseValueExpression(offset)), + OffsetNode.create(parseValueExpression(offset)) ), }) } @@ -2063,80 +2064,79 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: QueryNode.cloneWithTop( this.#props.queryNode, - expression, - modifiers + parseTop(expression, modifiers) ), }) } union( - expression: SetOperandExpression, + expression: SetOperandExpression ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, queryNode: SelectQueryNode.cloneWithSetOperations( this.#props.queryNode, - parseSetOperations('union', expression, false), + parseSetOperations('union', expression, false) ), }) } unionAll( - expression: SetOperandExpression, + expression: SetOperandExpression ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, queryNode: SelectQueryNode.cloneWithSetOperations( this.#props.queryNode, - parseSetOperations('union', expression, true), + parseSetOperations('union', expression, true) ), }) } intersect( - expression: SetOperandExpression, + expression: SetOperandExpression ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, queryNode: SelectQueryNode.cloneWithSetOperations( this.#props.queryNode, - parseSetOperations('intersect', expression, false), + parseSetOperations('intersect', expression, false) ), }) } intersectAll( - expression: SetOperandExpression, + expression: SetOperandExpression ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, queryNode: SelectQueryNode.cloneWithSetOperations( this.#props.queryNode, - parseSetOperations('intersect', expression, true), + parseSetOperations('intersect', expression, true) ), }) } except( - expression: SetOperandExpression, + expression: SetOperandExpression ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, queryNode: SelectQueryNode.cloneWithSetOperations( this.#props.queryNode, - parseSetOperations('except', expression, false), + parseSetOperations('except', expression, false) ), }) } exceptAll( - expression: SetOperandExpression, + expression: SetOperandExpression ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, queryNode: SelectQueryNode.cloneWithSetOperations( this.#props.queryNode, - parseSetOperations('except', expression, true), + parseSetOperations('except', expression, true) ), }) } @@ -2186,7 +2186,7 @@ class SelectQueryBuilderImpl $if( condition: boolean, - func: (qb: this) => SelectQueryBuilder, + func: (qb: this) => SelectQueryBuilder ): SelectQueryBuilder>> { if (condition) { return func(this) @@ -2225,14 +2225,14 @@ class SelectQueryBuilderImpl toOperationNode(): SelectQueryNode { return this.#props.executor.transformQuery( this.#props.queryNode, - this.#props.queryId, + this.#props.queryId ) } compile(): CompiledQuery> { return this.#props.executor.compileQuery( this.toOperationNode(), - this.#props.queryId, + this.#props.queryId ) } @@ -2241,7 +2241,7 @@ class SelectQueryBuilderImpl const result = await this.#props.executor.executeQuery( compiledQuery, - this.#props.queryId, + this.#props.queryId ) return result.rows @@ -2255,7 +2255,7 @@ class SelectQueryBuilderImpl async executeTakeFirstOrThrow( errorConstructor: | NoResultErrorConstructor - | ((node: QueryNode) => Error) = NoResultError, + | ((node: QueryNode) => Error) = NoResultError ): Promise> { const result = await this.executeTakeFirst() @@ -2276,7 +2276,7 @@ class SelectQueryBuilderImpl const stream = this.#props.executor.stream( compiledQuery, chunkSize, - this.#props.queryId, + this.#props.queryId ) for await (const item of stream) { @@ -2286,14 +2286,14 @@ class SelectQueryBuilderImpl async explain = Record>( format?: ExplainFormat, - options?: Expression, + options?: Expression ): Promise { const builder = new SelectQueryBuilderImpl({ ...this.#props, queryNode: QueryNode.cloneWithExplain( this.#props.queryNode, format, - options, + options ), }) @@ -2303,11 +2303,11 @@ class SelectQueryBuilderImpl preventAwait( SelectQueryBuilderImpl, - "don't await SelectQueryBuilder instances directly. To execute the query you need to call `execute` or `executeTakeFirst`.", + "don't await SelectQueryBuilder instances directly. To execute the query you need to call `execute` or `executeTakeFirst`." ) export function createSelectQueryBuilder( - props: SelectQueryBuilderProps, + props: SelectQueryBuilderProps ): SelectQueryBuilder { return new SelectQueryBuilderImpl(props) } @@ -2320,7 +2320,7 @@ export interface SelectQueryBuilderProps { export interface AliasedSelectQueryBuilder< O = undefined, - A extends string = never, + A extends string = never > extends AliasedExpression { get isAliasedSelectQueryBuilder(): true } @@ -2332,7 +2332,7 @@ class AliasedSelectQueryBuilderImpl< DB, TB extends keyof DB, O = undefined, - A extends string = never, + A extends string = never > implements AliasedSelectQueryBuilder { readonly #queryBuilder: SelectQueryBuilder @@ -2358,39 +2358,39 @@ class AliasedSelectQueryBuilderImpl< toOperationNode(): AliasNode { return AliasNode.create( this.#queryBuilder.toOperationNode(), - IdentifierNode.create(this.#alias), + IdentifierNode.create(this.#alias) ) } } preventAwait( AliasedSelectQueryBuilderImpl, - "don't await AliasedSelectQueryBuilder instances directly. AliasedSelectQueryBuilder should never be executed directly since it's always a part of another query.", + "don't await AliasedSelectQueryBuilder instances directly. AliasedSelectQueryBuilder should never be executed directly since it's always a part of another query." ) export type SelectQueryBuilderWithInnerJoin< DB, TB extends keyof DB, O, - TE extends TableExpression, + TE extends TableExpression > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? InnerJoinedBuilder : never : TE extends keyof DB - ? SelectQueryBuilder - : TE extends AliasedExpression - ? InnerJoinedBuilder - : TE extends (qb: any) => AliasedExpression - ? InnerJoinedBuilder - : never + ? SelectQueryBuilder + : TE extends AliasedExpression + ? InnerJoinedBuilder + : TE extends (qb: any) => AliasedExpression + ? InnerJoinedBuilder + : never type InnerJoinedBuilder< DB, TB extends keyof DB, O, A extends string, - R, + R > = A extends keyof DB ? SelectQueryBuilder, TB | A, O> : // Much faster non-recursive solution for the simple case. @@ -2404,25 +2404,25 @@ export type SelectQueryBuilderWithLeftJoin< DB, TB extends keyof DB, O, - TE extends TableExpression, + TE extends TableExpression > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? LeftJoinedBuilder : never : TE extends keyof DB - ? LeftJoinedBuilder - : TE extends AliasedExpression - ? LeftJoinedBuilder - : TE extends (qb: any) => AliasedExpression - ? LeftJoinedBuilder - : never + ? LeftJoinedBuilder + : TE extends AliasedExpression + ? LeftJoinedBuilder + : TE extends (qb: any) => AliasedExpression + ? LeftJoinedBuilder + : never type LeftJoinedBuilder< DB, TB extends keyof DB, O, A extends keyof any, - R, + R > = A extends keyof DB ? SelectQueryBuilder, TB | A, O> : // Much faster non-recursive solution for the simple case. @@ -2432,88 +2432,88 @@ type LeftJoinedDB = DrainOuterGeneric<{ [C in keyof DB | A]: C extends A ? Nullable : C extends keyof DB - ? DB[C] - : never + ? DB[C] + : never }> export type SelectQueryBuilderWithRightJoin< DB, TB extends keyof DB, O, - TE extends TableExpression, + TE extends TableExpression > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? RightJoinedBuilder : never : TE extends keyof DB - ? RightJoinedBuilder - : TE extends AliasedExpression - ? RightJoinedBuilder - : TE extends (qb: any) => AliasedExpression - ? RightJoinedBuilder - : never + ? RightJoinedBuilder + : TE extends AliasedExpression + ? RightJoinedBuilder + : TE extends (qb: any) => AliasedExpression + ? RightJoinedBuilder + : never type RightJoinedBuilder< DB, TB extends keyof DB, O, A extends keyof any, - R, + R > = SelectQueryBuilder, TB | A, O> type RightJoinedDB< DB, TB extends keyof DB, A extends keyof any, - R, + R > = DrainOuterGeneric<{ [C in keyof DB | A]: C extends A ? R : C extends TB - ? Nullable - : C extends keyof DB - ? DB[C] - : never + ? Nullable + : C extends keyof DB + ? DB[C] + : never }> export type SelectQueryBuilderWithFullJoin< DB, TB extends keyof DB, O, - TE extends TableExpression, + TE extends TableExpression > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? OuterJoinedBuilder : never : TE extends keyof DB - ? OuterJoinedBuilder - : TE extends AliasedExpression - ? OuterJoinedBuilder - : TE extends (qb: any) => AliasedExpression - ? OuterJoinedBuilder - : never + ? OuterJoinedBuilder + : TE extends AliasedExpression + ? OuterJoinedBuilder + : TE extends (qb: any) => AliasedExpression + ? OuterJoinedBuilder + : never type OuterJoinedBuilder< DB, TB extends keyof DB, O, A extends keyof any, - R, + R > = SelectQueryBuilder, TB | A, O> type OuterJoinedBuilderDB< DB, TB extends keyof DB, A extends keyof any, - R, + R > = DrainOuterGeneric<{ [C in keyof DB | A]: C extends A ? Nullable : C extends TB - ? Nullable - : C extends keyof DB - ? DB[C] - : never + ? Nullable + : C extends keyof DB + ? DB[C] + : never }> type TableOrList = diff --git a/src/query-builder/update-query-builder.ts b/src/query-builder/update-query-builder.ts index 5baf2d2c2..19b37c766 100644 --- a/src/query-builder/update-query-builder.ts +++ b/src/query-builder/update-query-builder.ts @@ -71,6 +71,7 @@ import { parseValueExpression, } from '../parser/value-parser.js' import { LimitNode } from '../operation-node/limit-node.js' +import { parseTop } from '../parser/top-parser.js' export class UpdateQueryBuilder implements @@ -89,15 +90,15 @@ export class UpdateQueryBuilder where< RE extends ReferenceExpression, - VE extends OperandValueExpressionOrList, + VE extends OperandValueExpressionOrList >( lhs: RE, op: ComparisonOperatorExpression, - rhs: VE, + rhs: VE ): UpdateQueryBuilder where>( - expression: E, + expression: E ): UpdateQueryBuilder where(...args: any[]): any { @@ -105,24 +106,24 @@ export class UpdateQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithWhere( this.#props.queryNode, - parseValueBinaryOperationOrExpression(args), + parseValueBinaryOperationOrExpression(args) ), }) } whereRef< LRE extends ReferenceExpression, - RRE extends ReferenceExpression, + RRE extends ReferenceExpression >( lhs: LRE, op: ComparisonOperatorExpression, - rhs: RRE, + rhs: RRE ): UpdateQueryBuilder { return new UpdateQueryBuilder({ ...this.#props, queryNode: QueryNode.cloneWithWhere( this.#props.queryNode, - parseReferentialBinaryOperation(lhs, op, rhs), + parseReferentialBinaryOperation(lhs, op, rhs) ), }) } @@ -181,8 +182,7 @@ export class UpdateQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithTop( this.#props.queryNode, - expression, - modifiers + parseTop(expression, modifiers) ), }) } @@ -215,11 +215,11 @@ export class UpdateQueryBuilder * ``` */ from>( - table: TE, + table: TE ): UpdateQueryBuilder, UT, FromTables, O> from>( - table: TE[], + table: TE[] ): UpdateQueryBuilder, UT, FromTables, O> from(from: TableExpressionOrList): any { @@ -227,7 +227,7 @@ export class UpdateQueryBuilder ...this.#props, queryNode: UpdateQueryNode.cloneWithFromItems( this.#props.queryNode, - parseTableExpressionOrList(from), + parseTableExpressionOrList(from) ), }) } @@ -344,16 +344,16 @@ export class UpdateQueryBuilder innerJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression, + K2 extends JoinReferenceExpression >( table: TE, k1: K1, - k2: K2, + k2: K2 ): UpdateQueryBuilderWithInnerJoin innerJoin< TE extends TableExpression, - FN extends JoinCallbackExpression, + FN extends JoinCallbackExpression >(table: TE, callback: FN): UpdateQueryBuilderWithInnerJoin innerJoin(...args: any): any { @@ -361,7 +361,7 @@ export class UpdateQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('InnerJoin', args), + parseJoin('InnerJoin', args) ), }) } @@ -372,16 +372,16 @@ export class UpdateQueryBuilder leftJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression, + K2 extends JoinReferenceExpression >( table: TE, k1: K1, - k2: K2, + k2: K2 ): UpdateQueryBuilderWithLeftJoin leftJoin< TE extends TableExpression, - FN extends JoinCallbackExpression, + FN extends JoinCallbackExpression >(table: TE, callback: FN): UpdateQueryBuilderWithLeftJoin leftJoin(...args: any): any { @@ -389,7 +389,7 @@ export class UpdateQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('LeftJoin', args), + parseJoin('LeftJoin', args) ), }) } @@ -400,16 +400,16 @@ export class UpdateQueryBuilder rightJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression, + K2 extends JoinReferenceExpression >( table: TE, k1: K1, - k2: K2, + k2: K2 ): UpdateQueryBuilderWithRightJoin rightJoin< TE extends TableExpression, - FN extends JoinCallbackExpression, + FN extends JoinCallbackExpression >(table: TE, callback: FN): UpdateQueryBuilderWithRightJoin rightJoin(...args: any): any { @@ -417,7 +417,7 @@ export class UpdateQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('RightJoin', args), + parseJoin('RightJoin', args) ), }) } @@ -428,16 +428,16 @@ export class UpdateQueryBuilder fullJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression, + K2 extends JoinReferenceExpression >( table: TE, k1: K1, - k2: K2, + k2: K2 ): UpdateQueryBuilderWithFullJoin fullJoin< TE extends TableExpression, - FN extends JoinCallbackExpression, + FN extends JoinCallbackExpression >(table: TE, callback: FN): UpdateQueryBuilderWithFullJoin fullJoin(...args: any): any { @@ -445,7 +445,7 @@ export class UpdateQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('FullJoin', args), + parseJoin('FullJoin', args) ), }) } @@ -470,13 +470,13 @@ export class UpdateQueryBuilder * ``` */ limit( - limit: ValueExpression, + limit: ValueExpression ): UpdateQueryBuilder { return new UpdateQueryBuilder({ ...this.#props, queryNode: UpdateQueryNode.cloneWithLimit( this.#props.queryNode, - LimitNode.create(parseValueExpression(limit)), + LimitNode.create(parseValueExpression(limit)) ), }) } @@ -622,7 +622,7 @@ export class UpdateQueryBuilder * ``` */ set( - update: UpdateObjectExpression, + update: UpdateObjectExpression ): UpdateQueryBuilder set>( @@ -631,7 +631,7 @@ export class UpdateQueryBuilder DB, TB, ExtractUpdateTypeFromReferenceExpression - >, + > ): UpdateQueryBuilder set( @@ -643,31 +643,31 @@ export class UpdateQueryBuilder ...this.#props, queryNode: UpdateQueryNode.cloneWithUpdates( this.#props.queryNode, - parseUpdate(...args), + parseUpdate(...args) ), }) } returning>( - selections: ReadonlyArray, + selections: ReadonlyArray ): UpdateQueryBuilder> returning>( - callback: CB, + callback: CB ): UpdateQueryBuilder> returning>( - selection: SE, + selection: SE ): UpdateQueryBuilder> returning>( - selection: SelectArg, + selection: SelectArg ): UpdateQueryBuilder> { return new UpdateQueryBuilder({ ...this.#props, queryNode: QueryNode.cloneWithReturning( this.#props.queryNode, - parseSelectArg(selection), + parseSelectArg(selection) ), }) } @@ -677,7 +677,7 @@ export class UpdateQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithReturning( this.#props.queryNode, - parseSelectAll(), + parseSelectAll() ), }) } @@ -773,12 +773,12 @@ export class UpdateQueryBuilder */ $if( condition: boolean, - func: (qb: this) => UpdateQueryBuilder, + func: (qb: this) => UpdateQueryBuilder ): O2 extends UpdateResult ? UpdateQueryBuilder : O2 extends O & infer E - ? UpdateQueryBuilder> - : UpdateQueryBuilder> { + ? UpdateQueryBuilder> + : UpdateQueryBuilder> { if (condition) { return func(this) as any } @@ -908,14 +908,14 @@ export class UpdateQueryBuilder toOperationNode(): UpdateQueryNode { return this.#props.executor.transformQuery( this.#props.queryNode, - this.#props.queryId, + this.#props.queryId ) } compile(): CompiledQuery> { return this.#props.executor.compileQuery( this.toOperationNode(), - this.#props.queryId, + this.#props.queryId ) } @@ -930,7 +930,7 @@ export class UpdateQueryBuilder const result = await this.#props.executor.executeQuery( compiledQuery, - this.#props.queryId, + this.#props.queryId ) if (this.#props.executor.adapter.supportsReturning && query.returning) { @@ -942,7 +942,7 @@ export class UpdateQueryBuilder // TODO: remove numUpdatedOrDeletedRows. // TODO: https://github.com/kysely-org/kysely/pull/431#discussion_r1172330899 result.numAffectedRows ?? result.numUpdatedOrDeletedRows ?? BigInt(0), - result.numChangedRows, + result.numChangedRows ) as any, ] } @@ -967,7 +967,7 @@ export class UpdateQueryBuilder async executeTakeFirstOrThrow( errorConstructor: | NoResultErrorConstructor - | ((node: QueryNode) => Error) = NoResultError, + | ((node: QueryNode) => Error) = NoResultError ): Promise> { const result = await this.executeTakeFirst() @@ -988,7 +988,7 @@ export class UpdateQueryBuilder const stream = this.#props.executor.stream( compiledQuery, chunkSize, - this.#props.queryId, + this.#props.queryId ) for await (const item of stream) { @@ -998,14 +998,14 @@ export class UpdateQueryBuilder async explain = Record>( format?: ExplainFormat, - options?: Expression, + options?: Expression ): Promise { const builder = new UpdateQueryBuilder({ ...this.#props, queryNode: QueryNode.cloneWithExplain( this.#props.queryNode, format, - options, + options ), }) @@ -1015,7 +1015,7 @@ export class UpdateQueryBuilder preventAwait( UpdateQueryBuilder, - "don't await UpdateQueryBuilder instances directly. To execute the query you need to call `execute` or `executeTakeFirst`.", + "don't await UpdateQueryBuilder instances directly. To execute the query you need to call `execute` or `executeTakeFirst`." ) export interface UpdateQueryBuilderProps { @@ -1029,18 +1029,18 @@ export type UpdateQueryBuilderWithInnerJoin< UT extends keyof DB, TB extends keyof DB, O, - TE extends TableExpression, + TE extends TableExpression > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? InnerJoinedBuilder : never : TE extends keyof DB - ? UpdateQueryBuilder - : TE extends AliasedExpression - ? InnerJoinedBuilder - : TE extends (qb: any) => AliasedExpression - ? InnerJoinedBuilder - : never + ? UpdateQueryBuilder + : TE extends AliasedExpression + ? InnerJoinedBuilder + : TE extends (qb: any) => AliasedExpression + ? InnerJoinedBuilder + : never type InnerJoinedBuilder< DB, @@ -1048,7 +1048,7 @@ type InnerJoinedBuilder< TB extends keyof DB, O, A extends string, - R, + R > = A extends keyof DB ? UpdateQueryBuilder, UT, TB | A, O> : // Much faster non-recursive solution for the simple case. @@ -1063,18 +1063,18 @@ export type UpdateQueryBuilderWithLeftJoin< UT extends keyof DB, TB extends keyof DB, O, - TE extends TableExpression, + TE extends TableExpression > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? LeftJoinedBuilder : never : TE extends keyof DB - ? LeftJoinedBuilder - : TE extends AliasedExpression - ? LeftJoinedBuilder - : TE extends (qb: any) => AliasedExpression - ? LeftJoinedBuilder - : never + ? LeftJoinedBuilder + : TE extends AliasedExpression + ? LeftJoinedBuilder + : TE extends (qb: any) => AliasedExpression + ? LeftJoinedBuilder + : never type LeftJoinedBuilder< DB, @@ -1082,7 +1082,7 @@ type LeftJoinedBuilder< TB extends keyof DB, O, A extends keyof any, - R, + R > = A extends keyof DB ? UpdateQueryBuilder, UT, TB | A, O> : // Much faster non-recursive solution for the simple case. @@ -1092,8 +1092,8 @@ type LeftJoinedDB = DrainOuterGeneric<{ [C in keyof DB | A]: C extends A ? Nullable : C extends keyof DB - ? DB[C] - : never + ? DB[C] + : never }> export type UpdateQueryBuilderWithRightJoin< @@ -1101,18 +1101,18 @@ export type UpdateQueryBuilderWithRightJoin< UT extends keyof DB, TB extends keyof DB, O, - TE extends TableExpression, + TE extends TableExpression > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? RightJoinedBuilder : never : TE extends keyof DB - ? RightJoinedBuilder - : TE extends AliasedExpression - ? RightJoinedBuilder - : TE extends (qb: any) => AliasedExpression - ? RightJoinedBuilder - : never + ? RightJoinedBuilder + : TE extends AliasedExpression + ? RightJoinedBuilder + : TE extends (qb: any) => AliasedExpression + ? RightJoinedBuilder + : never type RightJoinedBuilder< DB, @@ -1120,22 +1120,22 @@ type RightJoinedBuilder< TB extends keyof DB, O, A extends keyof any, - R, + R > = UpdateQueryBuilder, UT, TB | A, O> type RightJoinedDB< DB, TB extends keyof DB, A extends keyof any, - R, + R > = DrainOuterGeneric<{ [C in keyof DB | A]: C extends A ? R : C extends TB - ? Nullable - : C extends keyof DB - ? DB[C] - : never + ? Nullable + : C extends keyof DB + ? DB[C] + : never }> export type UpdateQueryBuilderWithFullJoin< @@ -1143,18 +1143,18 @@ export type UpdateQueryBuilderWithFullJoin< UT extends keyof DB, TB extends keyof DB, O, - TE extends TableExpression, + TE extends TableExpression > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? OuterJoinedBuilder : never : TE extends keyof DB - ? OuterJoinedBuilder - : TE extends AliasedExpression - ? OuterJoinedBuilder - : TE extends (qb: any) => AliasedExpression - ? OuterJoinedBuilder - : never + ? OuterJoinedBuilder + : TE extends AliasedExpression + ? OuterJoinedBuilder + : TE extends (qb: any) => AliasedExpression + ? OuterJoinedBuilder + : never type OuterJoinedBuilder< DB, @@ -1162,20 +1162,20 @@ type OuterJoinedBuilder< TB extends keyof DB, O, A extends keyof any, - R, + R > = UpdateQueryBuilder, UT, TB | A, O> type OuterJoinedBuilderDB< DB, TB extends keyof DB, A extends keyof any, - R, + R > = DrainOuterGeneric<{ [C in keyof DB | A]: C extends A ? Nullable : C extends TB - ? Nullable - : C extends keyof DB - ? DB[C] - : never + ? Nullable + : C extends keyof DB + ? DB[C] + : never }> From 4ed4bf257188cf715a093fc5a9b7f65d79b486c6 Mon Sep 17 00:00:00 2001 From: igalklebanov Date: Thu, 22 Feb 2024 00:37:48 +0200 Subject: [PATCH 12/18] trailing commas. --- .prettierrc.json | 5 +- src/parser/top-parser.ts | 2 +- src/query-builder/delete-query-builder.ts | 110 ++++----- src/query-builder/insert-query-builder.ts | 50 ++-- src/query-builder/select-query-builder.ts | 268 +++++++++++----------- src/query-builder/update-query-builder.ts | 118 +++++----- 6 files changed, 277 insertions(+), 276 deletions(-) diff --git a/.prettierrc.json b/.prettierrc.json index 00fbdb185..e3b414c7e 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,4 +1,5 @@ { "semi": false, - "singleQuote": true -} \ No newline at end of file + "singleQuote": true, + "trailingComma": "all" +} diff --git a/src/parser/top-parser.ts b/src/parser/top-parser.ts index 5643adc9f..048b95616 100644 --- a/src/parser/top-parser.ts +++ b/src/parser/top-parser.ts @@ -3,7 +3,7 @@ import { isBigInt, isNumber, isString } from '../util/object-utils' export function parseTop( expression: number | bigint, - modifiers?: TopModifier + modifiers?: TopModifier, ): TopNode { if (!isNumber(expression) && !isBigInt(expression)) { throw new Error(`Invalid top expression: ${expression}`) diff --git a/src/query-builder/delete-query-builder.ts b/src/query-builder/delete-query-builder.ts index efd1713ff..b9049729a 100644 --- a/src/query-builder/delete-query-builder.ts +++ b/src/query-builder/delete-query-builder.ts @@ -91,15 +91,15 @@ export class DeleteQueryBuilder where< RE extends ReferenceExpression, - VE extends OperandValueExpressionOrList + VE extends OperandValueExpressionOrList, >( lhs: RE, op: ComparisonOperatorExpression, - rhs: VE + rhs: VE, ): DeleteQueryBuilder where>( - expression: E + expression: E, ): DeleteQueryBuilder where(...args: any[]): any { @@ -107,24 +107,24 @@ export class DeleteQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithWhere( this.#props.queryNode, - parseValueBinaryOperationOrExpression(args) + parseValueBinaryOperationOrExpression(args), ), }) } whereRef< LRE extends ReferenceExpression, - RRE extends ReferenceExpression + RRE extends ReferenceExpression, >( lhs: LRE, op: ComparisonOperatorExpression, - rhs: RRE + rhs: RRE, ): DeleteQueryBuilder { return new DeleteQueryBuilder({ ...this.#props, queryNode: QueryNode.cloneWithWhere( this.#props.queryNode, - parseReferentialBinaryOperation(lhs, op, rhs) + parseReferentialBinaryOperation(lhs, op, rhs), ), }) } @@ -177,13 +177,13 @@ export class DeleteQueryBuilder */ top( expression: number | bigint, - modifiers?: 'percent' + modifiers?: 'percent', ): DeleteQueryBuilder { return new DeleteQueryBuilder({ ...this.#props, queryNode: QueryNode.cloneWithTop( this.#props.queryNode, - parseTop(expression, modifiers) + parseTop(expression, modifiers), ), }) } @@ -263,11 +263,11 @@ export class DeleteQueryBuilder * ``` */ using>( - tables: TE[] + tables: TE[], ): DeleteQueryBuilder, FromTables, O> using>( - table: TE + table: TE, ): DeleteQueryBuilder, FromTables, O> using(tables: TableExpressionOrList): any { @@ -275,7 +275,7 @@ export class DeleteQueryBuilder ...this.#props, queryNode: DeleteQueryNode.cloneWithUsing( this.#props.queryNode, - parseTableExpressionOrList(tables) + parseTableExpressionOrList(tables), ), }) } @@ -392,12 +392,12 @@ export class DeleteQueryBuilder innerJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression + K2 extends JoinReferenceExpression, >(table: TE, k1: K1, k2: K2): DeleteQueryBuilderWithInnerJoin innerJoin< TE extends TableExpression, - FN extends JoinCallbackExpression + FN extends JoinCallbackExpression, >(table: TE, callback: FN): DeleteQueryBuilderWithInnerJoin innerJoin(...args: any): any { @@ -405,7 +405,7 @@ export class DeleteQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('InnerJoin', args) + parseJoin('InnerJoin', args), ), }) } @@ -416,12 +416,12 @@ export class DeleteQueryBuilder leftJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression + K2 extends JoinReferenceExpression, >(table: TE, k1: K1, k2: K2): DeleteQueryBuilderWithLeftJoin leftJoin< TE extends TableExpression, - FN extends JoinCallbackExpression + FN extends JoinCallbackExpression, >(table: TE, callback: FN): DeleteQueryBuilderWithLeftJoin leftJoin(...args: any): any { @@ -429,7 +429,7 @@ export class DeleteQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('LeftJoin', args) + parseJoin('LeftJoin', args), ), }) } @@ -440,12 +440,12 @@ export class DeleteQueryBuilder rightJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression + K2 extends JoinReferenceExpression, >(table: TE, k1: K1, k2: K2): DeleteQueryBuilderWithRightJoin rightJoin< TE extends TableExpression, - FN extends JoinCallbackExpression + FN extends JoinCallbackExpression, >(table: TE, callback: FN): DeleteQueryBuilderWithRightJoin rightJoin(...args: any): any { @@ -453,7 +453,7 @@ export class DeleteQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('RightJoin', args) + parseJoin('RightJoin', args), ), }) } @@ -464,12 +464,12 @@ export class DeleteQueryBuilder fullJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression + K2 extends JoinReferenceExpression, >(table: TE, k1: K1, k2: K2): DeleteQueryBuilderWithFullJoin fullJoin< TE extends TableExpression, - FN extends JoinCallbackExpression + FN extends JoinCallbackExpression, >(table: TE, callback: FN): DeleteQueryBuilderWithFullJoin fullJoin(...args: any): any { @@ -477,31 +477,31 @@ export class DeleteQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('FullJoin', args) + parseJoin('FullJoin', args), ), }) } returning>( - selections: ReadonlyArray + selections: ReadonlyArray, ): DeleteQueryBuilder> returning>( - callback: CB + callback: CB, ): DeleteQueryBuilder> returning>( - selection: SE + selection: SE, ): DeleteQueryBuilder> returning>( - selection: SelectArg + selection: SelectArg, ): DeleteQueryBuilder> { return new DeleteQueryBuilder({ ...this.#props, queryNode: QueryNode.cloneWithReturning( this.#props.queryNode, - parseSelectArg(selection) + parseSelectArg(selection), ), }) } @@ -599,11 +599,11 @@ export class DeleteQueryBuilder * ``` */ returningAll( - tables: ReadonlyArray + tables: ReadonlyArray, ): DeleteQueryBuilder> returningAll( - table: T + table: T, ): DeleteQueryBuilder> returningAll(): DeleteQueryBuilder> @@ -613,7 +613,7 @@ export class DeleteQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithReturning( this.#props.queryNode, - parseSelectAll(table) + parseSelectAll(table), ), }) } @@ -731,13 +731,13 @@ export class DeleteQueryBuilder */ orderBy( orderBy: OrderByExpression, - direction?: OrderByDirectionExpression + direction?: OrderByDirectionExpression, ): DeleteQueryBuilder { return new DeleteQueryBuilder({ ...this.#props, queryNode: DeleteQueryNode.cloneWithOrderByItems( this.#props.queryNode, - parseOrderBy([orderBy, direction]) + parseOrderBy([orderBy, direction]), ), }) } @@ -765,7 +765,7 @@ export class DeleteQueryBuilder ...this.#props, queryNode: DeleteQueryNode.cloneWithLimit( this.#props.queryNode, - LimitNode.create(parseValueExpression(limit)) + LimitNode.create(parseValueExpression(limit)), ), }) } @@ -833,7 +833,7 @@ export class DeleteQueryBuilder */ $if( condition: boolean, - func: (qb: this) => DeleteQueryBuilder + func: (qb: this) => DeleteQueryBuilder, ): O2 extends DeleteResult ? DeleteQueryBuilder : O2 extends O & infer E @@ -963,14 +963,14 @@ export class DeleteQueryBuilder toOperationNode(): DeleteQueryNode { return this.#props.executor.transformQuery( this.#props.queryNode, - this.#props.queryId + this.#props.queryId, ) } compile(): CompiledQuery> { return this.#props.executor.compileQuery( this.toOperationNode(), - this.#props.queryId + this.#props.queryId, ) } @@ -985,7 +985,7 @@ export class DeleteQueryBuilder const result = await this.#props.executor.executeQuery( compiledQuery, - this.#props.queryId + this.#props.queryId, ) if (this.#props.executor.adapter.supportsReturning && query.returning) { @@ -995,7 +995,7 @@ export class DeleteQueryBuilder return [ new DeleteResult( // TODO: remove numUpdatedOrDeletedRows. - result.numAffectedRows ?? result.numUpdatedOrDeletedRows ?? BigInt(0) + result.numAffectedRows ?? result.numUpdatedOrDeletedRows ?? BigInt(0), ) as any, ] } @@ -1020,7 +1020,7 @@ export class DeleteQueryBuilder async executeTakeFirstOrThrow( errorConstructor: | NoResultErrorConstructor - | ((node: QueryNode) => Error) = NoResultError + | ((node: QueryNode) => Error) = NoResultError, ): Promise> { const result = await this.executeTakeFirst() @@ -1041,7 +1041,7 @@ export class DeleteQueryBuilder const stream = this.#props.executor.stream( compiledQuery, chunkSize, - this.#props.queryId + this.#props.queryId, ) for await (const item of stream) { @@ -1051,14 +1051,14 @@ export class DeleteQueryBuilder async explain = Record>( format?: ExplainFormat, - options?: Expression + options?: Expression, ): Promise { const builder = new DeleteQueryBuilder({ ...this.#props, queryNode: QueryNode.cloneWithExplain( this.#props.queryNode, format, - options + options, ), }) @@ -1068,7 +1068,7 @@ export class DeleteQueryBuilder preventAwait( DeleteQueryBuilder, - "don't await DeleteQueryBuilder instances directly. To execute the query you need to call `execute` or `executeTakeFirst`." + "don't await DeleteQueryBuilder instances directly. To execute the query you need to call `execute` or `executeTakeFirst`.", ) export interface DeleteQueryBuilderProps { @@ -1081,7 +1081,7 @@ export type DeleteQueryBuilderWithInnerJoin< DB, TB extends keyof DB, O, - TE extends TableExpression + TE extends TableExpression, > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? InnerJoinedBuilder @@ -1099,7 +1099,7 @@ type InnerJoinedBuilder< TB extends keyof DB, O, A extends string, - R + R, > = A extends keyof DB ? DeleteQueryBuilder, TB | A, O> : // Much faster non-recursive solution for the simple case. @@ -1113,7 +1113,7 @@ export type DeleteQueryBuilderWithLeftJoin< DB, TB extends keyof DB, O, - TE extends TableExpression + TE extends TableExpression, > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? LeftJoinedBuilder @@ -1131,7 +1131,7 @@ type LeftJoinedBuilder< TB extends keyof DB, O, A extends keyof any, - R + R, > = A extends keyof DB ? DeleteQueryBuilder, TB | A, O> : // Much faster non-recursive solution for the simple case. @@ -1149,7 +1149,7 @@ export type DeleteQueryBuilderWithRightJoin< DB, TB extends keyof DB, O, - TE extends TableExpression + TE extends TableExpression, > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? RightJoinedBuilder @@ -1167,14 +1167,14 @@ type RightJoinedBuilder< TB extends keyof DB, O, A extends keyof any, - R + R, > = DeleteQueryBuilder, TB | A, O> type RightJoinedDB< DB, TB extends keyof DB, A extends keyof any, - R + R, > = DrainOuterGeneric<{ [C in keyof DB | A]: C extends A ? R @@ -1189,7 +1189,7 @@ export type DeleteQueryBuilderWithFullJoin< DB, TB extends keyof DB, O, - TE extends TableExpression + TE extends TableExpression, > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? OuterJoinedBuilder @@ -1207,14 +1207,14 @@ type OuterJoinedBuilder< TB extends keyof DB, O, A extends keyof any, - R + R, > = DeleteQueryBuilder, TB | A, O> type OuterJoinedBuilderDB< DB, TB extends keyof DB, A extends keyof any, - R + R, > = DrainOuterGeneric<{ [C in keyof DB | A]: C extends A ? Nullable diff --git a/src/query-builder/insert-query-builder.ts b/src/query-builder/insert-query-builder.ts index 1b62bc488..2a5deded4 100644 --- a/src/query-builder/insert-query-builder.ts +++ b/src/query-builder/insert-query-builder.ts @@ -269,7 +269,7 @@ export class InsertQueryBuilder * ``` */ columns( - columns: ReadonlyArray + columns: ReadonlyArray, ): InsertQueryBuilder { return new InsertQueryBuilder({ ...this.#props, @@ -310,7 +310,7 @@ export class InsertQueryBuilder * ``` */ expression( - expression: ExpressionOrFactory + expression: ExpressionOrFactory, ): InsertQueryBuilder { return new InsertQueryBuilder({ ...this.#props, @@ -415,13 +415,13 @@ export class InsertQueryBuilder */ top( expression: number | bigint, - modifiers?: 'percent' + modifiers?: 'percent', ): InsertQueryBuilder { return new InsertQueryBuilder({ ...this.#props, queryNode: QueryNode.cloneWithTop( this.#props.queryNode, - parseTop(expression, modifiers) + parseTop(expression, modifiers), ), }) } @@ -579,13 +579,13 @@ export class InsertQueryBuilder */ onConflict( callback: ( - builder: OnConflictBuilder + builder: OnConflictBuilder, ) => | OnConflictUpdateBuilder< OnConflictDatabase, OnConflictTables > - | OnConflictDoNothingBuilder + | OnConflictDoNothingBuilder, ): InsertQueryBuilder { return new InsertQueryBuilder({ ...this.#props, @@ -593,7 +593,7 @@ export class InsertQueryBuilder onConflict: callback( new OnConflictBuilder({ onConflictNode: OnConflictNode.create(), - }) + }), ).toOperationNode(), }), }) @@ -618,38 +618,38 @@ export class InsertQueryBuilder * ``` */ onDuplicateKeyUpdate( - update: UpdateObjectExpression + update: UpdateObjectExpression, ): InsertQueryBuilder { return new InsertQueryBuilder({ ...this.#props, queryNode: InsertQueryNode.cloneWith(this.#props.queryNode, { onDuplicateKey: OnDuplicateKeyNode.create( - parseUpdateObjectExpression(update) + parseUpdateObjectExpression(update), ), }), }) } returning>( - selections: ReadonlyArray + selections: ReadonlyArray, ): InsertQueryBuilder> returning>( - callback: CB + callback: CB, ): InsertQueryBuilder> returning>( - selection: SE + selection: SE, ): InsertQueryBuilder> returning>( - selection: SelectArg + selection: SelectArg, ): InsertQueryBuilder> { return new InsertQueryBuilder({ ...this.#props, queryNode: QueryNode.cloneWithReturning( this.#props.queryNode, - parseSelectArg(selection) + parseSelectArg(selection), ), }) } @@ -659,7 +659,7 @@ export class InsertQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithReturning( this.#props.queryNode, - parseSelectAll() + parseSelectAll(), ), }) } @@ -753,7 +753,7 @@ export class InsertQueryBuilder */ $if( condition: boolean, - func: (qb: this) => InsertQueryBuilder + func: (qb: this) => InsertQueryBuilder, ): O2 extends InsertResult ? InsertQueryBuilder : O2 extends O & infer E @@ -882,14 +882,14 @@ export class InsertQueryBuilder toOperationNode(): InsertQueryNode { return this.#props.executor.transformQuery( this.#props.queryNode, - this.#props.queryId + this.#props.queryId, ) } compile(): CompiledQuery { return this.#props.executor.compileQuery( this.toOperationNode(), - this.#props.queryId + this.#props.queryId, ) } @@ -904,7 +904,7 @@ export class InsertQueryBuilder const result = await this.#props.executor.executeQuery( compiledQuery, - this.#props.queryId + this.#props.queryId, ) if (this.#props.executor.adapter.supportsReturning && query.returning) { @@ -915,7 +915,7 @@ export class InsertQueryBuilder new InsertResult( result.insertId, // TODO: remove numUpdatedOrDeletedRows. - result.numAffectedRows ?? result.numUpdatedOrDeletedRows + result.numAffectedRows ?? result.numUpdatedOrDeletedRows, ) as any, ] } @@ -940,7 +940,7 @@ export class InsertQueryBuilder async executeTakeFirstOrThrow( errorConstructor: | NoResultErrorConstructor - | ((node: QueryNode) => Error) = NoResultError + | ((node: QueryNode) => Error) = NoResultError, ): Promise> { const result = await this.executeTakeFirst() @@ -961,7 +961,7 @@ export class InsertQueryBuilder const stream = this.#props.executor.stream( compiledQuery, chunkSize, - this.#props.queryId + this.#props.queryId, ) for await (const item of stream) { @@ -971,14 +971,14 @@ export class InsertQueryBuilder async explain = Record>( format?: ExplainFormat, - options?: Expression + options?: Expression, ): Promise { const builder = new InsertQueryBuilder({ ...this.#props, queryNode: QueryNode.cloneWithExplain( this.#props.queryNode, format, - options + options, ), }) @@ -988,7 +988,7 @@ export class InsertQueryBuilder preventAwait( InsertQueryBuilder, - "don't await InsertQueryBuilder instances directly. To execute the query you need to call `execute` or `executeTakeFirst`." + "don't await InsertQueryBuilder instances directly. To execute the query you need to call `execute` or `executeTakeFirst`.", ) export interface InsertQueryBuilderProps { diff --git a/src/query-builder/select-query-builder.ts b/src/query-builder/select-query-builder.ts index 0db13f7ec..2317d77bf 100644 --- a/src/query-builder/select-query-builder.ts +++ b/src/query-builder/select-query-builder.ts @@ -91,46 +91,46 @@ export interface SelectQueryBuilder Streamable { where< RE extends ReferenceExpression, - VE extends OperandValueExpressionOrList + VE extends OperandValueExpressionOrList, >( lhs: RE, op: ComparisonOperatorExpression, - rhs: VE + rhs: VE, ): SelectQueryBuilder where>( - expression: E + expression: E, ): SelectQueryBuilder whereRef< LRE extends ReferenceExpression, - RRE extends ReferenceExpression + RRE extends ReferenceExpression, >( lhs: LRE, op: ComparisonOperatorExpression, - rhs: RRE + rhs: RRE, ): SelectQueryBuilder having< RE extends ReferenceExpression, - VE extends OperandValueExpressionOrList + VE extends OperandValueExpressionOrList, >( lhs: RE, op: ComparisonOperatorExpression, - rhs: VE + rhs: VE, ): SelectQueryBuilder having>( - expression: E + expression: E, ): SelectQueryBuilder havingRef< LRE extends ReferenceExpression, - RRE extends ReferenceExpression + RRE extends ReferenceExpression, >( lhs: LRE, op: ComparisonOperatorExpression, - rhs: RRE + rhs: RRE, ): SelectQueryBuilder /** @@ -320,15 +320,15 @@ export interface SelectQueryBuilder * ``` */ select>( - selections: ReadonlyArray + selections: ReadonlyArray, ): SelectQueryBuilder> select>( - callback: CB + callback: CB, ): SelectQueryBuilder> select>( - selection: SE + selection: SE, ): SelectQueryBuilder> /** @@ -357,11 +357,11 @@ export interface SelectQueryBuilder * ``` */ distinctOn>( - selections: ReadonlyArray + selections: ReadonlyArray, ): SelectQueryBuilder distinctOn>( - selection: RE + selection: RE, ): SelectQueryBuilder /** @@ -517,11 +517,11 @@ export interface SelectQueryBuilder * ``` */ selectAll( - table: ReadonlyArray + table: ReadonlyArray, ): SelectQueryBuilder> selectAll( - table: T + table: T, ): SelectQueryBuilder> selectAll(): SelectQueryBuilder> @@ -646,19 +646,19 @@ export interface SelectQueryBuilder innerJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression + K2 extends JoinReferenceExpression, >( table: TE, k1: K1, - k2: K2 + k2: K2, ): SelectQueryBuilderWithInnerJoin innerJoin< TE extends TableExpression, - FN extends JoinCallbackExpression + FN extends JoinCallbackExpression, >( table: TE, - callback: FN + callback: FN, ): SelectQueryBuilderWithInnerJoin /** @@ -667,19 +667,19 @@ export interface SelectQueryBuilder leftJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression + K2 extends JoinReferenceExpression, >( table: TE, k1: K1, - k2: K2 + k2: K2, ): SelectQueryBuilderWithLeftJoin leftJoin< TE extends TableExpression, - FN extends JoinCallbackExpression + FN extends JoinCallbackExpression, >( table: TE, - callback: FN + callback: FN, ): SelectQueryBuilderWithLeftJoin /** @@ -688,19 +688,19 @@ export interface SelectQueryBuilder rightJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression + K2 extends JoinReferenceExpression, >( table: TE, k1: K1, - k2: K2 + k2: K2, ): SelectQueryBuilderWithRightJoin rightJoin< TE extends TableExpression, - FN extends JoinCallbackExpression + FN extends JoinCallbackExpression, >( table: TE, - callback: FN + callback: FN, ): SelectQueryBuilderWithRightJoin /** @@ -709,19 +709,19 @@ export interface SelectQueryBuilder fullJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression + K2 extends JoinReferenceExpression, >( table: TE, k1: K1, - k2: K2 + k2: K2, ): SelectQueryBuilderWithFullJoin fullJoin< TE extends TableExpression, - FN extends JoinCallbackExpression + FN extends JoinCallbackExpression, >( table: TE, - callback: FN + callback: FN, ): SelectQueryBuilderWithFullJoin /** @@ -746,19 +746,19 @@ export interface SelectQueryBuilder innerJoinLateral< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression + K2 extends JoinReferenceExpression, >( table: TE, k1: K1, - k2: K2 + k2: K2, ): SelectQueryBuilderWithInnerJoin innerJoinLateral< TE extends TableExpression, - FN extends JoinCallbackExpression + FN extends JoinCallbackExpression, >( table: TE, - callback: FN + callback: FN, ): SelectQueryBuilderWithInnerJoin /** @@ -782,19 +782,19 @@ export interface SelectQueryBuilder leftJoinLateral< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression + K2 extends JoinReferenceExpression, >( table: TE, k1: K1, - k2: K2 + k2: K2, ): SelectQueryBuilderWithLeftJoin leftJoinLateral< TE extends TableExpression, - FN extends JoinCallbackExpression + FN extends JoinCallbackExpression, >( table: TE, - callback: FN + callback: FN, ): SelectQueryBuilderWithLeftJoin /** @@ -910,15 +910,15 @@ export interface SelectQueryBuilder */ orderBy>( orderBy: OE, - direction?: OrderByDirectionExpression + direction?: OrderByDirectionExpression, ): SelectQueryBuilder orderBy>( - ref: OE + ref: OE, ): SelectQueryBuilder orderBy>( - refs: ReadonlyArray + refs: ReadonlyArray, ): SelectQueryBuilder /** @@ -1020,7 +1020,7 @@ export interface SelectQueryBuilder * ``` */ groupBy>( - groupBy: GE + groupBy: GE, ): SelectQueryBuilder /** @@ -1129,7 +1129,7 @@ export interface SelectQueryBuilder */ top( expression: number | bigint, - modifiers?: TopModifier + modifiers?: TopModifier, ): SelectQueryBuilder /** @@ -1159,7 +1159,7 @@ export interface SelectQueryBuilder * ``` */ union>( - expression: E + expression: E, ): SelectQueryBuilder /** @@ -1189,7 +1189,7 @@ export interface SelectQueryBuilder * ``` */ unionAll>( - expression: E + expression: E, ): SelectQueryBuilder /** @@ -1219,7 +1219,7 @@ export interface SelectQueryBuilder * ``` */ intersect>( - expression: E + expression: E, ): SelectQueryBuilder /** @@ -1249,7 +1249,7 @@ export interface SelectQueryBuilder * ``` */ intersectAll>( - expression: E + expression: E, ): SelectQueryBuilder /** @@ -1279,7 +1279,7 @@ export interface SelectQueryBuilder * ``` */ except>( - expression: E + expression: E, ): SelectQueryBuilder /** @@ -1309,7 +1309,7 @@ export interface SelectQueryBuilder * ``` */ exceptAll>( - expression: E + expression: E, ): SelectQueryBuilder /** @@ -1508,7 +1508,7 @@ export interface SelectQueryBuilder */ $if( condition: boolean, - func: (qb: this) => SelectQueryBuilder + func: (qb: this) => SelectQueryBuilder, ): SelectQueryBuilder>> /** @@ -1565,7 +1565,7 @@ export interface SelectQueryBuilder */ $asTuple>( key1: K1, - key2: K2 + key2: K2, ): keyof O extends K1 | K2 ? ExpressionWrapper : KyselyTypeError<'$asTuple() call failed: All selected columns must be provided as arguments'> @@ -1573,11 +1573,11 @@ export interface SelectQueryBuilder $asTuple< K1 extends keyof O, K2 extends Exclude, - K3 extends Exclude + K3 extends Exclude, >( key1: K1, key2: K2, - key3: K3 + key3: K3, ): keyof O extends K1 | K2 | K3 ? ExpressionWrapper : KyselyTypeError<'$asTuple() call failed: All selected columns must be provided as arguments'> @@ -1586,12 +1586,12 @@ export interface SelectQueryBuilder K1 extends keyof O, K2 extends Exclude, K3 extends Exclude, - K4 extends Exclude + K4 extends Exclude, >( key1: K1, key2: K2, key3: K3, - key4: K4 + key4: K4, ): keyof O extends K1 | K2 | K3 | K4 ? ExpressionWrapper : KyselyTypeError<'$asTuple() call failed: All selected columns must be provided as arguments'> @@ -1601,13 +1601,13 @@ export interface SelectQueryBuilder K2 extends Exclude, K3 extends Exclude, K4 extends Exclude, - K5 extends Exclude + K5 extends Exclude, >( key1: K1, key2: K2, key3: K3, key4: K4, - key5: K5 + key5: K5, ): keyof O extends K1 | K2 | K3 | K4 | K5 ? ExpressionWrapper : KyselyTypeError<'$asTuple() call failed: All selected columns must be provided as arguments'> @@ -1744,14 +1744,14 @@ export interface SelectQueryBuilder * error. */ executeTakeFirstOrThrow( - errorConstructor?: NoResultErrorConstructor | ((node: QueryNode) => Error) + errorConstructor?: NoResultErrorConstructor | ((node: QueryNode) => Error), ): Promise> stream(chunkSize?: number): AsyncIterableIterator explain = Record>( format?: ExplainFormat, - options?: Expression + options?: Expression, ): Promise } @@ -1777,7 +1777,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: QueryNode.cloneWithWhere( this.#props.queryNode, - parseValueBinaryOperationOrExpression(args) + parseValueBinaryOperationOrExpression(args), ), }) } @@ -1785,13 +1785,13 @@ class SelectQueryBuilderImpl whereRef( lhs: ReferenceExpression, op: ComparisonOperatorExpression, - rhs: ReferenceExpression + rhs: ReferenceExpression, ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, queryNode: QueryNode.cloneWithWhere( this.#props.queryNode, - parseReferentialBinaryOperation(lhs, op, rhs) + parseReferentialBinaryOperation(lhs, op, rhs), ), }) } @@ -1801,7 +1801,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithHaving( this.#props.queryNode, - parseValueBinaryOperationOrExpression(args) + parseValueBinaryOperationOrExpression(args), ), }) } @@ -1809,25 +1809,25 @@ class SelectQueryBuilderImpl havingRef( lhs: ReferenceExpression, op: ComparisonOperatorExpression, - rhs: ReferenceExpression + rhs: ReferenceExpression, ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, queryNode: SelectQueryNode.cloneWithHaving( this.#props.queryNode, - parseReferentialBinaryOperation(lhs, op, rhs) + parseReferentialBinaryOperation(lhs, op, rhs), ), }) } select>( - selection: SelectArg + selection: SelectArg, ): SelectQueryBuilder> { return new SelectQueryBuilderImpl>({ ...this.#props, queryNode: SelectQueryNode.cloneWithSelections( this.#props.queryNode, - parseSelectArg(selection) + parseSelectArg(selection), ), }) } @@ -1837,7 +1837,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithDistinctOn( this.#props.queryNode, - parseReferenceExpressionOrList(selection) + parseReferenceExpressionOrList(selection), ), }) } @@ -1847,7 +1847,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithFrontModifier( this.#props.queryNode, - SelectModifierNode.createWithExpression(modifier.toOperationNode()) + SelectModifierNode.createWithExpression(modifier.toOperationNode()), ), }) } @@ -1857,7 +1857,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithEndModifier( this.#props.queryNode, - SelectModifierNode.createWithExpression(modifier.toOperationNode()) + SelectModifierNode.createWithExpression(modifier.toOperationNode()), ), }) } @@ -1867,7 +1867,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithFrontModifier( this.#props.queryNode, - SelectModifierNode.create('Distinct') + SelectModifierNode.create('Distinct'), ), }) } @@ -1879,8 +1879,8 @@ class SelectQueryBuilderImpl this.#props.queryNode, SelectModifierNode.create( 'ForUpdate', - of ? asArray(of).map(parseTable) : undefined - ) + of ? asArray(of).map(parseTable) : undefined, + ), ), }) } @@ -1892,8 +1892,8 @@ class SelectQueryBuilderImpl this.#props.queryNode, SelectModifierNode.create( 'ForShare', - of ? asArray(of).map(parseTable) : undefined - ) + of ? asArray(of).map(parseTable) : undefined, + ), ), }) } @@ -1905,8 +1905,8 @@ class SelectQueryBuilderImpl this.#props.queryNode, SelectModifierNode.create( 'ForKeyShare', - of ? asArray(of).map(parseTable) : undefined - ) + of ? asArray(of).map(parseTable) : undefined, + ), ), }) } @@ -1918,8 +1918,8 @@ class SelectQueryBuilderImpl this.#props.queryNode, SelectModifierNode.create( 'ForNoKeyUpdate', - of ? asArray(of).map(parseTable) : undefined - ) + of ? asArray(of).map(parseTable) : undefined, + ), ), }) } @@ -1929,7 +1929,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithEndModifier( this.#props.queryNode, - SelectModifierNode.create('SkipLocked') + SelectModifierNode.create('SkipLocked'), ), }) } @@ -1939,7 +1939,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithEndModifier( this.#props.queryNode, - SelectModifierNode.create('NoWait') + SelectModifierNode.create('NoWait'), ), }) } @@ -1949,7 +1949,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithSelections( this.#props.queryNode, - parseSelectAll(table) + parseSelectAll(table), ), }) } @@ -1959,7 +1959,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('InnerJoin', args) + parseJoin('InnerJoin', args), ), }) } @@ -1969,7 +1969,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('LeftJoin', args) + parseJoin('LeftJoin', args), ), }) } @@ -1979,7 +1979,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('RightJoin', args) + parseJoin('RightJoin', args), ), }) } @@ -1989,7 +1989,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('FullJoin', args) + parseJoin('FullJoin', args), ), }) } @@ -1999,7 +1999,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('LateralInnerJoin', args) + parseJoin('LateralInnerJoin', args), ), }) } @@ -2009,7 +2009,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('LateralLeftJoin', args) + parseJoin('LateralLeftJoin', args), ), }) } @@ -2019,7 +2019,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithOrderByItems( this.#props.queryNode, - parseOrderBy(args) + parseOrderBy(args), ), }) } @@ -2029,7 +2029,7 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithGroupByItems( this.#props.queryNode, - parseGroupBy(groupBy) + parseGroupBy(groupBy), ), }) } @@ -2039,104 +2039,104 @@ class SelectQueryBuilderImpl ...this.#props, queryNode: SelectQueryNode.cloneWithLimit( this.#props.queryNode, - LimitNode.create(parseValueExpression(limit)) + LimitNode.create(parseValueExpression(limit)), ), }) } offset( - offset: ValueExpression + offset: ValueExpression, ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, queryNode: SelectQueryNode.cloneWithOffset( this.#props.queryNode, - OffsetNode.create(parseValueExpression(offset)) + OffsetNode.create(parseValueExpression(offset)), ), }) } top( expression: number | bigint, - modifiers?: TopModifier + modifiers?: TopModifier, ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, queryNode: QueryNode.cloneWithTop( this.#props.queryNode, - parseTop(expression, modifiers) + parseTop(expression, modifiers), ), }) } union( - expression: SetOperandExpression + expression: SetOperandExpression, ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, queryNode: SelectQueryNode.cloneWithSetOperations( this.#props.queryNode, - parseSetOperations('union', expression, false) + parseSetOperations('union', expression, false), ), }) } unionAll( - expression: SetOperandExpression + expression: SetOperandExpression, ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, queryNode: SelectQueryNode.cloneWithSetOperations( this.#props.queryNode, - parseSetOperations('union', expression, true) + parseSetOperations('union', expression, true), ), }) } intersect( - expression: SetOperandExpression + expression: SetOperandExpression, ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, queryNode: SelectQueryNode.cloneWithSetOperations( this.#props.queryNode, - parseSetOperations('intersect', expression, false) + parseSetOperations('intersect', expression, false), ), }) } intersectAll( - expression: SetOperandExpression + expression: SetOperandExpression, ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, queryNode: SelectQueryNode.cloneWithSetOperations( this.#props.queryNode, - parseSetOperations('intersect', expression, true) + parseSetOperations('intersect', expression, true), ), }) } except( - expression: SetOperandExpression + expression: SetOperandExpression, ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, queryNode: SelectQueryNode.cloneWithSetOperations( this.#props.queryNode, - parseSetOperations('except', expression, false) + parseSetOperations('except', expression, false), ), }) } exceptAll( - expression: SetOperandExpression + expression: SetOperandExpression, ): SelectQueryBuilder { return new SelectQueryBuilderImpl({ ...this.#props, queryNode: SelectQueryNode.cloneWithSetOperations( this.#props.queryNode, - parseSetOperations('except', expression, true) + parseSetOperations('except', expression, true), ), }) } @@ -2186,7 +2186,7 @@ class SelectQueryBuilderImpl $if( condition: boolean, - func: (qb: this) => SelectQueryBuilder + func: (qb: this) => SelectQueryBuilder, ): SelectQueryBuilder>> { if (condition) { return func(this) @@ -2225,14 +2225,14 @@ class SelectQueryBuilderImpl toOperationNode(): SelectQueryNode { return this.#props.executor.transformQuery( this.#props.queryNode, - this.#props.queryId + this.#props.queryId, ) } compile(): CompiledQuery> { return this.#props.executor.compileQuery( this.toOperationNode(), - this.#props.queryId + this.#props.queryId, ) } @@ -2241,7 +2241,7 @@ class SelectQueryBuilderImpl const result = await this.#props.executor.executeQuery( compiledQuery, - this.#props.queryId + this.#props.queryId, ) return result.rows @@ -2255,7 +2255,7 @@ class SelectQueryBuilderImpl async executeTakeFirstOrThrow( errorConstructor: | NoResultErrorConstructor - | ((node: QueryNode) => Error) = NoResultError + | ((node: QueryNode) => Error) = NoResultError, ): Promise> { const result = await this.executeTakeFirst() @@ -2276,7 +2276,7 @@ class SelectQueryBuilderImpl const stream = this.#props.executor.stream( compiledQuery, chunkSize, - this.#props.queryId + this.#props.queryId, ) for await (const item of stream) { @@ -2286,14 +2286,14 @@ class SelectQueryBuilderImpl async explain = Record>( format?: ExplainFormat, - options?: Expression + options?: Expression, ): Promise { const builder = new SelectQueryBuilderImpl({ ...this.#props, queryNode: QueryNode.cloneWithExplain( this.#props.queryNode, format, - options + options, ), }) @@ -2303,11 +2303,11 @@ class SelectQueryBuilderImpl preventAwait( SelectQueryBuilderImpl, - "don't await SelectQueryBuilder instances directly. To execute the query you need to call `execute` or `executeTakeFirst`." + "don't await SelectQueryBuilder instances directly. To execute the query you need to call `execute` or `executeTakeFirst`.", ) export function createSelectQueryBuilder( - props: SelectQueryBuilderProps + props: SelectQueryBuilderProps, ): SelectQueryBuilder { return new SelectQueryBuilderImpl(props) } @@ -2320,7 +2320,7 @@ export interface SelectQueryBuilderProps { export interface AliasedSelectQueryBuilder< O = undefined, - A extends string = never + A extends string = never, > extends AliasedExpression { get isAliasedSelectQueryBuilder(): true } @@ -2332,7 +2332,7 @@ class AliasedSelectQueryBuilderImpl< DB, TB extends keyof DB, O = undefined, - A extends string = never + A extends string = never, > implements AliasedSelectQueryBuilder { readonly #queryBuilder: SelectQueryBuilder @@ -2358,21 +2358,21 @@ class AliasedSelectQueryBuilderImpl< toOperationNode(): AliasNode { return AliasNode.create( this.#queryBuilder.toOperationNode(), - IdentifierNode.create(this.#alias) + IdentifierNode.create(this.#alias), ) } } preventAwait( AliasedSelectQueryBuilderImpl, - "don't await AliasedSelectQueryBuilder instances directly. AliasedSelectQueryBuilder should never be executed directly since it's always a part of another query." + "don't await AliasedSelectQueryBuilder instances directly. AliasedSelectQueryBuilder should never be executed directly since it's always a part of another query.", ) export type SelectQueryBuilderWithInnerJoin< DB, TB extends keyof DB, O, - TE extends TableExpression + TE extends TableExpression, > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? InnerJoinedBuilder @@ -2390,7 +2390,7 @@ type InnerJoinedBuilder< TB extends keyof DB, O, A extends string, - R + R, > = A extends keyof DB ? SelectQueryBuilder, TB | A, O> : // Much faster non-recursive solution for the simple case. @@ -2404,7 +2404,7 @@ export type SelectQueryBuilderWithLeftJoin< DB, TB extends keyof DB, O, - TE extends TableExpression + TE extends TableExpression, > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? LeftJoinedBuilder @@ -2422,7 +2422,7 @@ type LeftJoinedBuilder< TB extends keyof DB, O, A extends keyof any, - R + R, > = A extends keyof DB ? SelectQueryBuilder, TB | A, O> : // Much faster non-recursive solution for the simple case. @@ -2440,7 +2440,7 @@ export type SelectQueryBuilderWithRightJoin< DB, TB extends keyof DB, O, - TE extends TableExpression + TE extends TableExpression, > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? RightJoinedBuilder @@ -2458,14 +2458,14 @@ type RightJoinedBuilder< TB extends keyof DB, O, A extends keyof any, - R + R, > = SelectQueryBuilder, TB | A, O> type RightJoinedDB< DB, TB extends keyof DB, A extends keyof any, - R + R, > = DrainOuterGeneric<{ [C in keyof DB | A]: C extends A ? R @@ -2480,7 +2480,7 @@ export type SelectQueryBuilderWithFullJoin< DB, TB extends keyof DB, O, - TE extends TableExpression + TE extends TableExpression, > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? OuterJoinedBuilder @@ -2498,14 +2498,14 @@ type OuterJoinedBuilder< TB extends keyof DB, O, A extends keyof any, - R + R, > = SelectQueryBuilder, TB | A, O> type OuterJoinedBuilderDB< DB, TB extends keyof DB, A extends keyof any, - R + R, > = DrainOuterGeneric<{ [C in keyof DB | A]: C extends A ? Nullable diff --git a/src/query-builder/update-query-builder.ts b/src/query-builder/update-query-builder.ts index 19b37c766..31333ca58 100644 --- a/src/query-builder/update-query-builder.ts +++ b/src/query-builder/update-query-builder.ts @@ -90,15 +90,15 @@ export class UpdateQueryBuilder where< RE extends ReferenceExpression, - VE extends OperandValueExpressionOrList + VE extends OperandValueExpressionOrList, >( lhs: RE, op: ComparisonOperatorExpression, - rhs: VE + rhs: VE, ): UpdateQueryBuilder where>( - expression: E + expression: E, ): UpdateQueryBuilder where(...args: any[]): any { @@ -106,24 +106,24 @@ export class UpdateQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithWhere( this.#props.queryNode, - parseValueBinaryOperationOrExpression(args) + parseValueBinaryOperationOrExpression(args), ), }) } whereRef< LRE extends ReferenceExpression, - RRE extends ReferenceExpression + RRE extends ReferenceExpression, >( lhs: LRE, op: ComparisonOperatorExpression, - rhs: RRE + rhs: RRE, ): UpdateQueryBuilder { return new UpdateQueryBuilder({ ...this.#props, queryNode: QueryNode.cloneWithWhere( this.#props.queryNode, - parseReferentialBinaryOperation(lhs, op, rhs) + parseReferentialBinaryOperation(lhs, op, rhs), ), }) } @@ -176,13 +176,13 @@ export class UpdateQueryBuilder */ top( expression: number | bigint, - modifiers?: 'percent' + modifiers?: 'percent', ): UpdateQueryBuilder { return new UpdateQueryBuilder({ ...this.#props, queryNode: QueryNode.cloneWithTop( this.#props.queryNode, - parseTop(expression, modifiers) + parseTop(expression, modifiers), ), }) } @@ -215,11 +215,11 @@ export class UpdateQueryBuilder * ``` */ from>( - table: TE + table: TE, ): UpdateQueryBuilder, UT, FromTables, O> from>( - table: TE[] + table: TE[], ): UpdateQueryBuilder, UT, FromTables, O> from(from: TableExpressionOrList): any { @@ -227,7 +227,7 @@ export class UpdateQueryBuilder ...this.#props, queryNode: UpdateQueryNode.cloneWithFromItems( this.#props.queryNode, - parseTableExpressionOrList(from) + parseTableExpressionOrList(from), ), }) } @@ -344,16 +344,16 @@ export class UpdateQueryBuilder innerJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression + K2 extends JoinReferenceExpression, >( table: TE, k1: K1, - k2: K2 + k2: K2, ): UpdateQueryBuilderWithInnerJoin innerJoin< TE extends TableExpression, - FN extends JoinCallbackExpression + FN extends JoinCallbackExpression, >(table: TE, callback: FN): UpdateQueryBuilderWithInnerJoin innerJoin(...args: any): any { @@ -361,7 +361,7 @@ export class UpdateQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('InnerJoin', args) + parseJoin('InnerJoin', args), ), }) } @@ -372,16 +372,16 @@ export class UpdateQueryBuilder leftJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression + K2 extends JoinReferenceExpression, >( table: TE, k1: K1, - k2: K2 + k2: K2, ): UpdateQueryBuilderWithLeftJoin leftJoin< TE extends TableExpression, - FN extends JoinCallbackExpression + FN extends JoinCallbackExpression, >(table: TE, callback: FN): UpdateQueryBuilderWithLeftJoin leftJoin(...args: any): any { @@ -389,7 +389,7 @@ export class UpdateQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('LeftJoin', args) + parseJoin('LeftJoin', args), ), }) } @@ -400,16 +400,16 @@ export class UpdateQueryBuilder rightJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression + K2 extends JoinReferenceExpression, >( table: TE, k1: K1, - k2: K2 + k2: K2, ): UpdateQueryBuilderWithRightJoin rightJoin< TE extends TableExpression, - FN extends JoinCallbackExpression + FN extends JoinCallbackExpression, >(table: TE, callback: FN): UpdateQueryBuilderWithRightJoin rightJoin(...args: any): any { @@ -417,7 +417,7 @@ export class UpdateQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('RightJoin', args) + parseJoin('RightJoin', args), ), }) } @@ -428,16 +428,16 @@ export class UpdateQueryBuilder fullJoin< TE extends TableExpression, K1 extends JoinReferenceExpression, - K2 extends JoinReferenceExpression + K2 extends JoinReferenceExpression, >( table: TE, k1: K1, - k2: K2 + k2: K2, ): UpdateQueryBuilderWithFullJoin fullJoin< TE extends TableExpression, - FN extends JoinCallbackExpression + FN extends JoinCallbackExpression, >(table: TE, callback: FN): UpdateQueryBuilderWithFullJoin fullJoin(...args: any): any { @@ -445,7 +445,7 @@ export class UpdateQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithJoin( this.#props.queryNode, - parseJoin('FullJoin', args) + parseJoin('FullJoin', args), ), }) } @@ -470,13 +470,13 @@ export class UpdateQueryBuilder * ``` */ limit( - limit: ValueExpression + limit: ValueExpression, ): UpdateQueryBuilder { return new UpdateQueryBuilder({ ...this.#props, queryNode: UpdateQueryNode.cloneWithLimit( this.#props.queryNode, - LimitNode.create(parseValueExpression(limit)) + LimitNode.create(parseValueExpression(limit)), ), }) } @@ -622,7 +622,7 @@ export class UpdateQueryBuilder * ``` */ set( - update: UpdateObjectExpression + update: UpdateObjectExpression, ): UpdateQueryBuilder set>( @@ -631,7 +631,7 @@ export class UpdateQueryBuilder DB, TB, ExtractUpdateTypeFromReferenceExpression - > + >, ): UpdateQueryBuilder set( @@ -643,31 +643,31 @@ export class UpdateQueryBuilder ...this.#props, queryNode: UpdateQueryNode.cloneWithUpdates( this.#props.queryNode, - parseUpdate(...args) + parseUpdate(...args), ), }) } returning>( - selections: ReadonlyArray + selections: ReadonlyArray, ): UpdateQueryBuilder> returning>( - callback: CB + callback: CB, ): UpdateQueryBuilder> returning>( - selection: SE + selection: SE, ): UpdateQueryBuilder> returning>( - selection: SelectArg + selection: SelectArg, ): UpdateQueryBuilder> { return new UpdateQueryBuilder({ ...this.#props, queryNode: QueryNode.cloneWithReturning( this.#props.queryNode, - parseSelectArg(selection) + parseSelectArg(selection), ), }) } @@ -677,7 +677,7 @@ export class UpdateQueryBuilder ...this.#props, queryNode: QueryNode.cloneWithReturning( this.#props.queryNode, - parseSelectAll() + parseSelectAll(), ), }) } @@ -773,7 +773,7 @@ export class UpdateQueryBuilder */ $if( condition: boolean, - func: (qb: this) => UpdateQueryBuilder + func: (qb: this) => UpdateQueryBuilder, ): O2 extends UpdateResult ? UpdateQueryBuilder : O2 extends O & infer E @@ -908,14 +908,14 @@ export class UpdateQueryBuilder toOperationNode(): UpdateQueryNode { return this.#props.executor.transformQuery( this.#props.queryNode, - this.#props.queryId + this.#props.queryId, ) } compile(): CompiledQuery> { return this.#props.executor.compileQuery( this.toOperationNode(), - this.#props.queryId + this.#props.queryId, ) } @@ -930,7 +930,7 @@ export class UpdateQueryBuilder const result = await this.#props.executor.executeQuery( compiledQuery, - this.#props.queryId + this.#props.queryId, ) if (this.#props.executor.adapter.supportsReturning && query.returning) { @@ -942,7 +942,7 @@ export class UpdateQueryBuilder // TODO: remove numUpdatedOrDeletedRows. // TODO: https://github.com/kysely-org/kysely/pull/431#discussion_r1172330899 result.numAffectedRows ?? result.numUpdatedOrDeletedRows ?? BigInt(0), - result.numChangedRows + result.numChangedRows, ) as any, ] } @@ -967,7 +967,7 @@ export class UpdateQueryBuilder async executeTakeFirstOrThrow( errorConstructor: | NoResultErrorConstructor - | ((node: QueryNode) => Error) = NoResultError + | ((node: QueryNode) => Error) = NoResultError, ): Promise> { const result = await this.executeTakeFirst() @@ -988,7 +988,7 @@ export class UpdateQueryBuilder const stream = this.#props.executor.stream( compiledQuery, chunkSize, - this.#props.queryId + this.#props.queryId, ) for await (const item of stream) { @@ -998,14 +998,14 @@ export class UpdateQueryBuilder async explain = Record>( format?: ExplainFormat, - options?: Expression + options?: Expression, ): Promise { const builder = new UpdateQueryBuilder({ ...this.#props, queryNode: QueryNode.cloneWithExplain( this.#props.queryNode, format, - options + options, ), }) @@ -1015,7 +1015,7 @@ export class UpdateQueryBuilder preventAwait( UpdateQueryBuilder, - "don't await UpdateQueryBuilder instances directly. To execute the query you need to call `execute` or `executeTakeFirst`." + "don't await UpdateQueryBuilder instances directly. To execute the query you need to call `execute` or `executeTakeFirst`.", ) export interface UpdateQueryBuilderProps { @@ -1029,7 +1029,7 @@ export type UpdateQueryBuilderWithInnerJoin< UT extends keyof DB, TB extends keyof DB, O, - TE extends TableExpression + TE extends TableExpression, > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? InnerJoinedBuilder @@ -1048,7 +1048,7 @@ type InnerJoinedBuilder< TB extends keyof DB, O, A extends string, - R + R, > = A extends keyof DB ? UpdateQueryBuilder, UT, TB | A, O> : // Much faster non-recursive solution for the simple case. @@ -1063,7 +1063,7 @@ export type UpdateQueryBuilderWithLeftJoin< UT extends keyof DB, TB extends keyof DB, O, - TE extends TableExpression + TE extends TableExpression, > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? LeftJoinedBuilder @@ -1082,7 +1082,7 @@ type LeftJoinedBuilder< TB extends keyof DB, O, A extends keyof any, - R + R, > = A extends keyof DB ? UpdateQueryBuilder, UT, TB | A, O> : // Much faster non-recursive solution for the simple case. @@ -1101,7 +1101,7 @@ export type UpdateQueryBuilderWithRightJoin< UT extends keyof DB, TB extends keyof DB, O, - TE extends TableExpression + TE extends TableExpression, > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? RightJoinedBuilder @@ -1120,14 +1120,14 @@ type RightJoinedBuilder< TB extends keyof DB, O, A extends keyof any, - R + R, > = UpdateQueryBuilder, UT, TB | A, O> type RightJoinedDB< DB, TB extends keyof DB, A extends keyof any, - R + R, > = DrainOuterGeneric<{ [C in keyof DB | A]: C extends A ? R @@ -1143,7 +1143,7 @@ export type UpdateQueryBuilderWithFullJoin< UT extends keyof DB, TB extends keyof DB, O, - TE extends TableExpression + TE extends TableExpression, > = TE extends `${infer T} as ${infer A}` ? T extends keyof DB ? OuterJoinedBuilder @@ -1162,14 +1162,14 @@ type OuterJoinedBuilder< TB extends keyof DB, O, A extends keyof any, - R + R, > = UpdateQueryBuilder, UT, TB | A, O> type OuterJoinedBuilderDB< DB, TB extends keyof DB, A extends keyof any, - R + R, > = DrainOuterGeneric<{ [C in keyof DB | A]: C extends A ? Nullable From f70b30ac66e56b9e428275ed47348c58e705de54 Mon Sep 17 00:00:00 2001 From: igalklebanov Date: Thu, 22 Feb 2024 00:43:59 +0200 Subject: [PATCH 13/18] fix top parser. --- src/parser/top-parser.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/parser/top-parser.ts b/src/parser/top-parser.ts index 048b95616..6a2fce445 100644 --- a/src/parser/top-parser.ts +++ b/src/parser/top-parser.ts @@ -1,5 +1,5 @@ -import { TopModifier, TopNode } from '../operation-node/top-node' -import { isBigInt, isNumber, isString } from '../util/object-utils' +import { TopModifier, TopNode } from '../operation-node/top-node.js' +import { isBigInt, isNumber, isUndefined } from '../util/object-utils.js' export function parseTop( expression: number | bigint, @@ -9,7 +9,7 @@ export function parseTop( throw new Error(`Invalid top expression: ${expression}`) } - if (!isString(modifiers) || !isTopModifiers(modifiers)) { + if (!isUndefined(modifiers) && !isTopModifiers(modifiers)) { throw new Error(`Invalid top modifiers: ${modifiers}`) } From e26950233a96323044b0822501b550e544b0206c Mon Sep 17 00:00:00 2001 From: igalklebanov Date: Thu, 22 Feb 2024 01:06:17 +0200 Subject: [PATCH 14/18] remove unused imports. --- src/operation-node/query-node.ts | 6 +++--- src/query-builder/delete-query-builder.ts | 1 - src/query-builder/select-query-builder.ts | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/operation-node/query-node.ts b/src/operation-node/query-node.ts index 935df9ef3..0d0848eee 100644 --- a/src/operation-node/query-node.ts +++ b/src/operation-node/query-node.ts @@ -12,7 +12,7 @@ import { ExplainNode } from './explain-node.js' import { ExplainFormat } from '../util/explainable.js' import { Expression } from '../expression/expression.js' import { MergeQueryNode } from './merge-query-node.js' -import { TopModifier, TopNode } from './top-node.js' +import { TopNode } from './top-node.js' export type QueryNode = | SelectQueryNode @@ -59,7 +59,7 @@ export const QueryNode = freeze({ cloneWithReturning( node: T, - selections: ReadonlyArray + selections: ReadonlyArray, ): T { return freeze({ ...node, @@ -86,7 +86,7 @@ export const QueryNode = freeze({ cloneWithExplain( node: T, format: ExplainFormat | undefined, - options: Expression | undefined + options: Expression | undefined, ): T { return freeze({ ...node, diff --git a/src/query-builder/delete-query-builder.ts b/src/query-builder/delete-query-builder.ts index b9049729a..529dc8091 100644 --- a/src/query-builder/delete-query-builder.ts +++ b/src/query-builder/delete-query-builder.ts @@ -71,7 +71,6 @@ import { ValueExpression, parseValueExpression, } from '../parser/value-parser.js' -import { TopNode } from '../operation-node/top-node.js' import { parseTop } from '../parser/top-parser.js' export class DeleteQueryBuilder diff --git a/src/query-builder/select-query-builder.ts b/src/query-builder/select-query-builder.ts index 2317d77bf..91f784cbc 100644 --- a/src/query-builder/select-query-builder.ts +++ b/src/query-builder/select-query-builder.ts @@ -79,7 +79,7 @@ import { ValueExpression, parseValueExpression, } from '../parser/value-parser.js' -import { TopModifier, TopNode } from '../operation-node/top-node.js' +import { TopModifier } from '../operation-node/top-node.js' import { parseTop } from '../parser/top-parser.js' export interface SelectQueryBuilder From d0a5fc9d1a720d69038e885fd57ed80379e69dc0 Mon Sep 17 00:00:00 2001 From: igalklebanov Date: Thu, 22 Feb 2024 01:10:38 +0200 Subject: [PATCH 15/18] add top to merge query builder. --- src/operation-node/merge-query-node.ts | 2 + .../operation-node-transformer.ts | 1 + src/query-builder/merge-query-builder.ts | 61 +++++++++++++++++++ src/query-compiler/default-query-compiler.ts | 11 +++- 4 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/operation-node/merge-query-node.ts b/src/operation-node/merge-query-node.ts index a65b36a94..fff9eaa5a 100644 --- a/src/operation-node/merge-query-node.ts +++ b/src/operation-node/merge-query-node.ts @@ -3,6 +3,7 @@ import { AliasNode } from './alias-node.js' import { JoinNode } from './join-node.js' import { OperationNode } from './operation-node.js' import { TableNode } from './table-node.js' +import { TopNode } from './top-node.js' import { WhenNode } from './when-node.js' import { WithNode } from './with-node.js' @@ -12,6 +13,7 @@ export interface MergeQueryNode extends OperationNode { readonly using?: JoinNode readonly whens?: ReadonlyArray readonly with?: WithNode + readonly top?: TopNode } /** diff --git a/src/operation-node/operation-node-transformer.ts b/src/operation-node/operation-node-transformer.ts index f9b971dd7..804461c04 100644 --- a/src/operation-node/operation-node-transformer.ts +++ b/src/operation-node/operation-node-transformer.ts @@ -1003,6 +1003,7 @@ export class OperationNodeTransformer { using: this.transformNode(node.using), whens: this.transformNodeList(node.whens), with: this.transformNode(node.with), + top: this.transformNode(node.top), }) } diff --git a/src/query-builder/merge-query-builder.ts b/src/query-builder/merge-query-builder.ts index c00951997..ef7ca68a6 100644 --- a/src/query-builder/merge-query-builder.ts +++ b/src/query-builder/merge-query-builder.ts @@ -23,6 +23,7 @@ import { import { parseMergeThen, parseMergeWhen } from '../parser/merge-parser.js' import { ReferenceExpression } from '../parser/reference-parser.js' import { TableExpression } from '../parser/table-parser.js' +import { parseTop } from '../parser/top-parser.js' import { ExtractUpdateTypeFromReferenceExpression, UpdateObject, @@ -58,6 +59,66 @@ export class MergeQueryBuilder { this.#props = freeze(props) } + /** + * Changes a `merge into` query to an `merge top into` query. + * + * `top` clause is only supported by some dialects like MS SQL Server. + * + * ### Examples + * + * Affect 5 matched rows at most: + * + * ```ts + * await db.mergeInto('person') + * .top(5) + * .using('pet', 'person.id', 'pet.owner_id') + * .whenMatched() + * .thenDelete() + * .execute() + * ``` + * + * The generated SQL (MS SQL Server): + * + * ```sql + * merge top(5) into "person" + * using "pet" on "person"."id" = "pet"."owner_id" + * when matched then + * delete + * ``` + * + * Affect 50% of matched rows: + * + * ```ts + * await db.mergeInto('person') + * .top(50, 'percent') + * .using('pet', 'person.id', 'pet.owner_id') + * .whenMatched() + * .thenDelete() + * .execute() + * ``` + * + * The generated SQL (MS SQL Server): + * + * ```sql + * merge top(50) percent into "person" + * using "pet" on "person"."id" = "pet"."owner_id" + * when matched then + * delete + * ``` + */ + top( + expression: number | bigint, + modifiers?: 'percent', + ): MergeQueryBuilder { + return new MergeQueryBuilder({ + ...this.#props, + queryNode: QueryNode.cloneWithTop( + this.#props.queryNode, + parseTop(expression, modifiers), + ), + }) + } + /** * Adds the `using` clause to the query. * diff --git a/src/query-compiler/default-query-compiler.ts b/src/query-compiler/default-query-compiler.ts index bfd26ddf4..4482c47b4 100644 --- a/src/query-compiler/default-query-compiler.ts +++ b/src/query-compiler/default-query-compiler.ts @@ -1492,7 +1492,14 @@ export class DefaultQueryCompiler this.append(' ') } - this.append('merge into ') + this.append('merge ') + + if (node.top) { + this.visitNode(node.top) + this.append(' ') + } + + this.append('into ') this.visitNode(node.into) if (node.using) { @@ -1548,7 +1555,7 @@ export class DefaultQueryCompiler this.visitNode(node.dataType) this.append(')') } - + protected override visitTop(node: TopNode): void { this.append(`top(${node.expression})`) From cb6a57fb53d9dc7bc583e7329088c94f3a8ace02 Mon Sep 17 00:00:00 2001 From: igalklebanov Date: Thu, 22 Feb 2024 01:23:45 +0200 Subject: [PATCH 16/18] add top to WheneableMergeQueryBuilder. --- src/query-builder/merge-query-builder.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/query-builder/merge-query-builder.ts b/src/query-builder/merge-query-builder.ts index ef7ca68a6..fc3c7a1cb 100644 --- a/src/query-builder/merge-query-builder.ts +++ b/src/query-builder/merge-query-builder.ts @@ -198,6 +198,22 @@ export class WheneableMergeQueryBuilder< this.#props = freeze(props) } + /** + * See {@link MergeQueryBuilder.top}. + */ + top( + expression: number | bigint, + modifiers?: 'percent', + ): WheneableMergeQueryBuilder { + return new WheneableMergeQueryBuilder({ + ...this.#props, + queryNode: QueryNode.cloneWithTop( + this.#props.queryNode, + parseTop(expression, modifiers), + ), + }) + } + /** * Adds a simple `when matched` clause to the query. * From a10136af744b61c6587894008a5f4abd000a4170 Mon Sep 17 00:00:00 2001 From: igalklebanov Date: Thu, 22 Feb 2024 01:23:56 +0200 Subject: [PATCH 17/18] add merge test cases. --- test/node/src/merge.test.ts | 50 +++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/test/node/src/merge.test.ts b/test/node/src/merge.test.ts index 73b803f20..9fbe1bb22 100644 --- a/test/node/src/merge.test.ts +++ b/test/node/src/merge.test.ts @@ -955,5 +955,55 @@ for (const dialect of DIALECTS.filter( }) } }) + + if (dialect === 'mssql') { + it('should perform a merge top...using table simple on...when matched then delete query', async () => { + const query = ctx.db + .mergeInto('person') + .top(1) + .using('pet', 'pet.owner_id', 'person.id') + .whenMatched() + .thenDelete() + + testSql(query, dialect, { + postgres: NOT_SUPPORTED, + mysql: NOT_SUPPORTED, + mssql: { + sql: 'merge top(1) into "person" using "pet" on "pet"."owner_id" = "person"."id" when matched then delete;', + parameters: [], + }, + sqlite: NOT_SUPPORTED, + }) + + const result = await query.executeTakeFirstOrThrow() + + expect(result).to.be.instanceOf(MergeResult) + expect(result.numChangedRows).to.equal(1n) + }) + + it('should perform a merge top percent...using table simple on...when matched then delete query', async () => { + const query = ctx.db + .mergeInto('person') + .top(50, 'percent') + .using('pet', 'pet.owner_id', 'person.id') + .whenMatched() + .thenDelete() + + testSql(query, dialect, { + postgres: NOT_SUPPORTED, + mysql: NOT_SUPPORTED, + mssql: { + sql: 'merge top(50) percent into "person" using "pet" on "pet"."owner_id" = "person"."id" when matched then delete;', + parameters: [], + }, + sqlite: NOT_SUPPORTED, + }) + + const result = await query.executeTakeFirstOrThrow() + + expect(result).to.be.instanceOf(MergeResult) + expect(result.numChangedRows).to.equal(2n) + }) + } }) } From 7f88abc4ed4a8a80158dc14901b5e647d7c89011 Mon Sep 17 00:00:00 2001 From: igalklebanov Date: Sat, 24 Feb 2024 17:23:01 +0200 Subject: [PATCH 18/18] re-add select test cases. --- test/node/src/select.test.ts | 97 ++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/test/node/src/select.test.ts b/test/node/src/select.test.ts index e1665e538..00477a19d 100644 --- a/test/node/src/select.test.ts +++ b/test/node/src/select.test.ts @@ -1237,5 +1237,102 @@ for (const dialect of DIALECTS) { await query.execute() }) } + + if (dialect === 'mssql') { + it('should create a select query with top', async () => { + const query = ctx.db.selectFrom('person').select('first_name').top(2) + + testSql(query, dialect, { + postgres: NOT_SUPPORTED, + mysql: NOT_SUPPORTED, + mssql: { + sql: 'select top(2) "first_name" from "person"', + parameters: [], + }, + sqlite: NOT_SUPPORTED, + }) + + await query.execute() + }) + + it('should create a select query with top and order by', async () => { + const query = ctx.db + .selectFrom('person') + .select('first_name') + .top(2) + .orderBy('first_name') + + testSql(query, dialect, { + postgres: NOT_SUPPORTED, + mysql: NOT_SUPPORTED, + mssql: { + sql: 'select top(2) "first_name" from "person" order by "first_name"', + parameters: [], + }, + sqlite: NOT_SUPPORTED, + }) + + await query.execute() + }) + + it('should create a select query with top percent', async () => { + const query = ctx.db + .selectFrom('person') + .select('first_name') + .top(50, 'percent') + + testSql(query, dialect, { + postgres: NOT_SUPPORTED, + mysql: NOT_SUPPORTED, + mssql: { + sql: 'select top(50) percent "first_name" from "person"', + parameters: [], + }, + sqlite: NOT_SUPPORTED, + }) + + await query.execute() + }) + + it('should create a select query with top with ties', async () => { + const query = ctx.db + .selectFrom('person') + .select('first_name') + .top(2, 'with ties') + .orderBy('first_name') + + testSql(query, dialect, { + postgres: NOT_SUPPORTED, + mysql: NOT_SUPPORTED, + mssql: { + sql: 'select top(2) with ties "first_name" from "person" order by "first_name"', + parameters: [], + }, + sqlite: NOT_SUPPORTED, + }) + + await query.execute() + }) + + it('should create a select query with top percent with ties', async () => { + const query = ctx.db + .selectFrom('person') + .select('first_name') + .top(50, 'percent with ties') + .orderBy('first_name') + + testSql(query, dialect, { + postgres: NOT_SUPPORTED, + mysql: NOT_SUPPORTED, + mssql: { + sql: 'select top(50) percent with ties "first_name" from "person" order by "first_name"', + parameters: [], + }, + sqlite: NOT_SUPPORTED, + }) + + await query.execute() + }) + } }) }