import * as lf from 'lovefield' ; import { forEach , warn } from '../../utils' ; import { ValueLiteral , VaildEqType , Predicate , PredicateMeta } from '../../interface' ; const predicateFactory = { $ne < T extends ValueLiteral > ( column , value ) { return lf . op . not ( column . eq ( value ) ) ; } , $lt < T extends VaildEqType > ( column , value ) { return column . lt ( value ) ; } , $lte < T extends VaildEqType > ( column , value ) { return column . lte ( value ) ; } , $gt < T extends VaildEqType > ( column , value ) { return column . gt ( value ) ; } , $gte < T extends VaildEqType > ( column , value ) { return column . gte ( value ) ; } , $match ( column , reg ) { return column . match ( reg ) ; } , $notMatch ( column , reg ) { return lf . op . not ( column . match ( reg ) ) ; } , $between ( column , values ) { return column . between ( values [ 0 ] , values [ 1 ] ) ; } , $has ( column , value ) { return column . match ( new RegExp ( `(${ value }\\b)` ) ) ; } , $in ( column , range ) { return column . in ( range ) ; } , $isNull ( column ) { return column . isNull ( ) ; } , $isNotNull ( column ) { return column . isNotNull ( ) ; } , } ; const compoundPredicateFactory = { $and ( predicates ) { return lf . op . and ( ... predicates ) ; } , $or ( predicates ) { return lf . op . or ( ... predicates ) ; } , $not ( predicates ) { return lf . op . not ( predicates [ 0 ] ) ; } , } ; export class PredicateProvider < T > { constructor ( private table , private meta ) { } getPredicate ( ) { const predicates = this . normalizeMeta ( this . meta ) ; if ( predicates . length ) { if ( predicates . length === 1 ) { return predicates [ 0 ] ; } else { return lf . op . and ( ... predicates ) ; } } else { return null ; } } toString ( ) { const pred = this . getPredicate ( ) ; return pred ? JSON . stringify ( this . meta ) : '' ; } private normalizeMeta ( meta , column ? ) { const buildSinglePred = ( col , val , key ) : lf . Predicate => this . checkMethod ( key ) ? predicateFactory [ key ] ( col , val ) : col . eq ( val as ValueLiteral ) ; const predicates = [ ] ; forEach ( meta , ( val , key ) => { let nestedPreds ; let resultPred ; if ( this . checkCompound ( key ) ) { nestedPreds = this . normalizeMeta ( val as Predicate < T > , column ) ; resultPred = compoundPredicateFactory [ key ] ( nestedPreds ) ; } else if ( this . checkPredicate ( val ) ) { nestedPreds = this . normalizeMeta ( val as any , this . table [ key ] ) ; resultPred = compoundPredicateFactory [ '$and' ] ( nestedPreds ) ; } else { const _column = column || this . table [ key ] ; if ( _column ) { resultPred = buildSinglePred ( _column , val , key ) ; } else { warn ( `Failed to build predicate, since column: ${ key } is not exist, on table: ${ this . table . getName ( ) }` ) ; return ; } } predicates . push ( resultPred ) ; } ) ; return predicates ; } private checkMethod ( methodName ) { return typeof predicateFactory [ methodName ] === 'function' ; } private checkCompound ( methodName ) { return typeof compoundPredicateFactory [ methodName ] === 'function' ; } private checkPredicate ( val ) { return val && typeof val === 'object' && ! ( val instanceof Array ) && ! ( val instanceof RegExp ) && ! ( val instanceof ( lf . schema as any ) . BaseColumn ) ; } }