@@ -7,10 +7,10 @@ const GROUP_START = '('
77const GROUP_END = ')'
88const EMPTY_QUOTES_STR = '""'
99const KEY_SEPARATOR = '.'
10- const NEGATED_PREFIX = 'not '
10+ const NEGATED_PREFIX = 'not'
1111const RANGE_REGEXP = / ^ [ - \D ] * ( - ? \d + ( \. \d + ) ? ) ? [ - \D ] * - [ - \D ] * ( - ? \d + ( \. \d + ) ? ) ? [ - \D ] * $ /
12- const TOKENIZER = new RegExp ( ` *(\\${ GROUP_START } )| *(${ NEGATED_PREFIX } +)?(?:((?:\\\\.|[^ ${ GROUP_START } ${ GROUP_END } \\\\${ REGEX_CHAR } ${ RANGE_CHAR } ${ TOKEN_SEPARATOR } ])+) *([${ REGEX_CHAR } ${ RANGE_CHAR } ]?${ TOKEN_SEPARATOR } ))? *("((?:\\\\.|[^"\\\\])+)"|(?:\\\\.|[^ ${ GROUP_START } ${ GROUP_END } \\\\])+)? *(\\ ${ GROUP_END } )? *( and|or|\\) |$)` , 'g' )
13- const TOKEN = { GROUP_START : 1 , NEGATED : 2 , KEY : 3 , TYPE : 4 , VALUE : 5 , QUOTED_VALUE : 6 , GROUP_END : 7 , OPERATOR : 8 }
12+ const TOKENIZER = new RegExp ( ` *(${ NEGATED_PREFIX } )? *( \\${ GROUP_START } )| *(${ NEGATED_PREFIX } +)?(?:((?:\\\\.|[^ ${ GROUP_START } ${ GROUP_END } \\\\${ REGEX_CHAR } ${ RANGE_CHAR } ${ TOKEN_SEPARATOR } ])+) *([${ REGEX_CHAR } ${ RANGE_CHAR } ]?${ TOKEN_SEPARATOR } ))? *("((?:\\\\.|[^"\\\\])+)"|(?:\\\\.|[^ ${ GROUP_START } ${ GROUP_END } \\\\])+)? *(and|or|\\${ GROUP_END } |$)` , 'g' )
13+ const TOKEN = { GROUP_NEGATED : 1 , GROUP_START : 2 , NEGATED : 3 , KEY : 4 , TYPE : 5 , VALUE : 6 , QUOTED_VALUE : 7 , OPERATOR : 8 }
1414const UNKNOWN = - 1
1515const EMPTY_ARR : any [ ] = [ ]
1616const EMPTY_STR = ''
@@ -34,6 +34,7 @@ interface Range {
3434
3535class GroupQuery {
3636 conditions : ( Query | GroupQuery ) [ ]
37+ negated ?: boolean
3738 operator ?: Operator
3839
3940 constructor ( ) {
@@ -71,14 +72,16 @@ function search<T extends Record<string, any>>(objList: T[], queryStr: string, e
7172
7273 if ( ! queryStr || queryStr . trim ( ) === EMPTY_STR ) { return objList . slice ( ) }
7374
74- return [ ...evaluateConditions ( objList , extractConditionsFromQuery ( queryStr . toLowerCase ( ) ) , exclude ) ]
75+ return [ ...evaluateCondition ( objList , extractConditionsFromQuery ( queryStr . toLowerCase ( ) ) , exclude ) ]
7576}
7677
7778function extractConditionsFromQuery ( query : string , regex = new RegExp ( TOKENIZER ) , group = new GroupQuery ( ) ) : GroupQuery {
7879 let m : RegExpExecArray | null
7980 while ( ( m = regex . exec ( query ) ) !== null && m [ 0 ] !== EMPTY_STR ) {
8081 if ( m [ TOKEN . GROUP_START ] ) {
81- group . conditions . push ( extractConditionsFromQuery ( query , regex ) )
82+ const subGroup = extractConditionsFromQuery ( query , regex )
83+ subGroup . negated = ! ! m [ TOKEN . GROUP_NEGATED ]
84+ group . conditions . push ( subGroup )
8285 continue
8386 }
8487
@@ -96,16 +99,7 @@ function extractConditionsFromQuery(query: string, regex = new RegExp(TOKENIZER)
9699 group . conditions . push ( getQuery ( ! ! m [ TOKEN . NEGATED ] , type , key , value ) )
97100 }
98101
99- if ( m [ TOKEN . OPERATOR ] === GROUP_END ) {
100- m [ TOKEN . GROUP_END ] = GROUP_END
101- m [ TOKEN . OPERATOR ] = void 0
102- }
103-
104- if ( m [ TOKEN . GROUP_END ] ) {
105- if ( m [ TOKEN . OPERATOR ] ) { group . operator = Operator . from ( m [ TOKEN . OPERATOR ] ) }
106- break
107- }
108-
102+ if ( m [ TOKEN . OPERATOR ] === GROUP_END ) { break }
109103 if ( m [ TOKEN . OPERATOR ] ) { group . lastCondition ( ) ! . operator = Operator . from ( m [ TOKEN . OPERATOR ] ) }
110104 }
111105
@@ -151,7 +145,7 @@ function getQuery(negated: boolean, type?: string, key?: string, value?: string)
151145 return query
152146}
153147
154- function evaluateConditions < T > ( objList : T [ ] , group : GroupQuery , exclude ?: string [ ] ) : Set < T > {
148+ function evaluateGroup < T > ( objList : T [ ] , group : GroupQuery , exclude ?: string [ ] ) : Set < T > {
155149 if ( group . conditions . length === 0 ) { return new Set ( objList ) }
156150
157151 let currentResults = evaluateCondition ( objList , group . conditions [ 0 ] , exclude )
@@ -172,7 +166,24 @@ function evaluateConditions<T>(objList: T[], group: GroupQuery, exclude?: string
172166}
173167
174168function evaluateCondition < T > ( objList : T [ ] , condition : Query | GroupQuery , exclude ?: string [ ] ) : Set < T > {
175- if ( 'conditions' in condition ) { return evaluateConditions ( objList , condition , exclude ) }
169+ if ( 'conditions' in condition ) {
170+ // Get the result of evaluating the group
171+ const groupResult = evaluateGroup ( objList , condition , exclude )
172+
173+ // If the group is negated, return everything except the group results
174+ if ( condition . negated ) {
175+ const negatedResult = new Set < T > ( )
176+ objList . forEach ( obj => {
177+ if ( ! groupResult . has ( obj ) ) {
178+ negatedResult . add ( obj )
179+ }
180+ } )
181+ return negatedResult
182+ }
183+
184+ return groupResult
185+ }
186+
176187 const resultSet = new Set < T > ( )
177188 objList . forEach ( obj => {
178189 if ( condition . negated !== findQuery ( obj , condition , EMPTY_STR , exclude ) ) {
@@ -182,7 +193,7 @@ function evaluateCondition<T>(objList: T[], condition: Query | GroupQuery, exclu
182193 return resultSet
183194}
184195
185- function findQuery ( obj : Object , query : Query , nestedKeys : string , excludedKeys ?: string [ ] , keyFound ?: boolean ) : boolean {
196+ function findQuery ( obj : any , query : Query , nestedKeys : string , excludedKeys ?: string [ ] , keyFound ?: boolean ) : boolean {
186197 return getObjectKeys ( obj ) . some ( ( key ) => {
187198 const newNestedKeys = nestedKeys + KEY_SEPARATOR + key . toLowerCase ( )
188199
0 commit comments