import { WhereOptions , Op , Association } from 'sequelize' ; import { Filter , FilterComparisons , FilterFieldComparison } from '@nestjs-query/core' ; import { EntityComparisonField , SQLComparisonBuilder } from './sql-comparison.builder' ; internal export class WhereBuilder < Entity > { constructor ( readonly sqlComparisonBuilder = new SQLComparisonBuilder < Entity > ( ) ) { } param filter param associations build ( filter , associations , alias ? ) { const { and , or } = filter ; let ands = [ ] ; let ors = [ ] ; let whereOpts = { } ; if ( and && and . length ) { ands = and . map ( ( f ) => this . build ( f , associations , alias ) ) ; } if ( or && or . length ) { ors = or . map ( ( f ) => this . build ( f , associations , alias ) ) ; } const filterAnds = this . filterFields ( filter , associations , alias ) ; if ( filterAnds ) { ands = [ ... ands , filterAnds ] ; } if ( ands . length ) { whereOpts = { ... whereOpts , [ Op . and ] : ands } ; } if ( ors . length ) { whereOpts = { ... whereOpts , [ Op . or ] : ors } ; } return whereOpts ; } param filter private filterFields ( filter , associations , alias ? ) { const ands = Object . keys ( filter ) . filter ( ( f ) => f !== 'and' && f !== 'or' ) . map ( ( field ) => this . withFilterComparison ( field as keyof Entity , this . getField ( filter , field as keyof Entity ) , associations , alias ) ) ; if ( ands . length === 1 ) { return ands [ 0 ] ; } if ( ands . length ) { return { [ Op . and ] : ands } ; } return undefined ; } private getField < K extends keyof FilterComparisons < Entity > > ( obj , field ) { return obj [ field ] as FilterFieldComparison < Entity [ K ] > ; } private withFilterComparison < T extends keyof Entity > ( field , cmp , associations , alias ? ) { if ( associations . has ( field as string ) ) { const wb = new WhereBuilder < Entity [ T ] > ( ) ; return wb . build ( cmp as unknown as Filter < Entity [ T ] > , associations , field as string ) ; } let colName = field ; if ( alias && associations . has ( alias ) ) { colName = ( associations . get ( alias ) ?. target . rawAttributes [ colName as string ] ?. field ?? colName ) as T ; } const opts = Object . keys ( cmp ) as ( keyof FilterFieldComparison < Entity [ T ] > ) [ ] ; if ( opts . length === 1 ) { const cmpType = opts [ 0 ] ; return this . sqlComparisonBuilder . build ( colName , cmpType , cmp [ cmpType ] as EntityComparisonField < Entity , T > , alias ) ; } return { [ Op . or ] : opts . map ( ( cmpType ) => this . sqlComparisonBuilder . build ( colName , cmpType , cmp [ cmpType ] as EntityComparisonField < Entity , T > , alias ) ) , } ; } }