import { Mapping } from '../Mapping' ; import { QueryBuilder } from 'knex' ; /**
 * Parse and apply criteria to statement.
 */ export class Criteria { type { { } } protected conditions : { and : string ; or : string ; } = { and : 'where' , or : 'orWhere' } ; type { string } protected defaultCondition : string = 'and' ; type { { } } private operators = { '<' : { operator : '<' , value : value => value } , 'lt' : { operator : '<' , value : value => value } , 'lessThan' : { operator : '<' , value : value => value } , '<=' : { operator : '<=' , value : value => value } , 'lte' : { operator : '<=' , value : value => value } , 'lessThanOrEqual' : { operator : '<=' , value : value => value } , '>' : { operator : '>' , value : value => value } , 'gt' : { operator : '>' , value : value => value } , 'greaterThan' : { operator : '>' , value : value => value } , '>=' : { operator : '>=' , value : value => value } , 'greaterThanOrEqual' : { operator : '>=' , value : value => value } , 'gte' : { operator : '>=' , value : value => value } , '!' : { operator : '<>' , value : value => value } , 'not' : { operator : '<>' , value : value => value } , 'between' : { operator : 'between' , value : value => value } , 'notBetween' : { operator : 'not between' , value : value => value } , 'in' : { operator : 'in' , value : value => value } , 'notIn' : { operator : 'not in' , value : value => value } , 'is' : { operator : 'is' , value : value => value } , 'isNot' : { operator : 'is not' , value : value => value } , 'like' : { operator : 'like' , value : value => `%${ value }%` } , 'notLike' : { operator : 'not like' , value : value => `%${ value }%` } , 'contains' : { operator : 'like' , value : value => `%${ value }%` } , 'notContains' : { operator : 'not like' , value : value => `%${ value }%` } , 'startsWith' : { operator : 'like' , value : value => `${ value }%` } , 'notStartsWith' : { operator : 'not like' , value : value => `${ value }%` } , 'endsWith' : { operator : 'like' , value : value => `%${ value }` } , 'notEndsWith' : { operator : 'not like' , value : value => `%${ value }` } , } ; type { Mapping } private hostMapping : Mapping < any > ; type { string } private hostAlias : string ; type { { } } private mappings : { [ key ] : Mapping < any > ; } ; /**
     * Statement to apply criteria to.
     *
     * {QueryBuilder}
     */ private statement : QueryBuilder ; type { Array } private staged : Array < { criteria : Object ; condition ? : string ; statement ? : QueryBuilder ; } > = [ ] ; constructor param { QueryBuilder } statement param { Mapping } hostMapping param { { } } mappings param { string } hostAlias public constructor ( statement , hostMapping , mappings ? , hostAlias ? ) { this . statement = statement ; this . mappings = mappings || { } ; this . hostMapping = hostMapping ; this . hostAlias = hostAlias ; } param { string } hostAlias returns { Criteria } public setHostAlias ( hostAlias ) { this . hostAlias = hostAlias ; return this ; } param { { } } criteria param { string } condition param { QueryBuilder } statement returns { Criteria } public stage ( criteria , condition = this . defaultCondition , statement ? ) { this . staged . push ( { criteria , condition , statement } ) ; return this ; } returns { Criteria } public applyStaged ( ) { this . staged . forEach ( criteria => this . apply ( criteria . criteria , criteria . condition , criteria . statement ) ) ; this . staged = [ ] ; return this ; } param { { } } criteria param { string } condition param { QueryBuilder } statement param { string } property returns { void } public apply ( criteria , condition = this . defaultCondition , statement ? , property ? ) { statement = statement || this . statement ; Reflect . ownKeys ( criteria ) . forEach ( ( key ) => { let value = criteria [ key ] ; let operator = '=' ; if ( this . conditions [ key ] ) { return this . applyNestedCondition ( statement , key , value , condition ) ; } if ( ! ( value === null || typeof value !== 'object' ) && value . constructor === Object ) { return this . apply ( value , condition , statement , key ) ; } if ( this . operators [ key ] ) { value = this . operators [ key ] . value ( value ) ; operator = this . operators [ key ] . operator ; } else { property = key ; } operator = this . applyConvenience ( value , operator ) ; statement [ this . conditions [ condition || this . defaultCondition ] ] ( this . mapToColumn ( property ) , operator , value ) ; } ) ; } param { string } property returns { string } public mapToColumn ( property ) { if ( property . indexOf ( '.' ) === - 1 && this . mappings [ property ] ) { return `${ property }.${ this . mappings [ property ] . getPrimaryKeyField ( ) }` ; } if ( property . indexOf ( '.' ) > - 1 ) { const parts = property . split ( '.' ) ; if ( ! this . mappings [ parts [ 0 ] ] ) { return property ; } parts [ 1 ] = this . mappings [ parts [ 0 ] ] . getFieldName ( parts [ 1 ] , parts [ 1 ] ) ; return parts . join ( '.' ) ; } const columnName = this . hostMapping . getFieldName ( property , property ) ; if ( this . hostAlias && this . hostMapping . getField ( property , true ) ) { return this . hostAlias + '.' + columnName ; } return columnName ; } param { QueryBuilder } statement param { string } condition param { * } value param { string } wrapCondition returns { void } protected applyNestedCondition ( statement , condition , value , wrapCondition ) { statement [ this . conditions [ wrapCondition || condition ] ] ( ( subStatement ) => { value . forEach ( ( criteria ) => { this . apply ( criteria , condition , subStatement ) ; } ) ; } ) ; } param { * } value param { string } operator returns { string } protected applyConvenience ( value , operator ) { if ( value === null ) { if ( operator === '=' ) { operator = this . operators . is . operator ; } else if ( operator === '<>' ) { operator = this . operators . isNot . operator ; } } if ( Array . isArray ( value ) ) { if ( operator === '=' ) { operator = this . operators . in . operator ; } else if ( operator === '<>' ) { operator = this . operators . notIn . operator ; } } return operator ; } }