2023-01-30 11:17:14 +00:00
|
|
|
import { SelectQueryBuilder } from 'typeorm'
|
|
|
|
import { ColumnMetadata } from 'typeorm/metadata/ColumnMetadata'
|
|
|
|
|
2023-03-14 18:12:30 +00:00
|
|
|
type Join<K, P> = K extends string
|
|
|
|
? P extends string
|
|
|
|
? `${K}${'' extends P ? '' : '.'}${P | `(${P}` | `${P})`}`
|
|
|
|
: never
|
|
|
|
: never
|
2022-03-14 19:48:41 +00:00
|
|
|
|
|
|
|
type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...0[]]
|
|
|
|
|
2022-12-13 11:35:08 +00:00
|
|
|
// TODO: puts some comments here, in this ternary of doom
|
2022-03-14 19:48:41 +00:00
|
|
|
export type Column<T, D extends number = 2> = [D] extends [never]
|
|
|
|
? never
|
|
|
|
: T extends Record<string, any>
|
|
|
|
? {
|
|
|
|
[K in keyof T]-?: K extends string
|
|
|
|
? T[K] extends Date
|
|
|
|
? `${K}`
|
|
|
|
: T[K] extends Array<infer U>
|
|
|
|
? `${K}` | Join<K, Column<U, Prev[D]>>
|
|
|
|
: `${K}` | Join<K, Column<T[K], Prev[D]>>
|
|
|
|
: never
|
|
|
|
}[keyof T]
|
|
|
|
: ''
|
|
|
|
|
|
|
|
export type RelationColumn<T> = Extract<
|
|
|
|
Column<T>,
|
|
|
|
{
|
|
|
|
[K in Column<T>]: K extends `${infer R}.${string}` ? R : never
|
|
|
|
}[Column<T>]
|
|
|
|
>
|
|
|
|
|
|
|
|
export type Order<T> = [Column<T>, 'ASC' | 'DESC']
|
|
|
|
export type SortBy<T> = Order<T>[]
|
2022-12-13 11:35:08 +00:00
|
|
|
|
|
|
|
export const positiveNumberOrDefault = (value: number | undefined, defaultValue: number, minValue: 0 | 1 = 0) =>
|
|
|
|
value === undefined || value < minValue ? defaultValue : value
|
2023-01-30 11:17:14 +00:00
|
|
|
|
2023-03-14 18:31:38 +00:00
|
|
|
export type ColumnProperties = { propertyPath?: string; propertyName: string; isNested: boolean; column: string }
|
2023-01-30 11:17:14 +00:00
|
|
|
|
|
|
|
export function getPropertiesByColumnName(column: string): ColumnProperties {
|
|
|
|
const propertyPath = column.split('.')
|
2023-03-14 18:12:30 +00:00
|
|
|
if (propertyPath.length > 1) {
|
|
|
|
const propertyNamePath = propertyPath.slice(1)
|
2023-03-14 18:31:38 +00:00
|
|
|
let isNested = false,
|
2023-03-14 18:12:30 +00:00
|
|
|
propertyName = propertyNamePath.join('.')
|
|
|
|
|
|
|
|
if (!propertyName.startsWith('(') && propertyNamePath.length > 1) {
|
2023-03-14 18:31:38 +00:00
|
|
|
isNested = true
|
2023-03-14 18:12:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
propertyName = propertyName.replace('(', '').replace(')', '')
|
|
|
|
|
|
|
|
return {
|
|
|
|
propertyPath: propertyPath[0],
|
|
|
|
propertyName, // the join is in case of an embedded entity
|
2023-03-14 18:31:38 +00:00
|
|
|
isNested,
|
2023-03-14 18:12:30 +00:00
|
|
|
column: `${propertyPath[0]}.${propertyName}`,
|
|
|
|
}
|
|
|
|
} else {
|
2023-03-14 18:31:38 +00:00
|
|
|
return { propertyName: propertyPath[0], isNested: false, column: propertyPath[0] }
|
2023-03-14 18:12:30 +00:00
|
|
|
}
|
2023-01-30 11:17:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export function extractVirtualProperty(
|
|
|
|
qb: SelectQueryBuilder<unknown>,
|
|
|
|
columnProperties: ColumnProperties
|
|
|
|
): { isVirtualProperty: boolean; query?: ColumnMetadata['query'] } {
|
|
|
|
const metadata = columnProperties.propertyPath
|
|
|
|
? qb?.expressionMap?.mainAlias?.metadata?.findColumnWithPropertyPath(columnProperties.propertyPath)
|
|
|
|
?.referencedColumn?.entityMetadata // on relation
|
|
|
|
: qb?.expressionMap?.mainAlias?.metadata
|
|
|
|
return (
|
|
|
|
metadata?.columns?.find((column) => column.propertyName === columnProperties.propertyName) || {
|
|
|
|
isVirtualProperty: false,
|
|
|
|
query: undefined,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-03-01 11:23:17 +00:00
|
|
|
export function includesAllPrimaryKeyColumns(qb: SelectQueryBuilder<unknown>, propertyPath: string[]): boolean {
|
|
|
|
if (!qb || !propertyPath) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return qb.expressionMap.mainAlias?.metadata?.primaryColumns
|
|
|
|
.map((column) => column.propertyPath)
|
|
|
|
.every((column) => propertyPath.includes(column))
|
|
|
|
}
|
|
|
|
|
|
|
|
export function hasColumnWithPropertyPath(
|
|
|
|
qb: SelectQueryBuilder<unknown>,
|
|
|
|
columnProperties: ColumnProperties
|
|
|
|
): boolean {
|
|
|
|
if (!qb || !columnProperties) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return !!qb.expressionMap.mainAlias?.metadata?.hasColumnWithPropertyPath(columnProperties.propertyName)
|
|
|
|
}
|
|
|
|
|
2023-01-30 11:17:14 +00:00
|
|
|
export function checkIsRelation(qb: SelectQueryBuilder<unknown>, propertyPath: string): boolean {
|
|
|
|
if (!qb || !propertyPath) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return !!qb?.expressionMap?.mainAlias?.metadata?.hasRelationWithPropertyPath(propertyPath)
|
|
|
|
}
|
|
|
|
|
2023-02-15 08:05:52 +00:00
|
|
|
export function checkIsEmbedded(qb: SelectQueryBuilder<unknown>, propertyPath: string): boolean {
|
|
|
|
if (!qb || !propertyPath) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return !!qb?.expressionMap?.mainAlias?.metadata?.hasEmbeddedWithPropertyPath(propertyPath)
|
|
|
|
}
|
|
|
|
|
2023-01-30 11:17:14 +00:00
|
|
|
// This function is used to fix the column alias when using relation, embedded or virtual properties
|
|
|
|
export function fixColumnAlias(
|
|
|
|
properties: ColumnProperties,
|
|
|
|
alias: string,
|
|
|
|
isRelation = false,
|
|
|
|
isVirtualProperty = false,
|
2023-02-15 08:05:52 +00:00
|
|
|
isEmbedded = false,
|
2023-01-30 11:17:14 +00:00
|
|
|
query?: ColumnMetadata['query']
|
|
|
|
): string {
|
|
|
|
if (isRelation) {
|
|
|
|
if (isVirtualProperty && query) {
|
|
|
|
return `(${query(`${alias}_${properties.propertyPath}`)})` // () is needed to avoid parameter conflict
|
2023-03-14 18:31:38 +00:00
|
|
|
} else if ((isVirtualProperty && !query) || properties.isNested) {
|
2023-01-30 11:17:14 +00:00
|
|
|
return `${alias}_${properties.propertyPath}_${properties.propertyName}`
|
|
|
|
} else {
|
2023-02-15 08:05:52 +00:00
|
|
|
return `${alias}_${properties.propertyPath}.${properties.propertyName}`
|
2023-01-30 11:17:14 +00:00
|
|
|
}
|
|
|
|
} else if (isVirtualProperty) {
|
|
|
|
return query ? `(${query(`${alias}`)})` : `${alias}_${properties.propertyName}`
|
2023-02-15 08:05:52 +00:00
|
|
|
} else if (isEmbedded) {
|
|
|
|
return `${alias}.${properties.propertyPath}.${properties.propertyName}`
|
2023-01-30 11:17:14 +00:00
|
|
|
} else {
|
2023-02-15 08:05:52 +00:00
|
|
|
return `${alias}.${properties.propertyName}`
|
2023-01-30 11:17:14 +00:00
|
|
|
}
|
|
|
|
}
|