@@ -102,6 +102,87 @@ const buildEsFullTextQuery = (keyword, matchType, singleFieldName) => {
102
102
} ;
103
103
} ;
104
104
105
+ /**
106
+ * Build ES query search request body based on value, keyword, matchType and fieldName
107
+ *
108
+ * @param {String } value the value to build request body for
109
+ * @param {String } keyword the keyword to query
110
+ * @param {String } matchType wildcard match or exact match
111
+ * @param {Array } fieldName the fieldName
112
+ * @return {Object } search request body that can be passed to .search api call
113
+ */
114
+ const buildEsQueryWithFilter = ( value , keyword , matchType , fieldName ) => {
115
+ let should = [ ] ;
116
+ if ( value !== 'details' && value !== 'customer' && value !== 'manager' ) {
117
+ should = _ . concat ( should , {
118
+ query_string : {
119
+ query : keyword ,
120
+ analyze_wildcard : ( matchType === MATCH_TYPE_WILDCARD ) ,
121
+ fields : fieldName ,
122
+ } ,
123
+ } ) ;
124
+ }
125
+
126
+ if ( value === 'details' ) {
127
+ should = _ . concat ( should , {
128
+ nested : {
129
+ path : 'details' ,
130
+ query : {
131
+ nested : {
132
+ path : 'details.utm' ,
133
+ query : {
134
+ query_string : {
135
+ query : keyword ,
136
+ analyze_wildcard : ( matchType === MATCH_TYPE_WILDCARD ) ,
137
+ fields : fieldName ,
138
+ } ,
139
+ } ,
140
+ } ,
141
+ } ,
142
+ } ,
143
+ } ) ;
144
+ }
145
+
146
+ if ( value === 'customer' || value === 'manager' ) {
147
+ should = _ . concat ( should , {
148
+ nested : {
149
+ path : 'members' ,
150
+ query : {
151
+ bool : {
152
+ must : [
153
+ { match : { 'members.role' : value } } ,
154
+ {
155
+ query_string : {
156
+ query : keyword ,
157
+ analyze_wildcard : ( matchType === MATCH_TYPE_WILDCARD ) ,
158
+ fields : fieldName ,
159
+ } ,
160
+ } ,
161
+ ] ,
162
+ } ,
163
+ } ,
164
+ } ,
165
+ } ) ;
166
+ }
167
+
168
+ return should ;
169
+ } ;
170
+
171
+ /**
172
+ * Prepare search request body based on wildcard query
173
+ *
174
+ * @param {String } value the value to build request body for
175
+ * @param {String } keyword the keyword to query
176
+ * @param {Array } fieldName the fieldName
177
+ * @return {Object } search request body that can be passed to .search api call
178
+ */
179
+ const setFilter = ( value , keyword , fieldName ) => {
180
+ if ( keyword . indexOf ( '*' ) > - 1 ) {
181
+ return buildEsQueryWithFilter ( value , keyword , MATCH_TYPE_WILDCARD , fieldName ) ;
182
+ }
183
+ return buildEsQueryWithFilter ( value , keyword , MATCH_TYPE_EXACT_PHRASE , fieldName ) ;
184
+ } ;
185
+
105
186
/**
106
187
* Parse the ES search criteria and prepare search request body
107
188
*
@@ -152,13 +233,42 @@ const parseElasticSearchCriteria = (criteria, fields, order) => {
152
233
}
153
234
// prepare the elasticsearch filter criteria
154
235
const boolQuery = [ ] ;
236
+ let mustQuery = [ ] ;
155
237
let fullTextQuery ;
156
238
if ( _ . has ( criteria , 'filters.id.$in' ) ) {
157
239
boolQuery . push ( {
158
240
ids : {
159
241
values : criteria . filters . id . $in ,
160
242
} ,
161
243
} ) ;
244
+ } else if ( _ . has ( criteria , 'filters.id' ) && criteria . filters . id . indexOf ( '*' ) > - 1 ) {
245
+ mustQuery = _ . concat ( mustQuery , buildEsQueryWithFilter ( 'id' , criteria . filters . id , MATCH_TYPE_WILDCARD , [ 'id' ] ) ) ;
246
+ } else if ( _ . has ( criteria , 'filters.id' ) ) {
247
+ boolQuery . push ( {
248
+ term : {
249
+ id : criteria . filters . id ,
250
+ } ,
251
+ } ) ;
252
+ }
253
+
254
+ if ( _ . has ( criteria , 'filters.name' ) ) {
255
+ mustQuery = _ . concat ( mustQuery , setFilter ( 'name' , criteria . filters . name , [ 'name' ] ) ) ;
256
+ }
257
+
258
+ if ( _ . has ( criteria , 'filters.code' ) ) {
259
+ mustQuery = _ . concat ( mustQuery , setFilter ( 'details' , criteria . filters . code , [ 'details.utm.code' ] ) ) ;
260
+ }
261
+
262
+ if ( _ . has ( criteria , 'filters.customer' ) ) {
263
+ mustQuery = _ . concat ( mustQuery , setFilter ( 'customer' ,
264
+ criteria . filters . customer ,
265
+ [ 'members.firstName' , 'members.lastName' ] ) ) ;
266
+ }
267
+
268
+ if ( _ . has ( criteria , 'filters.manager' ) ) {
269
+ mustQuery = _ . concat ( mustQuery , setFilter ( 'manager' ,
270
+ criteria . filters . manager ,
271
+ [ 'members.firstName' , 'members.lastName' ] ) ) ;
162
272
}
163
273
164
274
if ( _ . has ( criteria , 'filters.status.$in' ) ) {
@@ -177,21 +287,6 @@ const parseElasticSearchCriteria = (criteria, fields, order) => {
177
287
} ) ;
178
288
}
179
289
180
- if ( _ . has ( criteria , 'filters.type.$in' ) ) {
181
- // type is an array
182
- boolQuery . push ( {
183
- terms : {
184
- type : criteria . filters . type . $in ,
185
- } ,
186
- } ) ;
187
- } else if ( _ . has ( criteria , 'filters.type' ) ) {
188
- // type is simple string
189
- boolQuery . push ( {
190
- term : {
191
- type : criteria . filters . type ,
192
- } ,
193
- } ) ;
194
- }
195
290
if ( _ . has ( criteria , 'filters.keyword' ) ) {
196
291
// keyword is a full text search
197
292
// escape special fields from keyword search
@@ -222,7 +317,7 @@ const parseElasticSearchCriteria = (criteria, fields, order) => {
222
317
223
318
if ( ! keyword ) {
224
319
// Not a specific field search nor an exact phrase search, do a wildcard match
225
- keyword = escapeEsKeyword ( criteria . filters . keyword ) ;
320
+ keyword = criteria . filters . keyword ;
226
321
matchType = MATCH_TYPE_WILDCARD ;
227
322
}
228
323
@@ -234,17 +329,22 @@ const parseElasticSearchCriteria = (criteria, fields, order) => {
234
329
filter : boolQuery ,
235
330
} ;
236
331
}
332
+
333
+ if ( mustQuery . length > 0 ) {
334
+ body . query . bool = _ . merge ( body . query . bool , {
335
+ must : mustQuery ,
336
+ } ) ;
337
+ }
237
338
if ( fullTextQuery ) {
238
339
body . query = _ . merge ( body . query , fullTextQuery ) ;
239
340
if ( body . query . bool ) {
240
341
body . query . bool . minimum_should_match = 1 ;
241
342
}
242
343
}
243
344
244
- if ( fullTextQuery || boolQuery . length > 0 ) {
345
+ if ( fullTextQuery || boolQuery . length > 0 || mustQuery . length > 0 ) {
245
346
searchCriteria . body = body ;
246
347
}
247
-
248
348
return searchCriteria ;
249
349
} ;
250
350
@@ -267,8 +367,7 @@ const retrieveProjects = (req, criteria, sort, ffields) => {
267
367
fields . projects . push ( 'id' ) ;
268
368
}
269
369
270
- const searchCriteria = parseElasticSearchCriteria ( criteria , fields , order ) ;
271
-
370
+ const searchCriteria = parseElasticSearchCriteria ( criteria , fields , order ) || { } ;
272
371
return new Promise ( ( accept , reject ) => {
273
372
const es = util . getElasticSearchClient ( ) ;
274
373
es . search ( searchCriteria ) . then ( ( docs ) => {
@@ -300,7 +399,8 @@ module.exports = [
300
399
'name' , 'name asc' , 'name desc' ,
301
400
'type' , 'type asc' , 'type desc' ,
302
401
] ;
303
- if ( ! util . isValidFilter ( filters , [ 'id' , 'status' , 'type' , 'memberOnly' , 'keyword' ] ) ||
402
+ if ( ! util . isValidFilter ( filters ,
403
+ [ 'id' , 'status' , 'memberOnly' , 'keyword' , 'name' , 'code' , 'customer' , 'manager' ] ) ||
304
404
( sort && _ . indexOf ( sortableProps , sort ) < 0 ) ) {
305
405
return util . handleError ( 'Invalid filters or sort' , null , req , next ) ;
306
406
}
0 commit comments