Skip to content

Commit

Permalink
add to insert query builder.
Browse files Browse the repository at this point in the history
  • Loading branch information
igalklebanov committed Dec 29, 2023
1 parent 132f3e7 commit d26ac31
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 5 deletions.
2 changes: 2 additions & 0 deletions src/operation-node/insert-query-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<InsertQueryNode, 'kind' | 'into'>
Expand All @@ -22,6 +23,7 @@ export interface InsertQueryNode extends OperationNode {
readonly ignore?: boolean
readonly replace?: boolean
readonly explain?: ExplainNode
readonly top?: TopNode
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/operation-node/operation-node-transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ export class OperationNodeTransformer {
ignore: node.ignore,
replace: node.replace,
explain: this.transformNode(node.explain),
top: this.transformNode(node.top),
})
}

Expand Down
4 changes: 2 additions & 2 deletions src/query-builder/delete-query-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,9 @@ export class DeleteQueryBuilder<DB, TB extends keyof DB, O>
}

/**
* 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
*
Expand Down
57 changes: 57 additions & 0 deletions src/query-builder/insert-query-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,63 @@ export class InsertQueryBuilder<DB, TB extends keyof DB, O>
})
}

/**
* 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<DB, TB, O> {
return new InsertQueryBuilder({
...this.#props,
queryNode: QueryNode.cloneWithTop(
this.#props.queryNode,
expression,
modifiers
),
})
}

/**
* Adds an `on conflict` clause to the query.
*
Expand Down
2 changes: 1 addition & 1 deletion src/query-builder/select-query-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1080,7 +1080,7 @@ export interface SelectQueryBuilder<DB, TB extends keyof DB, O>
offset(offset: number): SelectQueryBuilder<DB, TB, O>

/**
* 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.
*
Expand Down
4 changes: 2 additions & 2 deletions src/query-builder/update-query-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,9 @@ export class UpdateQueryBuilder<DB, UT extends keyof DB, TB extends keyof DB, O>
}

/**
* 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
*
Expand Down
5 changes: 5 additions & 0 deletions src/query-compiler/default-query-compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
46 changes: 46 additions & 0 deletions test/node/src/insert.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down

0 comments on commit d26ac31

Please sign in to comment.