Skip to content

Commit

Permalink
Speedup types with huge databases. Fixes #867 (#1080)
Browse files Browse the repository at this point in the history
  • Loading branch information
koskimas authored and igalklebanov committed Oct 3, 2024
1 parent a0fbd38 commit 86d3cad
Show file tree
Hide file tree
Showing 10 changed files with 3,380 additions and 168 deletions.
31 changes: 3 additions & 28 deletions src/expression/expression-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,7 @@ import {
import { SelectQueryNode } from '../operation-node/select-query-node.js'
import {
parseTableExpressionOrList,
TableExpression,
From,
TableExpressionOrList,
FromTables,
ExtractTableAlias,
AnyAliasedTable,
PickTableWithAlias,
parseTable,
} from '../parser/table-parser.js'
import { WithSchemaPlugin } from '../plugin/with-schema/with-schema-plugin.js'
Expand Down Expand Up @@ -83,6 +77,7 @@ import {
parseDataTypeExpression,
} from '../parser/data-type-parser.js'
import { CastNode } from '../operation-node/cast-node.js'
import { SelectFrom } from '../parser/select-from-parser.js'

export interface ExpressionBuilder<DB, TB extends keyof DB> {
/**
Expand Down Expand Up @@ -277,29 +272,9 @@ export interface ExpressionBuilder<DB, TB extends keyof DB> {
* that case Kysely typings wouldn't allow you to reference `pet.owner_id`
* because `pet` is not joined to that query.
*/
selectFrom<TE extends keyof DB & string>(
from: TE[],
): SelectQueryBuilder<DB, TB | ExtractTableAlias<DB, TE>, {}>

selectFrom<TE extends TableExpression<DB, TB>>(
from: TE[],
): SelectQueryBuilder<From<DB, TE>, FromTables<DB, TB, TE>, {}>

selectFrom<TE extends keyof DB & string>(
from: TE,
): SelectQueryBuilder<DB, TB | ExtractTableAlias<DB, TE>, {}>

selectFrom<TE extends AnyAliasedTable<DB>>(
from: TE,
): SelectQueryBuilder<
DB & PickTableWithAlias<DB, TE>,
TB | ExtractTableAlias<DB & PickTableWithAlias<DB, TE>, TE>,
{}
>

selectFrom<TE extends TableExpression<DB, TB>>(
selectFrom<TE extends TableExpressionOrList<DB, TB>>(
from: TE,
): SelectQueryBuilder<From<DB, TE>, FromTables<DB, TB, TE>, {}>
): SelectFrom<DB, TB, TE>

/**
* Creates a `case` statement/operator.
Expand Down
30 changes: 30 additions & 0 deletions src/parser/delete-from-parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { DeleteQueryBuilder } from '../query-builder/delete-query-builder.js'
import type { DeleteResult } from '../query-builder/delete-result.js'
import type { ShallowRecord } from '../util/type-utils.js'
import type {
ExtractTableAlias,
From,
FromTables,
TableExpressionOrList,
} from './table-parser.js'

export type DeleteFrom<DB, TE extends TableExpressionOrList<DB, never>> =
TE extends ReadonlyArray<infer T>
? DeleteQueryBuilder<From<DB, T>, FromTables<DB, never, T>, DeleteResult>
: TE extends keyof DB & string
? // This branch creates a good-looking type for the most common case:
// deleteFrom('person') --> DeleteQueryBuilder<DB, 'person', {}>.
// ExtractTableAlias is needed for the case where DB == any. Without it:
// deleteFrom('person as p') --> DeleteQueryBuilder<DB, 'person as p', {}>
DeleteQueryBuilder<DB, ExtractTableAlias<DB, TE>, DeleteResult>
: // This branch creates a good-looking type for common aliased case:
// deleteFrom('person as p') --> DeleteQueryBuilder<DB & { p: Person }, 'p', {}>.
TE extends `${infer T} as ${infer A}`
? T extends keyof DB
? DeleteQueryBuilder<DB & ShallowRecord<A, DB[T]>, A, DeleteResult>
: never
: DeleteQueryBuilder<
From<DB, TE>,
FromTables<DB, never, TE>,
DeleteResult
>
15 changes: 15 additions & 0 deletions src/parser/merge-into-parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { MergeQueryBuilder } from '../query-builder/merge-query-builder.js'
import type { MergeResult } from '../query-builder/merge-result.js'
import type { ShallowRecord } from '../util/type-utils.js'
import type { ExtractTableAlias, SimpleTableReference } from './table-parser.js'

export type MergeInto<
DB,
TE extends SimpleTableReference<DB>,
> = TE extends keyof DB & string
? MergeQueryBuilder<DB, ExtractTableAlias<DB, TE>, MergeResult>
: TE extends `${infer T} as ${infer A}`
? T extends keyof DB
? MergeQueryBuilder<DB & ShallowRecord<A, DB[T]>, A, MergeResult>
: never
: never
29 changes: 29 additions & 0 deletions src/parser/select-from-parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { SelectQueryBuilder } from '../query-builder/select-query-builder.js'
import type { ShallowRecord } from '../util/type-utils.js'
import type {
ExtractTableAlias,
From,
FromTables,
TableExpressionOrList,
} from './table-parser.js'

export type SelectFrom<
DB,
TB extends keyof DB,
TE extends TableExpressionOrList<DB, TB>,
> =
TE extends ReadonlyArray<infer T>
? SelectQueryBuilder<From<DB, T>, FromTables<DB, TB, T>, {}>
: TE extends keyof DB & string
? // This branch creates a good-looking type for the most common case:
// selectFrom('person') --> SelectQueryBuilder<DB, 'person', {}>.
// ExtractTableAlias is needed for the case where DB == any. Without it:
// selectFrom('person as p') --> SelectQueryBuilder<DB, 'person as p', {}>
SelectQueryBuilder<DB, TB | ExtractTableAlias<DB, TE>, {}>
: // This branch creates a good-looking type for common aliased case:
// selectFrom('person as p') --> SelectQueryBuilder<DB & { p: Person }, 'p', {}>.
TE extends `${infer T} as ${infer A}`
? T extends keyof DB
? SelectQueryBuilder<DB & ShallowRecord<A, DB[T]>, TB | A, {}>
: never
: SelectQueryBuilder<From<DB, TE>, FromTables<DB, TB, TE>, {}>
23 changes: 2 additions & 21 deletions src/parser/table-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
import { IdentifierNode } from '../operation-node/identifier-node.js'
import { OperationNode } from '../operation-node/operation-node.js'
import { AliasedExpression } from '../expression/expression.js'
import { DrainOuterGeneric, ShallowRecord } from '../util/type-utils.js'
import { DrainOuterGeneric } from '../util/type-utils.js'

export type TableExpression<DB, TB extends keyof DB> =
| AnyAliasedTable<DB>
Expand All @@ -19,17 +19,9 @@ export type TableExpressionOrList<DB, TB extends keyof DB> =
| TableExpression<DB, TB>
| ReadonlyArray<TableExpression<DB, TB>>

export type TableReference<DB> =
| SimpleTableReference<DB>
| AliasedExpression<any, any>

export type SimpleTableReference<DB> = AnyAliasedTable<DB> | AnyTable<DB>

export type AnyAliasedTable<DB> = `${AnyTable<DB>} as ${string}`

export type TableReferenceOrList<DB> =
| TableReference<DB>
| ReadonlyArray<TableReference<DB>>
export type AnyTable<DB> = keyof DB & string

export type From<DB, TE> = DrainOuterGeneric<{
[C in
Expand All @@ -56,15 +48,6 @@ export type ExtractTableAlias<DB, TE> = TE extends `${string} as ${infer TA}`
? TE
: never

export type PickTableWithAlias<
DB,
T extends AnyAliasedTable<DB>,
> = T extends `${infer TB} as ${infer A}`
? TB extends keyof DB
? ShallowRecord<A, DB[TB]>
: never
: never

type ExtractAliasFromTableExpression<DB, TE> = TE extends string
? TE extends `${string} as ${infer TA}`
? TA
Expand Down Expand Up @@ -101,8 +84,6 @@ type ExtractRowTypeFromTableExpression<
: never
: never

type AnyTable<DB> = keyof DB & string

export function parseTableExpressionOrList(
table: TableExpressionOrList<any, any>,
): OperationNode[] {
Expand Down
41 changes: 41 additions & 0 deletions src/parser/update-parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type { UpdateQueryBuilder } from '../query-builder/update-query-builder.js'
import type { UpdateResult } from '../query-builder/update-result.js'
import type { ShallowRecord } from '../util/type-utils.js'
import type {
ExtractTableAlias,
From,
FromTables,
TableExpressionOrList,
} from './table-parser.js'

export type UpdateTable<DB, TE extends TableExpressionOrList<DB, never>> =
TE extends ReadonlyArray<infer T>
? UpdateQueryBuilder<
From<DB, T>,
FromTables<DB, never, T>,
FromTables<DB, never, T>,
UpdateResult
>
: TE extends keyof DB & string
? // This branch creates a good-looking type for the most common case:
// updateTable('person') --> UpdateQueryBuilder<DB, 'person', 'person', {}>.
// ExtractTableAlias is needed for the case where DB == any. Without it:
// updateTable('person as p') --> UpdateQueryBuilder<DB, 'person as p', 'person as p', {}>
UpdateQueryBuilder<
DB,
ExtractTableAlias<DB, TE>,
ExtractTableAlias<DB, TE>,
UpdateResult
>
: // This branch creates a good-looking type for common aliased case:
// updateTable('person as p') --> UpdateQueryBuilder<DB & { p: Person }, 'p', 'p', {}>.
TE extends `${infer T} as ${infer A}`
? T extends keyof DB
? UpdateQueryBuilder<DB & ShallowRecord<A, DB[T]>, A, A, UpdateResult>
: never
: UpdateQueryBuilder<
From<DB, TE>,
FromTables<DB, never, TE>,
FromTables<DB, never, TE>,
UpdateResult
>
Loading

0 comments on commit 86d3cad

Please sign in to comment.