1111
1212import {
1313 EventStatus ,
14+ QueryInputType ,
15+ SearchField ,
1416 tennisClubMembershipEvent
1517} from '@opencrvs/commons/client'
1618import {
@@ -20,7 +22,8 @@ import {
2022 deserializeSearchParams ,
2123 buildQuickSearchQuery ,
2224 resolveAdvancedSearchConfig ,
23- getAdvancedSearchFieldErrors
25+ getAdvancedSearchFieldErrors ,
26+ toAdvancedSearchQueryType
2427} from './utils'
2528
2629describe ( 'getAdvancedSearchFieldErrors' , ( ) => {
@@ -235,3 +238,298 @@ describe('buildQuickSearchQuery', () => {
235238 } )
236239 } )
237240} )
241+
242+ describe ( 'Nested Query Generation with searchFields' , ( ) => {
243+ it ( 'creates OR clauses for fields with multiple searchFields' , ( ) => {
244+ const searchParams = {
245+ 'person-name' : 'Bob' ,
246+ 'child.dob' : '1985-01-01'
247+ }
248+ const searchFieldConfigs : SearchField [ ] = [
249+ {
250+ fieldId : 'person-name' ,
251+ fieldType : 'field' ,
252+ type : 'NAME' ,
253+ config : {
254+ type : 'fuzzy' ,
255+ searchFields : [
256+ 'child.name.firstname' ,
257+ 'child.name.surname' ,
258+ 'mother.name.firstname' ,
259+ 'father.name.firstname'
260+ ]
261+ }
262+ } ,
263+ {
264+ fieldId : 'child.dob' ,
265+ fieldType : 'field' ,
266+ config : { type : 'exact' }
267+ }
268+ ]
269+
270+ const result = toAdvancedSearchQueryType (
271+ searchParams as unknown as QueryInputType ,
272+ searchFieldConfigs ,
273+ 'birth'
274+ )
275+
276+ expect ( result ) . toEqual ( {
277+ type : 'and' ,
278+ clauses : [
279+ {
280+ eventType : 'birth'
281+ } ,
282+ {
283+ type : 'or' ,
284+ clauses : [
285+ {
286+ data : { 'child.name.firstname' : 'Bob' }
287+ } ,
288+ {
289+ data : { 'child.name.surname' : 'Bob' }
290+ } ,
291+ {
292+ data : { 'mother.name.firstname' : 'Bob' }
293+ } ,
294+ {
295+ data : { 'father.name.firstname' : 'Bob' }
296+ }
297+ ]
298+ } ,
299+ {
300+ data : { 'child.dob' : '1985-01-01' }
301+ }
302+ ]
303+ } )
304+ } )
305+
306+ it ( 'creates individual clauses for fields without searchFields' , ( ) => {
307+ const searchParams = {
308+ 'child.name.firstname' : 'Alice' ,
309+ 'child.dob' : '1990-01-01'
310+ }
311+ const searchFieldConfigs : SearchField [ ] = [
312+ {
313+ fieldId : 'child.name.firstname' ,
314+ fieldType : 'field' ,
315+ config : { type : 'fuzzy' }
316+ } ,
317+ {
318+ fieldId : 'child.dob' ,
319+ fieldType : 'field' ,
320+ config : { type : 'exact' }
321+ }
322+ ]
323+
324+ const result = toAdvancedSearchQueryType (
325+ searchParams as unknown as QueryInputType ,
326+ searchFieldConfigs ,
327+ 'birth'
328+ )
329+
330+ expect ( result ) . toEqual ( {
331+ type : 'and' ,
332+ clauses : [
333+ {
334+ eventType : 'birth'
335+ } ,
336+ {
337+ data : { 'child.name.firstname' : 'Alice' }
338+ } ,
339+ {
340+ data : { 'child.dob' : '1990-01-01' }
341+ }
342+ ]
343+ } )
344+ } )
345+
346+ it ( 'handles single searchField as individual clause' , ( ) => {
347+ const searchParams = {
348+ 'custom-field' : 'test-value'
349+ }
350+ const searchFieldConfigs : SearchField [ ] = [
351+ {
352+ fieldId : 'custom-field' ,
353+ fieldType : 'field' ,
354+ config : {
355+ type : 'exact' ,
356+ searchFields : [ 'mapped.database.field' ] // Single field
357+ }
358+ }
359+ ]
360+
361+ const result = toAdvancedSearchQueryType (
362+ searchParams as unknown as QueryInputType ,
363+ searchFieldConfigs ,
364+ 'birth'
365+ )
366+
367+ expect ( result ) . toEqual ( {
368+ type : 'and' ,
369+ clauses : [
370+ {
371+ eventType : 'birth'
372+ } ,
373+ {
374+ type : 'or' ,
375+ clauses : [
376+ {
377+ data : { 'mapped.database.field' : 'test-value' }
378+ }
379+ ]
380+ }
381+ ]
382+ } )
383+ } )
384+
385+ it ( 'handles metadata fields correctly' , ( ) => {
386+ const searchParams = {
387+ 'event.trackingId' : 'ABC123' ,
388+ 'person-name' : 'Bob'
389+ }
390+
391+ const searchFieldConfigs : SearchField [ ] = [
392+ {
393+ fieldId : 'event.trackingId' ,
394+ fieldType : 'event' ,
395+ config : { type : 'exact' }
396+ } ,
397+ {
398+ fieldId : 'person-name' ,
399+ fieldType : 'field' ,
400+ config : {
401+ type : 'fuzzy' ,
402+ searchFields : [ 'child.name.firstname' , 'mother.name.firstname' ]
403+ }
404+ }
405+ ]
406+
407+ const result = toAdvancedSearchQueryType (
408+ searchParams as unknown as QueryInputType ,
409+ searchFieldConfigs ,
410+ 'birth'
411+ )
412+
413+ expect ( result ) . toEqual ( {
414+ type : 'and' ,
415+ clauses : [
416+ {
417+ trackingId : 'ABC123' ,
418+ eventType : 'birth'
419+ } ,
420+ {
421+ type : 'or' ,
422+ clauses : [
423+ {
424+ data : { 'child.name.firstname' : 'Bob' }
425+ } ,
426+ {
427+ data : { 'mother.name.firstname' : 'Bob' }
428+ }
429+ ]
430+ }
431+ ]
432+ } )
433+ } )
434+
435+ it ( 'handles complex multi-field scenario' , ( ) => {
436+ const searchParams = {
437+ 'applicant-name' : 'John' ,
438+ 'contact-info' :
'[email protected] ' , 439+ 'event.status' : 'REGISTERED' ,
440+ 'birth.date' : '1980-01-01'
441+ }
442+
443+ const searchFieldConfigs : SearchField [ ] = [
444+ {
445+ fieldId : 'applicant-name' ,
446+ fieldType : 'field' ,
447+ config : {
448+ type : 'fuzzy' ,
449+ searchFields : [
450+ 'child.name.firstname' ,
451+ 'child.name.surname' ,
452+ 'informant.name.firstname' ,
453+ 'informant.name.surname'
454+ ]
455+ }
456+ } ,
457+ {
458+ fieldId : 'contact-info' ,
459+ fieldType : 'field' ,
460+ config : {
461+ type : 'exact' ,
462+ searchFields : [
463+ 'child.email' ,
464+ 'informant.email' ,
465+ 'child.phone' ,
466+ 'informant.phone'
467+ ]
468+ }
469+ } ,
470+ {
471+ fieldId : 'event.status' ,
472+ fieldType : 'event' ,
473+ config : { type : 'exact' }
474+ } ,
475+ {
476+ fieldId : 'birth.date' ,
477+ fieldType : 'field' ,
478+ config : { type : 'exact' }
479+ }
480+ ]
481+
482+ const result = toAdvancedSearchQueryType (
483+ searchParams as unknown as QueryInputType ,
484+ searchFieldConfigs ,
485+ 'birth'
486+ )
487+
488+ expect ( result ) . toEqual ( {
489+ type : 'and' ,
490+ clauses : [
491+ {
492+ status : 'REGISTERED' ,
493+ eventType : 'birth'
494+ } ,
495+ {
496+ type : 'or' ,
497+ clauses : [
498+ {
499+ data : { 'child.name.firstname' : 'John' }
500+ } ,
501+ {
502+ data : { 'child.name.surname' : 'John' }
503+ } ,
504+ {
505+ data : { 'informant.name.firstname' : 'John' }
506+ } ,
507+ {
508+ data : { 'informant.name.surname' : 'John' }
509+ }
510+ ]
511+ } ,
512+ {
513+ type : 'or' ,
514+ clauses : [
515+ {
516+ data :
{ 'child.email' :
'[email protected] ' } 517+ } ,
518+ {
519+ data :
{ 'informant.email' :
'[email protected] ' } 520+ } ,
521+ {
522+ data :
{ 'child.phone' :
'[email protected] ' } 523+ } ,
524+ {
525+ data :
{ 'informant.phone' :
'[email protected] ' } 526+ }
527+ ]
528+ } ,
529+ {
530+ data : { 'birth.date' : '1980-01-01' }
531+ }
532+ ]
533+ } )
534+ } )
535+ } )
0 commit comments