@@ -611,7 +611,7 @@ public static string GetJoinProjection(string sourceName, string targetName, Typ
611
611
var fieldRef = sourceName ;
612
612
if ( sourceName != targetName && ! string . IsNullOrEmpty ( targetName ) )
613
613
{
614
- fieldRef = $ "\" { targetName } \" : { sourceName } ";
614
+ fieldRef = $ "\" { targetName } \" :{ sourceName } ";
615
615
}
616
616
617
617
// String or primative
@@ -638,7 +638,7 @@ public static string GetJoinProjection(string sourceName, string targetName, Typ
638
638
var elementType = listOfSanityReferenceType . GetGenericArguments ( ) [ 0 ] . GetGenericArguments ( ) [ 0 ] ;
639
639
var fields = GetPropertyProjectionList ( elementType ) ;
640
640
var fieldList = fields . Aggregate ( ( c , n ) => c + "," + n ) ;
641
- projection = $ "{ fieldRef } []->{{ { fieldList } }}";
641
+ projection = $ "{ fieldRef } []->{{{fieldList}}}";
642
642
}
643
643
else
644
644
{
@@ -654,7 +654,7 @@ public static string GetJoinProjection(string sourceName, string targetName, Typ
654
654
655
655
// Nested Reference
656
656
var fieldList = fields . Select ( f => f . StartsWith ( "asset" ) ? $ "asset->{ ( nestedFields . Count > 0 ? ( "{" + nestedFields . Aggregate ( ( a , b ) => a + "," + b ) + "}" ) : "" ) } " : f ) . Aggregate ( ( c , n ) => c + "," + n ) ;
657
- projection = $ "{ fieldRef } {{ { fieldList } }}";
657
+ projection = $ "{ fieldRef } {{{fieldList}}}";
658
658
}
659
659
else
660
660
{
@@ -689,7 +689,7 @@ public static string GetJoinProjection(string sourceName, string targetName, Typ
689
689
690
690
// Nested Reference
691
691
var fieldList = fields . Select ( f => f == propertyName ? $ "{ propertyName } []->{ ( nestedFields . Count > 0 ? ( "{" + nestedFields . Aggregate ( ( a , b ) => a + "," + b ) + "}" ) : "" ) } " : f ) . Aggregate ( ( c , n ) => c + "," + n ) ;
692
- projection = $ "{ fieldRef } {{ { fieldList } }}";
692
+ projection = $ "{ fieldRef } {{{fieldList}}}";
693
693
694
694
}
695
695
else
@@ -705,8 +705,8 @@ public static string GetJoinProjection(string sourceName, string targetName, Typ
705
705
706
706
707
707
// Nested Reference
708
- var fieldList = fields . Select ( f => f . StartsWith ( "asset" ) ? $ "asset->{{ ... }}" : f ) . Aggregate ( ( c , n ) => c + "," + n ) ;
709
- projection = $ "{ fieldRef } [] {{ { fieldList } }}";
708
+ var fieldList = fields . Select ( f => f . StartsWith ( "asset" ) ? $ "asset->{{{SanityConstants.SPREAD_OPERATOR} }}" : f ) . Aggregate ( ( c , n ) => c + "," + n ) ;
709
+ projection = $ "{ fieldRef } []{{ {fieldList}}}";
710
710
}
711
711
}
712
712
}
@@ -727,7 +727,15 @@ public static string GetJoinProjection(string sourceName, string targetName, Typ
727
727
{
728
728
// Other strongly typed includes
729
729
var fieldList = fields . Aggregate ( ( c , n ) => c + "," + n ) ;
730
- projection = $ "{ fieldRef } []->{{ { fieldList } }}";
730
+ // projection = $"{fieldRef}[]->{{ {fieldList} }}";
731
+
732
+ // Include both references and inline objects:
733
+ // E.g.
734
+ // activities[] {
735
+ // ...,
736
+ // _type == 'reference' => @->{...}
737
+ // },
738
+ projection = $ "{ fieldRef } []{{{fieldList},{ SanityConstants . DEREFERENCING_SWITCH + "{" + fieldList + "}" } }}";
731
739
}
732
740
else
733
741
{
@@ -742,12 +750,14 @@ public static string GetJoinProjection(string sourceName, string targetName, Typ
742
750
{
743
751
// Other strongly typed includes
744
752
var fieldList = fields . Aggregate ( ( c , n ) => c + "," + n ) ;
745
- projection = $ "{ fieldRef } ->{{ { fieldList } }}";
753
+ // projection = $"{fieldRef}->{{{fieldList}}}";
754
+ projection = $ "{ fieldRef } {{{fieldList},{ SanityConstants . DEREFERENCING_SWITCH + "{" + fieldList + "}" } }}";
746
755
}
747
756
else
748
757
{
749
758
// "object" without any fields defined
750
- projection = $ "{ fieldRef } ->{{ ... }}";
759
+ //projection = $"{fieldRef}->{{{SanityConstants.SPREAD_OPERATOR}}}";
760
+ projection = $ "{ fieldRef } {{{SanityConstants.SPREAD_OPERATOR},{ SanityConstants . DEREFERENCING_SWITCH + "{" + SanityConstants . SPREAD_OPERATOR + "}" } }}";
751
761
}
752
762
}
753
763
}
@@ -756,6 +766,16 @@ public static string GetJoinProjection(string sourceName, string targetName, Typ
756
766
757
767
}
758
768
769
+ internal class SanityConstants
770
+ {
771
+ public const string ARRAY_INDICATOR = "[]" ;
772
+ public const string DEREFERENCING_SWITCH = "_type=='reference'=>@->" ;
773
+ public const string SPREAD_OPERATOR = "..." ;
774
+ public const string STRING_DELIMITOR = "\" " ;
775
+ public const string COLON = ":" ;
776
+ public const string DEREFERENCING_OPERATOR = "->" ;
777
+ }
778
+
759
779
760
780
internal class SanityQueryBuilder
761
781
{
@@ -846,7 +866,7 @@ public virtual string Build(bool includeProjections)
846
866
if ( ! string . IsNullOrEmpty ( projection ) )
847
867
{
848
868
projection = ExpandIncludesInProjection ( projection , Includes ) ;
849
- projection = projection . Replace ( "{... }", "" ) ; // Remove redundant {...} to simplify query
869
+ projection = projection . Replace ( $ "{{{SanityConstants.SPREAD_OPERATOR}} }", "" ) ; // Remove redundant {...} to simplify query
850
870
sb . Append ( projection ) ;
851
871
}
852
872
}
@@ -887,6 +907,16 @@ public virtual string Build(bool includeProjections)
887
907
return sb . ToString ( ) ;
888
908
}
889
909
910
+ private Dictionary < string , string > GroqTokens = new Dictionary < string , string >
911
+ {
912
+ { SanityConstants . DEREFERENCING_SWITCH , "__0001__" } ,
913
+ { SanityConstants . DEREFERENCING_OPERATOR , "__0002__" } ,
914
+ { SanityConstants . STRING_DELIMITOR , "__0003__" } ,
915
+ { SanityConstants . COLON , "__0004__" } ,
916
+ { SanityConstants . SPREAD_OPERATOR , "__0005__" } ,
917
+ { SanityConstants . ARRAY_INDICATOR , "__0006__" } ,
918
+ } ;
919
+
890
920
private string ExpandIncludesInProjection ( string projection , Dictionary < string , string > includes )
891
921
{
892
922
// Finds and replaces includes in projection by converting projection (GROQ) to an equivelant JSON representation,
@@ -904,10 +934,11 @@ private string ExpandIncludesInProjection(string projection, Dictionary<string,
904
934
var jObjectInclude = JsonConvert . DeserializeObject ( jsonInclude ) as JObject ;
905
935
906
936
var pathParts = includeKey
907
- . Replace ( "\" :" , GroqTokens [ "\" :" ] )
908
- . Replace ( "\" " , GroqTokens [ "\" " ] )
909
- . Replace ( "[]" , GroqTokens [ "[]" ] )
910
- . Replace ( "->" , "." )
937
+ . Replace ( SanityConstants . COLON , GroqTokens [ SanityConstants . COLON ] )
938
+ . Replace ( SanityConstants . STRING_DELIMITOR , GroqTokens [ SanityConstants . STRING_DELIMITOR ] )
939
+ . Replace ( SanityConstants . ARRAY_INDICATOR , GroqTokens [ SanityConstants . ARRAY_INDICATOR ] )
940
+ . Replace ( SanityConstants . DEREFERENCING_SWITCH , GroqTokens [ SanityConstants . DEREFERENCING_SWITCH ] )
941
+ . Replace ( SanityConstants . DEREFERENCING_OPERATOR , "." )
911
942
. TrimEnd ( '.' ) . Split ( '.' ) ;
912
943
913
944
JObject obj = jObjectProjection ;
@@ -917,53 +948,56 @@ private string ExpandIncludesInProjection(string projection, Dictionary<string,
917
948
bool isLast = i == pathParts . Length - 1 ;
918
949
if ( ! isLast )
919
950
{
920
- if ( obj . ContainsKey ( part ) )
921
- {
922
- obj = obj [ part ] as JObject ;
923
- }
924
- else if ( obj . ContainsKey ( part + GroqTokens [ "->" ] ) )
925
- {
926
- obj = obj [ part + GroqTokens [ "->" ] ] as JObject ;
927
- }
928
- else if ( obj . ContainsKey ( part + GroqTokens [ "[]" ] ) )
929
- {
930
- obj = obj [ part + GroqTokens [ "[]" ] ] as JObject ;
931
- }
932
- else if ( obj . ContainsKey ( part + GroqTokens [ "[]" ] + GroqTokens [ "->" ] ) )
951
+ // Traverse / construct path to property
952
+ bool propertyExists = false ;
953
+ foreach ( var property in obj )
933
954
{
934
- obj = obj [ part + GroqTokens [ "[]" ] + GroqTokens [ "->" ] ] as JObject ;
955
+ if ( property . Key == part
956
+ || property . Key . StartsWith ( $ "{ GroqTokens [ SanityConstants . STRING_DELIMITOR ] } { part } { GroqTokens [ SanityConstants . STRING_DELIMITOR ] } ")
957
+ || property . Key . StartsWith ( part + GroqTokens [ SanityConstants . ARRAY_INDICATOR ] )
958
+ || property . Key . StartsWith ( part + GroqTokens [ SanityConstants . DEREFERENCING_OPERATOR ] ) )
959
+ {
960
+ obj = obj [ property . Key ] as JObject ;
961
+ propertyExists = true ;
962
+ break ;
963
+ }
935
964
}
936
- else
965
+ if ( ! propertyExists )
937
966
{
938
967
obj [ part ] = new JObject ( ) ;
939
968
obj = obj [ part ] as JObject ;
940
969
}
941
970
}
942
971
else
943
972
{
944
- if ( obj . ContainsKey ( part ) )
945
- {
946
- obj . Remove ( part ) ;
947
- }
948
- if ( obj . ContainsKey ( part + GroqTokens [ "[]" ] ) )
973
+ // Remove previous representations of field (typically without a projection)
974
+ var fieldsToReplace = new List < string > ( ) ;
975
+ foreach ( var property in obj )
949
976
{
950
- obj . Remove ( part + GroqTokens [ "[]" ] ) ;
951
- }
952
- if ( jObjectInclude . ContainsKey ( part ) )
953
- {
954
- obj [ part ] = jObjectInclude [ part ] ;
955
- }
956
- else if ( jObjectInclude . ContainsKey ( part + GroqTokens [ "[]" ] ) )
957
- {
958
- obj [ part + GroqTokens [ "[]" ] ] = jObjectInclude [ part + GroqTokens [ "[]" ] ] ;
977
+ if ( property . Key == part
978
+ || property . Key . StartsWith ( $ "{ GroqTokens [ SanityConstants . STRING_DELIMITOR ] } { part } { GroqTokens [ SanityConstants . STRING_DELIMITOR ] } ")
979
+ || property . Key . StartsWith ( part + GroqTokens [ SanityConstants . ARRAY_INDICATOR ] )
980
+ || property . Key . StartsWith ( part + GroqTokens [ SanityConstants . DEREFERENCING_OPERATOR ] ) )
981
+ {
982
+ fieldsToReplace . Add ( property . Key ) ;
983
+ }
959
984
}
960
- else if ( jObjectInclude . ContainsKey ( part + GroqTokens [ "->" ] ) )
985
+ foreach ( var key in fieldsToReplace )
961
986
{
962
- obj [ part + GroqTokens [ "->" ] ] = jObjectInclude [ part + GroqTokens [ "->" ] ] ;
987
+ obj . Remove ( key ) ;
963
988
}
964
- else if ( jObjectInclude . ContainsKey ( part + GroqTokens [ "[]" ] + GroqTokens [ "->" ] ) )
989
+
990
+ // Set field to new projection
991
+ foreach ( var include in jObjectInclude )
965
992
{
966
- obj [ part + GroqTokens [ "[]" ] + GroqTokens [ "->" ] ] = jObjectInclude [ part + GroqTokens [ "[]" ] + GroqTokens [ "->" ] ] ;
993
+ if ( include . Key == part
994
+ || include . Key . StartsWith ( $ "{ GroqTokens [ SanityConstants . STRING_DELIMITOR ] } { part } { GroqTokens [ SanityConstants . STRING_DELIMITOR ] } ")
995
+ || include . Key . StartsWith ( part + GroqTokens [ SanityConstants . ARRAY_INDICATOR ] )
996
+ || include . Key . StartsWith ( part + GroqTokens [ SanityConstants . DEREFERENCING_OPERATOR ] ) )
997
+ {
998
+ obj [ include . Key ] = include . Value ;
999
+ break ;
1000
+ }
967
1001
}
968
1002
}
969
1003
}
@@ -977,26 +1011,15 @@ private string ExpandIncludesInProjection(string projection, Dictionary<string,
977
1011
return projection ;
978
1012
}
979
1013
980
- private Dictionary < string , string > GroqTokens = new Dictionary < string , string >
981
- {
982
- { "\" " , "VVV" } ,
983
- { "\" :" , "WWW" } ,
984
- { "..." , "XXX" } ,
985
- { "->" , "YYY" } ,
986
- { "[]" , "ZZZ" } ,
987
- } ;
988
-
989
1014
private string GroqToJson ( string groq )
990
1015
{
991
- var json = groq
992
- . Replace ( " " , "" )
993
- . Replace ( "\" :" , GroqTokens [ "\" :" ] )
994
- . Replace ( "\" " , GroqTokens [ "\" " ] )
995
- . Replace ( "{" , ":{" )
996
- . Replace ( "..." , GroqTokens [ "..." ] )
997
- . Replace ( "->" , GroqTokens [ "->" ] )
998
- . Replace ( "[]" , GroqTokens [ "[]" ] )
999
- . TrimStart ( ':' ) ;
1016
+ var json = groq . Replace ( " " , "" ) ;
1017
+ foreach ( var token in GroqTokens . Keys . OrderBy ( k => GroqTokens [ k ] ) )
1018
+ {
1019
+ json = json . Replace ( token , GroqTokens [ token ] ) ;
1020
+ }
1021
+ json = json . Replace ( "{" , ":{" )
1022
+ . TrimStart ( ':' ) ;
1000
1023
1001
1024
// Replace variable names with valid json (e.g. convert myField to "myField":true)
1002
1025
var reVariables = new Regex ( "(,|{)([^\" }:,]+)(,|})" ) ;
@@ -1018,15 +1041,15 @@ private string GroqToJson(string groq)
1018
1041
1019
1042
private string JsonToGroq ( string json )
1020
1043
{
1021
- return json
1022
- . Replace ( GroqTokens [ "..." ] , "..." )
1023
- . Replace ( GroqTokens [ "->" ] , "->" )
1044
+ var groq = json
1024
1045
. Replace ( ":{" , "{" )
1025
- . Replace ( GroqTokens [ "[]" ] , "[]" )
1026
1046
. Replace ( ":true" , "" )
1027
- . Replace ( "\" " , "" )
1028
- . Replace ( GroqTokens [ "\" :" ] , "\" :" )
1029
- . Replace ( GroqTokens [ "\" " ] , "\" " ) ;
1047
+ . Replace ( "\" " , "" ) ;
1048
+ foreach ( var token in GroqTokens . Keys )
1049
+ {
1050
+ groq = groq . Replace ( GroqTokens [ token ] , token ) ;
1051
+ }
1052
+ return groq ;
1030
1053
}
1031
1054
}
1032
1055
0 commit comments