Improved PaginateConfig and Column autocompletion (#931)

This commit is contained in:
Robin De Schepper 2024-06-21 11:48:20 +02:00 committed by GitHub
parent dfecad17f6
commit acd158961f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 54 additions and 14 deletions

View File

@ -1,36 +1,72 @@
import { SelectQueryBuilder } from 'typeorm'
import { ColumnMetadata } from 'typeorm/metadata/ColumnMetadata'
/**
* Joins 2 keys as `K`, `K.P`, `K.(P` or `K.P)`
* The parenthesis notation is included for embedded columns
*/
type Join<K, P> = K extends string
? P extends string
? `${K}${'' extends P ? '' : '.'}${P | `(${P}` | `${P})`}`
: never
: never
/**
* Get the previous number between 0 and 10. Examples:
* Prev[3] = 2
* Prev[0] = never.
* Prev[20] = 0
*/
type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...0[]]
// unwrap Promise type
/**
* Unwrap Promise<T> to T
*/
type UnwrapPromise<T> = T extends Promise<infer U> ? UnwrapPromise<U> : T
// Unwrap Array type
/**
* Unwrap Array<T> to T
*/
type UnwrapArray<T> = T extends Array<infer U> ? UnwrapArray<U> : T
// TODO: puts some comments here, in this ternary of doom
/**
* Find all the dotted path properties for a given column.
*
* T: The column
* D: max depth
*/
// v Have we reached max depth?
export type Column<T, D extends number = 2> = [D] extends [never]
? never
: T extends Record<string, any>
? // yes, stop recursing
never
: // Are we extending something with keys?
T extends Record<string, any>
? {
// For every keyof T, find all possible properties as a string union
[K in keyof T]-?: K extends string
? T[K] extends Date
? `${K}`
: T[K] extends Array<infer U>
? `${K}` | Join<K, Column<UnwrapArray<U>, Prev[D]>>
: T[K] extends Promise<infer U>
? U extends Array<infer V>
? // Is it string or number (includes enums)?
T[K] extends string | number
? // yes, add just the key
`${K}`
: // Is it a Date?
T[K] extends Date
? // yes, add just the key
`${K}`
: // no, is it an array?
T[K] extends Array<infer U>
? // yes, unwrap it, and recurse deeper
`${K}` | Join<K, Column<UnwrapArray<U>, Prev[D]>>
: // no, is it a promise?
T[K] extends Promise<infer U>
? // yes, try to infer its return type and recurse
U extends Array<infer V>
? `${K}` | Join<K, Column<UnwrapArray<V>, Prev[D]>>
: `${K}` | Join<K, Column<UnwrapPromise<U>, Prev[D]>>
: `${K}` | Join<K, Column<T[K], Prev[D]>>
: // no, we have no more special cases, so treat it as an
// object and recurse deeper on its keys
`${K}` | Join<K, Column<T[K], Prev[D]>>
: never
// Join all the string unions of each keyof T into a single string union
}[keyof T]
: ''

View File

@ -70,13 +70,17 @@ export interface PaginateConfig<T> {
sortableColumns: Column<T>[]
nullSort?: 'first' | 'last'
searchableColumns?: Column<T>[]
select?: Column<T>[] | string[]
// see https://github.com/microsoft/TypeScript/issues/29729 for (string & {})
// eslint-disable-next-line @typescript-eslint/ban-types
select?: (Column<T> | (string & {}))[]
maxLimit?: number
defaultSortBy?: SortBy<T>
defaultLimit?: number
where?: FindOptionsWhere<T> | FindOptionsWhere<T>[]
filterableColumns?: {
[key in Column<T> | string]?: (FilterOperator | FilterSuffix)[] | true
// see https://github.com/microsoft/TypeScript/issues/29729 for (string & {})
// eslint-disable-next-line @typescript-eslint/ban-types
[key in Column<T> | (string & {})]?: (FilterOperator | FilterSuffix)[] | true
}
loadEagerRelations?: boolean
withDeleted?: boolean