@@ -517,23 +517,92 @@ class Stack {
517
517
}
518
518
throw new Error ( 'Kindly pass a query object for \'.queryReferences()\'' ) ;
519
519
}
520
+ queryReferencesBeta ( query ) {
521
+ if ( query && typeof query === 'object' ) {
522
+ this . internal . queryReferencesBeta = query ;
523
+ return this ;
524
+ }
525
+ throw new Error ( 'Kindly pass a query object for \'.queryReferences()\'' ) ;
526
+ }
520
527
getQuery ( ) {
521
528
return Object . assign ( { } , this . q ) ;
522
529
}
530
+ include ( fields ) {
531
+ if ( fields . length === 0 ) {
532
+ throw new Error ( 'Kindly pass a valid reference field path to \'.include()\' ' ) ;
533
+ }
534
+ else if ( typeof fields === 'string' ) {
535
+ this . internal . includeSpecificReferences = [ fields ] ;
536
+ }
537
+ else {
538
+ this . internal . includeSpecificReferences = fields ;
539
+ }
540
+ return this ;
541
+ }
523
542
find ( query = { } ) {
524
543
return new Promise ( ( resolve , reject ) => {
525
- const queryFilters = this . preProcess ( query ) ;
526
- if ( this . internal . sort ) {
527
- this . collection = this . collection . find ( queryFilters ) . sort ( this . internal . sort ) ;
528
- }
529
- else {
530
- this . collection = this . collection . find ( queryFilters ) ;
531
- }
544
+ let queryFilters = this . preProcess ( query ) ;
532
545
if ( this . internal . queryReferences ) {
533
546
return this . queryOnReferences ( )
534
547
. then ( resolve )
535
548
. catch ( reject ) ;
536
549
}
550
+ if ( this . internal . queryReferencesBeta ) {
551
+ return this . queryBuilder ( this . internal . queryReferencesBeta , this . q . locale , this . q . content_type_uid )
552
+ . then ( ( query ) => {
553
+ queryFilters = lodash_1 . merge ( queryFilters , query ) ;
554
+ this . collection = this . collection . find ( queryFilters ) ;
555
+ return this . collection
556
+ . project ( this . internal . projections )
557
+ . limit ( this . internal . limit )
558
+ . skip ( this . internal . skip )
559
+ . toArray ( )
560
+ . then ( ( result ) => {
561
+ let contentType ;
562
+ if ( this . internal . includeSchema && this . q . content_type_uid !== 'contentTypes' && this . q . content_type_uid !==
563
+ '_assets' ) {
564
+ contentType = lodash_1 . remove ( result , { uid : this . q . content_type_uid } ) ;
565
+ contentType = ( typeof contentType === 'object' && contentType instanceof Array && contentType . length ) ?
566
+ contentType [ 0 ] : null ;
567
+ }
568
+ if ( this . internal . excludeReferences || this . q . content_type_uid === 'contentTypes' || this . q . content_type_uid
569
+ === '_assets' ) {
570
+ result = this . postProcess ( result , contentType ) ;
571
+ return resolve ( result ) ;
572
+ }
573
+ else if ( this . internal . includeSpecificReferences ) {
574
+ return this . includeSpecificReferences ( result , this . q . locale , { } , undefined , this . internal . includeSpecificReferences )
575
+ . then ( ( ) => {
576
+ result = this . postProcess ( result , contentType ) ;
577
+ return resolve ( result ) ;
578
+ } )
579
+ . catch ( ( refError ) => {
580
+ this . cleanup ( ) ;
581
+ return reject ( refError ) ;
582
+ } ) ;
583
+ }
584
+ else {
585
+ return this . includeReferencesI ( result , this . q . locale , { } , undefined )
586
+ . then ( ( ) => {
587
+ result = this . postProcess ( result , contentType ) ;
588
+ return resolve ( result ) ;
589
+ } )
590
+ . catch ( ( refError ) => {
591
+ this . cleanup ( ) ;
592
+ return reject ( refError ) ;
593
+ } ) ;
594
+ }
595
+ } )
596
+ . catch ( ( error ) => {
597
+ this . cleanup ( ) ;
598
+ return reject ( error ) ;
599
+ } ) ;
600
+ } )
601
+ . catch ( ( error ) => {
602
+ this . cleanup ( ) ;
603
+ return reject ( error ) ;
604
+ } ) ;
605
+ }
537
606
return this . collection
538
607
. project ( this . internal . projections )
539
608
. limit ( this . internal . limit )
@@ -552,6 +621,17 @@ class Stack {
552
621
result = this . postProcess ( result , contentType ) ;
553
622
return resolve ( result ) ;
554
623
}
624
+ else if ( this . internal . includeSpecificReferences ) {
625
+ return this . includeSpecificReferences ( result , this . q . locale , { } , undefined , this . internal . includeSpecificReferences )
626
+ . then ( ( ) => {
627
+ result = this . postProcess ( result , contentType ) ;
628
+ return resolve ( result ) ;
629
+ } )
630
+ . catch ( ( refError ) => {
631
+ this . cleanup ( ) ;
632
+ return reject ( refError ) ;
633
+ } ) ;
634
+ }
555
635
else {
556
636
return this . includeReferencesI ( result , this . q . locale , { } , undefined )
557
637
. then ( ( ) => {
@@ -833,5 +913,178 @@ class Stack {
833
913
. catch ( reject ) ;
834
914
} ) ;
835
915
}
916
+ isPartOfInclude ( pth , include ) {
917
+ for ( let i = 0 , j = include . length ; i < j ; i ++ ) {
918
+ if ( include [ i ] . indexOf ( pth ) !== - 1 ) {
919
+ return true ;
920
+ }
921
+ }
922
+ return false ;
923
+ }
924
+ includeSpecificReferences ( entry , locale , references , parentUid , includePths = [ ] , parentField = '' ) {
925
+ const self = this ;
926
+ return new Promise ( ( resolve , reject ) => {
927
+ if ( entry === null || typeof entry !== 'object' ) {
928
+ return resolve ( ) ;
929
+ }
930
+ if ( entry . uid ) {
931
+ parentUid = entry . uid ;
932
+ }
933
+ const referencesFound = [ ] ;
934
+ for ( const prop in entry ) {
935
+ if ( entry [ prop ] !== null && typeof entry [ prop ] === 'object' ) {
936
+ let currentPth ;
937
+ if ( parentField === '' && isNaN ( parseInt ( prop ) ) ) {
938
+ currentPth = prop ;
939
+ }
940
+ else if ( parentField === '' && ! isNaN ( parseInt ( prop ) ) ) {
941
+ currentPth = parentField ;
942
+ }
943
+ else {
944
+ currentPth = parentField . concat ( '.' , prop ) ;
945
+ }
946
+ if ( entry [ prop ] && entry [ prop ] . reference_to ) {
947
+ if ( entry [ prop ] . reference_to === '_assets' || this . isPartOfInclude ( currentPth , includePths ) ) {
948
+ if ( entry [ prop ] . values . length === 0 ) {
949
+ entry [ prop ] = [ ] ;
950
+ }
951
+ else {
952
+ let uids = entry [ prop ] . values ;
953
+ if ( typeof uids === 'string' ) {
954
+ uids = [ uids ] ;
955
+ }
956
+ if ( entry [ prop ] . reference_to !== '_assets' ) {
957
+ uids = lodash_1 . filter ( uids , ( uid ) => {
958
+ return ! ( util_1 . checkCyclic ( uid , references ) ) ;
959
+ } ) ;
960
+ }
961
+ if ( uids . length ) {
962
+ const query = {
963
+ content_type_uid : entry [ prop ] . reference_to ,
964
+ locale,
965
+ uid : {
966
+ $in : uids ,
967
+ } ,
968
+ } ;
969
+ referencesFound . push ( new Promise ( ( rs , rj ) => {
970
+ return self . db . collection ( this . contentStore . collectionName )
971
+ . find ( query )
972
+ . project ( self . config . contentStore . projections )
973
+ . toArray ( )
974
+ . then ( ( result ) => {
975
+ if ( result . length === 0 ) {
976
+ entry [ prop ] = [ ] ;
977
+ return rs ( ) ;
978
+ }
979
+ else if ( parentUid ) {
980
+ references [ parentUid ] = references [ parentUid ] || [ ] ;
981
+ references [ parentUid ] = lodash_1 . uniq ( references [ parentUid ] . concat ( lodash_1 . map ( result , 'uid' ) ) ) ;
982
+ }
983
+ if ( typeof entry [ prop ] . values === 'string' ) {
984
+ entry [ prop ] = ( ( result === null ) || result . length === 0 ) ? null : result [ 0 ] ;
985
+ }
986
+ else {
987
+ const referenceBucket = [ ] ;
988
+ query . uid . $in . forEach ( ( entityUid ) => {
989
+ const elem = lodash_1 . find ( result , ( entity ) => {
990
+ return entity . uid === entityUid ;
991
+ } ) ;
992
+ if ( elem ) {
993
+ referenceBucket . push ( elem ) ;
994
+ }
995
+ } ) ;
996
+ entry [ prop ] = referenceBucket ;
997
+ }
998
+ return self . includeSpecificReferences ( entry [ prop ] , locale , references , parentUid , includePths , currentPth )
999
+ . then ( rs )
1000
+ . catch ( rj ) ;
1001
+ } )
1002
+ . catch ( rj ) ;
1003
+ } ) ) ;
1004
+ }
1005
+ }
1006
+ }
1007
+ }
1008
+ else {
1009
+ referencesFound . push ( self . includeSpecificReferences ( entry [ prop ] , locale , references , parentUid , includePths , currentPth ) ) ;
1010
+ }
1011
+ }
1012
+ }
1013
+ return Promise . all ( referencesFound )
1014
+ . then ( resolve )
1015
+ . catch ( reject ) ;
1016
+ } ) ;
1017
+ }
1018
+ queryBuilder ( query , language , ct ) {
1019
+ return new Promise ( ( resolve , reject ) => {
1020
+ if ( query && Object . keys ( query ) . length && ct ) {
1021
+ return this . db . collection ( this . contentStore . collectionName )
1022
+ . find ( {
1023
+ content_type_uid : 'contentTypes' ,
1024
+ locale : language ,
1025
+ uid : ct
1026
+ } )
1027
+ . project ( {
1028
+ reference_to : 1
1029
+ } )
1030
+ . limit ( 1 )
1031
+ . toArray ( )
1032
+ . then ( ( result ) => {
1033
+ if ( result === null || result . length === 0 ) {
1034
+ return resolve ( ) ;
1035
+ }
1036
+ const references = result [ 0 ] . reference_to ;
1037
+ if ( references && Object . keys ( references ) . length > 0 ) {
1038
+ const promises = [ ] ;
1039
+ for ( const field in query ) {
1040
+ let filterField = field ;
1041
+ let refQuery , refContentType ;
1042
+ for ( let refField in references ) {
1043
+ if ( field . indexOf ( refField ) === 0 ) {
1044
+ filterField = filterField . split ( '.' ) ;
1045
+ filterField [ filterField . length - 1 ] = 'uid' ;
1046
+ filterField = filterField . join ( '.' ) ;
1047
+ refQuery = refQuery || { } ;
1048
+ refContentType = references [ refField ] ;
1049
+ refQuery [ filterField ] = query [ field ] ;
1050
+ refQuery . content_type_uid = refContentType ;
1051
+ refQuery . locale = language ;
1052
+ delete query [ field ] ;
1053
+ }
1054
+ }
1055
+ if ( refQuery && Object . keys ( refQuery ) . length ) {
1056
+ promises . push ( this . db . collection ( this . contentStore . collectionName )
1057
+ . find ( refQuery )
1058
+ . project ( { uid : 1 } )
1059
+ . toArray ( )
1060
+ . then ( ( result ) => {
1061
+ if ( result === null || result . length === 0 ) {
1062
+ query [ filterField ] = {
1063
+ $in : [ ]
1064
+ } ;
1065
+ }
1066
+ else {
1067
+ query [ filterField ] = {
1068
+ $in : lodash_1 . map ( result , 'uid' )
1069
+ } ;
1070
+ }
1071
+ } ) ) ;
1072
+ }
1073
+ else if ( query [ field ] !== null && typeof query [ field ] === 'object' && query [ field ] instanceof Array && query [ field ] . length ) {
1074
+ promises . push ( this . queryBuilder ( query [ field ] , language , ct ) ) ;
1075
+ }
1076
+ }
1077
+ }
1078
+ else {
1079
+ return resolve ( query ) ;
1080
+ }
1081
+ } )
1082
+ . catch ( reject ) ;
1083
+ }
1084
+ else {
1085
+ return resolve ( query ) ;
1086
+ }
1087
+ } ) ;
1088
+ }
836
1089
}
837
1090
exports . Stack = Stack ;
0 commit comments