import { Brackets , WhereExpression } from 'typeorm' ; import { Filter , FilterComparisons , FilterFieldComparison } from '@nestjs-query/core' ; import { EntityComparisonField , SQLComparisonBuilder } from './sql-comparison.builder' ; import { NestedRecord } from './filter-query.builder' ; internal export class WhereBuilder < Entity > { constructor ( readonly sqlComparisonBuilder = new SQLComparisonBuilder < Entity > ( ) ) { } param where param filter param relationNames param alias build < Where extends WhereExpression > ( where , filter , relationNames , alias ? ) { const { and , or } = filter ; if ( and && and . length ) { this . filterAnd ( where , and , relationNames , alias ) ; } if ( or && or . length ) { this . filterOr ( where , or , relationNames , alias ) ; } return this . filterFields ( where , filter , relationNames , alias ) ; } param where param filters param relationNames param alias private filterAnd < Where extends WhereExpression > ( where , filters , relationNames , alias ? ) { return where . andWhere ( new Brackets ( ( qb ) => filters . reduce ( ( w , f ) => qb . andWhere ( this . createBrackets ( f , relationNames , alias ) ) , qb ) ) ) ; } param where param filter param relationNames param alias private filterOr < Where extends WhereExpression > ( where , filter , relationNames , alias ? ) { return where . andWhere ( new Brackets ( ( qb ) => filter . reduce ( ( w , f ) => qb . orWhere ( this . createBrackets ( f , relationNames , alias ) ) , qb ) ) ) ; } param filter param relationNames param alias private createBrackets ( filter , relationNames , alias ? ) { return new Brackets ( ( qb ) => this . build ( qb , filter , relationNames , alias ) ) ; } param where param filter param relationNames param alias private filterFields < Where extends WhereExpression > ( where , filter , relationNames , alias ? ) { return Object . keys ( filter ) . reduce ( ( w , field ) => { if ( field !== 'and' && field !== 'or' ) { return this . withFilterComparison ( where , field as keyof Entity , this . getField ( filter , field as keyof Entity ) , relationNames , alias ) ; } return w ; } , where ) ; } private getField < K extends keyof FilterComparisons < Entity > > ( obj , field ) { return obj [ field ] as FilterFieldComparison < Entity [ K ] > ; } private withFilterComparison < T extends keyof Entity , Where extends WhereExpression > ( where , field , cmp , relationNames , alias ? ) { if ( relationNames [ field as string ] ) { return this . withRelationFilter ( where , field , cmp as Filter < Entity [ T ] > , relationNames [ field as string ] ) ; } return where . andWhere ( new Brackets ( ( qb ) => { const opts = Object . keys ( cmp ) as ( keyof FilterFieldComparison < Entity [ T ] > ) [ ] ; const sqlComparisons = opts . map ( ( cmpType ) => this . sqlComparisonBuilder . build ( field , cmpType , cmp [ cmpType ] as EntityComparisonField < Entity , T > , alias ) ) ; sqlComparisons . map ( ( { sql , params } ) => qb . orWhere ( sql , params ) ) ; } ) ) ; } private withRelationFilter < T extends keyof Entity , Where extends WhereExpression > ( where , field , cmp , relationNames ) { return where . andWhere ( new Brackets ( ( qb ) => { const relationWhere = new WhereBuilder < Entity [ T ] > ( ) ; return relationWhere . build ( qb , cmp , relationNames , field as string ) ; } ) ) ; } }