Skip to content

Commit

Permalink
closes #1021
Browse files Browse the repository at this point in the history
  • Loading branch information
koskimas committed Jun 16, 2024
1 parent de7e560 commit f63327e
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 47 deletions.
98 changes: 54 additions & 44 deletions src/query-builder/update-query-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -682,18 +682,28 @@ export class UpdateQueryBuilder<DB, UT extends keyof DB, TB extends keyof DB, O>
})
}

returningAll(): UpdateQueryBuilder<DB, UT, TB, Selectable<DB[TB]>> {
returningAll<T extends TB>(
tables: ReadonlyArray<T>,
): UpdateQueryBuilder<DB, UT, TB, ReturningAllRow<DB, T, O>>

returningAll<T extends TB>(
table: T,
): UpdateQueryBuilder<DB, UT, TB, ReturningAllRow<DB, T, O>>

returningAll(): UpdateQueryBuilder<DB, UT, TB, ReturningAllRow<DB, TB, O>>

returningAll(table?: any): any {
return new UpdateQueryBuilder({
...this.#props,
queryNode: QueryNode.cloneWithReturning(
this.#props.queryNode,
parseSelectAll(),
parseSelectAll(table),
),
})
}

output<OE extends OutputExpression<DB, UT>>(
selections: readonly OE[]
selections: readonly OE[],
): UpdateQueryBuilder<
DB,
UT,
Expand All @@ -702,7 +712,7 @@ export class UpdateQueryBuilder<DB, UT extends keyof DB, TB extends keyof DB, O>
>

output<CB extends OutputCallback<DB, TB>>(
callback: CB
callback: CB,
): UpdateQueryBuilder<
DB,
UT,
Expand All @@ -711,7 +721,7 @@ export class UpdateQueryBuilder<DB, UT extends keyof DB, TB extends keyof DB, O>
>

output<OE extends OutputExpression<DB, TB>>(
selection: OE
selection: OE,
): UpdateQueryBuilder<
DB,
UT,
Expand All @@ -724,19 +734,19 @@ export class UpdateQueryBuilder<DB, UT extends keyof DB, TB extends keyof DB, O>
...this.#props,
queryNode: QueryNode.cloneWithOutput(
this.#props.queryNode,
parseSelectArg(args)
parseSelectArg(args),
),
})
}

outputAll(
table: OutputPrefix
table: OutputPrefix,
): UpdateQueryBuilder<DB, UT, TB, ReturningAllRow<DB, TB, O>> {
return new UpdateQueryBuilder({
...this.#props,
queryNode: QueryNode.cloneWithOutput(
this.#props.queryNode,
parseSelectAll(table)
parseSelectAll(table),
),
})
}
Expand Down Expand Up @@ -836,8 +846,8 @@ export class UpdateQueryBuilder<DB, UT extends keyof DB, TB extends keyof DB, O>
): O2 extends UpdateResult
? UpdateQueryBuilder<DB, UT, TB, UpdateResult>
: O2 extends O & infer E
? UpdateQueryBuilder<DB, UT, TB, O & Partial<E>>
: UpdateQueryBuilder<DB, UT, TB, Partial<O2>> {
? UpdateQueryBuilder<DB, UT, TB, O & Partial<E>>
: UpdateQueryBuilder<DB, UT, TB, Partial<O2>> {
if (condition) {
return func(this) as any
}
Expand Down Expand Up @@ -1099,12 +1109,12 @@ export type UpdateQueryBuilderWithInnerJoin<
? InnerJoinedBuilder<DB, UT, TB, O, A, DB[T]>
: never
: TE extends keyof DB
? UpdateQueryBuilder<DB, UT, TB | TE, O>
: TE extends AliasedExpression<infer QO, infer QA>
? InnerJoinedBuilder<DB, UT, TB, O, QA, QO>
: TE extends (qb: any) => AliasedExpression<infer QO, infer QA>
? InnerJoinedBuilder<DB, UT, TB, O, QA, QO>
: never
? UpdateQueryBuilder<DB, UT, TB | TE, O>
: TE extends AliasedExpression<infer QO, infer QA>
? InnerJoinedBuilder<DB, UT, TB, O, QA, QO>
: TE extends (qb: any) => AliasedExpression<infer QO, infer QA>
? InnerJoinedBuilder<DB, UT, TB, O, QA, QO>
: never

type InnerJoinedBuilder<
DB,
Expand Down Expand Up @@ -1133,12 +1143,12 @@ export type UpdateQueryBuilderWithLeftJoin<
? LeftJoinedBuilder<DB, UT, TB, O, A, DB[T]>
: never
: TE extends keyof DB
? LeftJoinedBuilder<DB, UT, TB, O, TE, DB[TE]>
: TE extends AliasedExpression<infer QO, infer QA>
? LeftJoinedBuilder<DB, UT, TB, O, QA, QO>
: TE extends (qb: any) => AliasedExpression<infer QO, infer QA>
? LeftJoinedBuilder<DB, UT, TB, O, QA, QO>
: never
? LeftJoinedBuilder<DB, UT, TB, O, TE, DB[TE]>
: TE extends AliasedExpression<infer QO, infer QA>
? LeftJoinedBuilder<DB, UT, TB, O, QA, QO>
: TE extends (qb: any) => AliasedExpression<infer QO, infer QA>
? LeftJoinedBuilder<DB, UT, TB, O, QA, QO>
: never

type LeftJoinedBuilder<
DB,
Expand All @@ -1156,8 +1166,8 @@ type LeftJoinedDB<DB, A extends keyof any, R> = DrainOuterGeneric<{
[C in keyof DB | A]: C extends A
? Nullable<R>
: C extends keyof DB
? DB[C]
: never
? DB[C]
: never
}>

export type UpdateQueryBuilderWithRightJoin<
Expand All @@ -1171,12 +1181,12 @@ export type UpdateQueryBuilderWithRightJoin<
? RightJoinedBuilder<DB, UT, TB, O, A, DB[T]>
: never
: TE extends keyof DB
? RightJoinedBuilder<DB, UT, TB, O, TE, DB[TE]>
: TE extends AliasedExpression<infer QO, infer QA>
? RightJoinedBuilder<DB, UT, TB, O, QA, QO>
: TE extends (qb: any) => AliasedExpression<infer QO, infer QA>
? RightJoinedBuilder<DB, UT, TB, O, QA, QO>
: never
? RightJoinedBuilder<DB, UT, TB, O, TE, DB[TE]>
: TE extends AliasedExpression<infer QO, infer QA>
? RightJoinedBuilder<DB, UT, TB, O, QA, QO>
: TE extends (qb: any) => AliasedExpression<infer QO, infer QA>
? RightJoinedBuilder<DB, UT, TB, O, QA, QO>
: never

type RightJoinedBuilder<
DB,
Expand All @@ -1196,10 +1206,10 @@ type RightJoinedDB<
[C in keyof DB | A]: C extends A
? R
: C extends TB
? Nullable<DB[C]>
: C extends keyof DB
? DB[C]
: never
? Nullable<DB[C]>
: C extends keyof DB
? DB[C]
: never
}>

export type UpdateQueryBuilderWithFullJoin<
Expand All @@ -1213,12 +1223,12 @@ export type UpdateQueryBuilderWithFullJoin<
? OuterJoinedBuilder<DB, UT, TB, O, A, DB[T]>
: never
: TE extends keyof DB
? OuterJoinedBuilder<DB, UT, TB, O, TE, DB[TE]>
: TE extends AliasedExpression<infer QO, infer QA>
? OuterJoinedBuilder<DB, UT, TB, O, QA, QO>
: TE extends (qb: any) => AliasedExpression<infer QO, infer QA>
? OuterJoinedBuilder<DB, UT, TB, O, QA, QO>
: never
? OuterJoinedBuilder<DB, UT, TB, O, TE, DB[TE]>
: TE extends AliasedExpression<infer QO, infer QA>
? OuterJoinedBuilder<DB, UT, TB, O, QA, QO>
: TE extends (qb: any) => AliasedExpression<infer QO, infer QA>
? OuterJoinedBuilder<DB, UT, TB, O, QA, QO>
: never

type OuterJoinedBuilder<
DB,
Expand All @@ -1238,8 +1248,8 @@ type OuterJoinedBuilderDB<
[C in keyof DB | A]: C extends A
? Nullable<R>
: C extends TB
? Nullable<DB[C]>
: C extends keyof DB
? DB[C]
: never
? Nullable<DB[C]>
: C extends keyof DB
? DB[C]
: never
}>
29 changes: 29 additions & 0 deletions test/node/src/delete.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,35 @@ for (const dialect of DIALECTS) {
await query.execute()
})

it('should delete from t1 using t2, t3 returning t2.*', async () => {
const query = ctx.db
.deleteFrom('toy')
.using(['pet', 'person'])
.whereRef('toy.pet_id', '=', 'pet.id')
.whereRef('pet.owner_id', '=', 'person.id')
.where('person.first_name', '=', 'Bob')
.returningAll('pet')

testSql(query, dialect, {
postgres: {
sql: [
'delete from "toy"',
'using "pet", "person"',
'where "toy"."pet_id" = "pet"."id"',
'and "pet"."owner_id" = "person"."id"',
'and "person"."first_name" = $1',
'returning "pet".*',
],
parameters: ['Bob'],
},
mysql: NOT_SUPPORTED,
mssql: NOT_SUPPORTED,
sqlite: NOT_SUPPORTED,
})

await query.execute()
})

it('should delete from t1 returning *', async () => {
const query = ctx.db
.deleteFrom('pet')
Expand Down
30 changes: 30 additions & 0 deletions test/node/src/object-util.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { isPlainObject } from '../../../dist/cjs/util/object-utils'

import { expect } from './test-setup.js'

describe('object util', () => {
it('isPlainObject', async () => {
class SomeClass {}

for (const obj of [{ foo: 'bar' }, Object.create(null)]) {
expect(isPlainObject(obj)).to.equal(true)
}

for (const obj of [
[],
new Date(),
Buffer.allocUnsafe(10),
new ArrayBuffer(10),
new Int32Array(10),
new Float64Array(10),
'',
42,
false,
null,
undefined,
new SomeClass(),
]) {
expect(isPlainObject(obj)).to.equal(false)
}
})
})
28 changes: 28 additions & 0 deletions test/node/src/update.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,34 @@ for (const dialect of DIALECTS) {
})
}

if (dialect === 'postgres') {
it('should update some rows and return joined rows when `returningAll` is used', async () => {
const query = ctx.db
.updateTable('person')
.from('pet')
.set({
first_name: (eb) => eb.ref('pet.name'),
})
.whereRef('pet.owner_id', '=', 'person.id')
.where('person.first_name', '=', 'Arnold')
.returningAll('pet')

testSql(query, dialect, {
postgres: {
sql: 'update "person" set "first_name" = "pet"."name" from "pet" where "pet"."owner_id" = "person"."id" and "person"."first_name" = $1 returning "pet".*',
parameters: ['Arnold'],
},
mysql: NOT_SUPPORTED,
mssql: NOT_SUPPORTED,
sqlite: NOT_SUPPORTED,
})

const result = await query.execute()
expect(result[0].name).to.equal('Doggo')
expect(result[0].species).to.equal('dog')
})
}

if (dialect === 'postgres') {
it('should update multiple rows and stream returned results', async () => {
const stream = ctx.db
Expand Down
9 changes: 9 additions & 0 deletions test/typings/test-d/delete-query-builder.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ async function testDelete(db: Kysely<Database>) {
.executeTakeFirstOrThrow()
expectType<DeleteResult>(r7)

const r8 = await db
.deleteFrom('pet')
.using('person')
.leftJoin('pet', 'pet.owner_id', 'person.id')
.where('person.id', '=', 1)
.returningAll('person')
.executeTakeFirstOrThrow()
expectType<Selectable<Person>>(r8)

expectError(db.deleteFrom('NO_SUCH_TABLE'))
expectError(db.deleteFrom('pet').where('NO_SUCH_COLUMN', '=', '1'))
expectError(db.deleteFrom('pet').whereRef('owner_id', '=', 'NO_SUCH_COLUMN'))
Expand Down
20 changes: 17 additions & 3 deletions test/typings/test-d/infer-result.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,23 @@ function testInferResultUpdateQuery(db: Kysely<Database>) {
const query1 = query0.returningAll()
const compiledQuery1 = query1.compile()

type Expected1 = Selectable<Person | Pet>[]
expectType<Equals<Expected1, InferResult<typeof query1>>>(true)
expectType<Equals<Expected1, InferResult<typeof compiledQuery1>>>(true)
type Expected1 = {
id: string | number
first_name: string
last_name: string | null
age: number
gender: 'male' | 'female' | 'other'
marital_status: 'single' | 'married' | 'divorced' | 'widowed' | null
modified_at: Date
deleted_at: Date | null
name: string
owner_id: number
species: 'dog' | 'cat'
}[]

const expected1: Expected1 = undefined!
expectType<InferResult<typeof query1>>(expected1)
expectType<InferResult<typeof compiledQuery1>>(expected1)

const query2 = query0.returning('modified_at')
const compiledQuery2 = query2.compile()
Expand Down
16 changes: 16 additions & 0 deletions test/typings/test-d/update.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@ async function testUpdate(db: Kysely<Database>) {
.executeTakeFirst()
expectType<UpdateResult>(r4)

const r5 = await db
.updateTable('pet')
.from((eb) =>
eb
.selectFrom('person')
.select(['person.id as person_id', 'first_name as fn'])
.where('person.first_name', '=', 'Jennifer')
.forUpdate()
.skipLocked()
.as('p'),
)
.set('name', (eb) => eb.ref('p.fn'))
.returningAll('p')
.execute()
expectType<{ fn: string; person_id: number }[]>(r5)

// Non-existent column
expectError(
db
Expand Down

0 comments on commit f63327e

Please sign in to comment.