Skip to content

Commit

Permalink
Merge branch 'master' into case
Browse files Browse the repository at this point in the history
  • Loading branch information
igalklebanov authored Apr 9, 2023
2 parents 7f127d7 + a5425ca commit 36d6ecf
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 0 deletions.
46 changes: 46 additions & 0 deletions src/query-builder/delete-query-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { ReferenceExpression } from '../parser/reference-parser.js'
import { QueryNode } from '../operation-node/query-node.js'
import {
MergePartial,
NarrowPartial,
Nullable,
SimplifyResult,
SimplifySingleResult,
Expand Down Expand Up @@ -815,6 +816,51 @@ export class DeleteQueryBuilder<DB, TB extends keyof DB, O>
return this.$castTo<T>()
}

/**
* Narrows (parts of) the output type of the query.
*
* Kysely tries to be as type-safe as possible, but in some cases we have to make
* compromises for better maintainability and compilation performance. At present,
* Kysely doesn't narrow the output type of the query when using {@link where} and {@link returning} or {@link returningAll}.
*
* This utility method is very useful for these situations, as it removes unncessary
* runtime assertion/guard code. Its input type is limited to the output type
* of the query, so you can't add a column that doesn't exist, or change a column's
* type to something that doesn't exist in its union type.
*
* ### Examples
*
* Turn this code:
*
* ```ts
* const person = await db.deleteFrom('person')
* .where('id', '=', id)
* .where('nullable_column', 'is not', null)
* .returningAll()
* .executeTakeFirstOrThrow()
*
* if (person.nullable_column) {
* functionThatExpectsPersonWithNonNullValue(person)
* }
* ```
*
* Into this:
*
* ```ts
* const person = await db.deleteFrom('person')
* .where('id', '=', id)
* .where('nullable_column', 'is not', null)
* .returningAll()
* .$narrowType<{ nullable_column: string }>()
* .executeTakeFirstOrThrow()
*
* functionThatExpectsPersonWithNonNullValue(person)
* ```
*/
$narrowType<T>(): DeleteQueryBuilder<DB, TB, NarrowPartial<O, T>> {
return new DeleteQueryBuilder(this.#props)
}

/**
* Asserts that query's output row type equals the given type `T`.
*
Expand Down
45 changes: 45 additions & 0 deletions src/query-builder/insert-query-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { InsertQueryNode } from '../operation-node/insert-query-node.js'
import { QueryNode } from '../operation-node/query-node.js'
import {
MergePartial,
NarrowPartial,
SimplifyResult,
SimplifySingleResult,
} from '../util/type-utils.js'
Expand Down Expand Up @@ -652,6 +653,50 @@ export class InsertQueryBuilder<DB, TB extends keyof DB, O>
return this.$castTo<T>()
}

/**
* Narrows (parts of) the output type of the query.
*
* Kysely tries to be as type-safe as possible, but in some cases we have to make
* compromises for better maintainability and compilation performance. At present,
* Kysely doesn't narrow the output type of the query based on {@link values} input
* when using {@link returning} or {@link returningAll}.
*
* This utility method is very useful for these situations, as it removes unncessary
* runtime assertion/guard code. Its input type is limited to the output type
* of the query, so you can't add a column that doesn't exist, or change a column's
* type to something that doesn't exist in its union type.
*
* ### Examples
*
* Turn this code:
*
* ```ts
* const person = await db.insertInto('person')
* .values({ ...inputPerson, nullable_column: 'hell yeah!' })
* .returningAll()
* .executeTakeFirstOrThrow()
*
* if (nullable_column) {
* functionThatExpectsPersonWithNonNullValue(person)
* }
* ```
*
* Into this:
*
* ```ts
* const person = await db.insertInto('person')
* .values({ ...inputPerson, nullable_column: 'hell yeah!' })
* .returningAll()
* .$narrowType<{ nullable_column: string }>()
* .executeTakeFirstOrThrow()
*
* functionThatExpectsPersonWithNonNullValue(person)
* ```
*/
$narrowType<T>(): InsertQueryBuilder<DB, TB, NarrowPartial<O, T>> {
return new InsertQueryBuilder(this.#props)
}

/**
* Asserts that query's output row type equals the given type `T`.
*
Expand Down
45 changes: 45 additions & 0 deletions src/query-builder/select-query-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { SelectQueryNode } from '../operation-node/select-query-node.js'
import { QueryNode } from '../operation-node/query-node.js'
import {
MergePartial,
NarrowPartial,
Nullable,
Simplify,
SimplifySingleResult,
Expand Down Expand Up @@ -1772,6 +1773,50 @@ export class SelectQueryBuilder<DB, TB extends keyof DB, O>
return this.$castTo<T>()
}

/**
* Narrows (parts of) the output type of the query.
*
* Kysely tries to be as type-safe as possible, but in some cases we have to make
* compromises for better maintainability and compilation performance. At present,
* Kysely doesn't narrow the output type of the query when using {@link where}, {@link having}
* or {@link JoinQueryBuilder.on}.
*
* This utility method is very useful for these situations, as it removes unncessary
* runtime assertion/guard code. Its input type is limited to the output type
* of the query, so you can't add a column that doesn't exist, or change a column's
* type to something that doesn't exist in its union type.
*
* ### Examples
*
* Turn this code:
*
* ```ts
* const person = await db.selectFrom('person')
* .where('nullable_column', 'is not', null)
* .selectAll()
* .executeTakeFirstOrThrow()
*
* if (person.nullable_column) {
* functionThatExpectsPersonWithNonNullValue(person)
* }
* ```
*
* Into this:
*
* ```ts
* const person = await db.selectFrom('person')
* .where('nullable_column', 'is not', null)
* .selectAll()
* .$narrowType<{ nullable_column: string }>()
* .executeTakeFirstOrThrow()
*
* functionThatExpectsPersonWithNonNullValue(person)
* ```
*/
$narrowType<T>(): SelectQueryBuilder<DB, TB, NarrowPartial<O, T>> {
return new SelectQueryBuilder(this.#props)
}

/**
* Asserts that query's output row type equals the given type `T`.
*
Expand Down
49 changes: 49 additions & 0 deletions src/query-builder/update-query-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { ReferenceExpression } from '../parser/reference-parser.js'
import { QueryNode } from '../operation-node/query-node.js'
import {
MergePartial,
NarrowPartial,
Nullable,
SimplifyResult,
SimplifySingleResult,
Expand Down Expand Up @@ -729,6 +730,54 @@ export class UpdateQueryBuilder<DB, UT extends keyof DB, TB extends keyof DB, O>
return this.$castTo<T>()
}

/**
* Narrows (parts of) the output type of the query.
*
* Kysely tries to be as type-safe as possible, but in some cases we have to make
* compromises for better maintainability and compilation performance. At present,
* Kysely doesn't narrow the output type of the query based on {@link set} input
* when using {@link where} and/or {@link returning} or {@link returningAll}.
*
* This utility method is very useful for these situations, as it removes unncessary
* runtime assertion/guard code. Its input type is limited to the output type
* of the query, so you can't add a column that doesn't exist, or change a column's
* type to something that doesn't exist in its union type.
*
* ### Examples
*
* Turn this code:
*
* ```ts
* const person = await db.updateTable('person')
* .set({ deletedAt: now })
* .where('id', '=', id)
* .where('nullable_column', 'is not', null)
* .returningAll()
* .executeTakeFirstOrThrow()
*
* if (person.nullable_column) {
* functionThatExpectsPersonWithNonNullValue(person)
* }
* ```
*
* Into this:
*
* ```ts
* const person = await db.updateTable('person')
* .set({ deletedAt: now })
* .where('id', '=', id)
* .where('nullable_column', 'is not', null)
* .returningAll()
* .$narrowType<{ deletedAt: Date; nullable_column: string }>()
* .executeTakeFirstOrThrow()
*
* functionThatExpectsPersonWithNonNullValue(person)
* ```
*/
$narrowType<T>(): UpdateQueryBuilder<DB, UT, TB, NarrowPartial<O, T>> {
return new UpdateQueryBuilder(this.#props)
}

/**
* Asserts that query's output row type equals the given type `T`.
*
Expand Down
9 changes: 9 additions & 0 deletions src/util/type-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { SelectQueryBuilder } from '../query-builder/select-query-builder.js'
import { InsertResult } from '../query-builder/insert-result.js'
import { DeleteResult } from '../query-builder/delete-result.js'
import { UpdateResult } from '../query-builder/update-result.js'
import { KyselyTypeError } from './type-error.js'

/**
* Given an object type, extracts the union of all value types.
Expand Down Expand Up @@ -186,4 +187,12 @@ export type Equals<T, U> = (<G>() => G extends T ? 1 : 2) extends <
? true
: false

export type NarrowPartial<S, T> = {
[K in keyof S & string]: K extends keyof T
? T[K] extends S[K]
? T[K]
: KyselyTypeError<`$narrowType() call failed: passed type does not exist in '${K}'s type union`>
: S[K]
}

export type SqlBool = boolean | 0 | 1

0 comments on commit 36d6ecf

Please sign in to comment.