@@ -697,39 +697,88 @@ impl<'s> RawQuery<'s> {
697
697
}
698
698
}
699
699
700
+ // graphql-bug-compat
701
+ // Everything with looking up defaults here has to do with making queries
702
+ // that use undefined variables work so that a query `{ things(first:
703
+ // $first) { .. }}` where `$first` is not defined acts as if `$first` was
704
+ // set to the default value 100
705
+ trait DefaultLookup {
706
+ fn find ( & self , name : & str ) -> Option < r:: Value > {
707
+ self . get ( name)
708
+ . map ( |value| r:: Value :: try_from ( value. clone ( ) ) )
709
+ . transpose ( )
710
+ . expect ( "our API schema does not use variables as default values" )
711
+ }
712
+
713
+ fn get ( & self , name : & str ) -> Option < & q:: Value > ;
714
+ }
715
+
716
+ struct DirectiveDefaults < ' a > ( Option < & ' a Vec < ( String , q:: Value ) > > ) ;
717
+
718
+ impl < ' a > DefaultLookup for DirectiveDefaults < ' a > {
719
+ fn get ( & self , name : & str ) -> Option < & q:: Value > {
720
+ self . 0
721
+ . and_then ( |values| values. iter ( ) . find ( |( n, _) | n == name) . map ( |( _, v) | v) )
722
+ }
723
+ }
724
+
725
+ struct FieldArgumentDefaults < ' a > ( & ' a s:: Field ) ;
726
+
727
+ impl < ' a > DefaultLookup for FieldArgumentDefaults < ' a > {
728
+ fn get ( & self , name : & str ) -> Option < & q:: Value > {
729
+ self . 0
730
+ . arguments
731
+ . iter ( )
732
+ . find ( |arg| arg. name == name)
733
+ . and_then ( |arg| arg. default_value . as_ref ( ) )
734
+ }
735
+ }
736
+
700
737
struct Transform {
701
738
schema : Arc < ApiSchema > ,
702
739
variables : HashMap < String , r:: Value > ,
703
740
fragments : HashMap < String , q:: FragmentDefinition > ,
704
741
}
705
742
706
743
impl Transform {
707
- fn variable ( & self , name : & str , pos : & Pos ) -> Result < r:: Value , QueryExecutionError > {
744
+ fn variable (
745
+ & self ,
746
+ name : & str ,
747
+ default : Option < r:: Value > ,
748
+ pos : & Pos ,
749
+ ) -> Result < r:: Value , QueryExecutionError > {
708
750
self . variables
709
751
. get ( name)
710
752
. map ( |value| value. clone ( ) )
753
+ . or ( default)
711
754
. ok_or_else ( || QueryExecutionError :: MissingVariableError ( pos. clone ( ) , name. to_string ( ) ) )
712
755
}
713
756
714
757
/// Interpolate variable references in the arguments `args`
715
758
fn interpolate_arguments (
716
759
& self ,
717
760
args : Vec < ( String , q:: Value ) > ,
761
+ defaults : & dyn DefaultLookup ,
718
762
pos : & Pos ,
719
763
) -> Result < Vec < ( String , r:: Value ) > , QueryExecutionError > {
720
764
args. into_iter ( )
721
- . map ( |( name, val) | self . interpolate_value ( val, pos) . map ( |val| ( name, val) ) )
765
+ . map ( |( name, val) | {
766
+ let default = defaults. find ( & name) ;
767
+ self . interpolate_value ( val, default, pos)
768
+ . map ( |val| ( name, val) )
769
+ } )
722
770
. collect ( )
723
771
}
724
772
725
773
/// Turn `value` into an `r::Value` by resolving variable references
726
774
fn interpolate_value (
727
775
& self ,
728
776
value : q:: Value ,
777
+ default : Option < r:: Value > ,
729
778
pos : & Pos ,
730
779
) -> Result < r:: Value , QueryExecutionError > {
731
780
match value {
732
- q:: Value :: Variable ( var) => self . variable ( & var, pos) ,
781
+ q:: Value :: Variable ( var) => self . variable ( & var, default , pos) ,
733
782
q:: Value :: Int ( ref num) => Ok ( r:: Value :: Int (
734
783
num. as_i64 ( ) . expect ( "q::Value::Int contains an i64" ) ,
735
784
) ) ,
@@ -741,14 +790,14 @@ impl Transform {
741
790
q:: Value :: List ( vals) => {
742
791
let vals: Vec < _ > = vals
743
792
. into_iter ( )
744
- . map ( |val| self . interpolate_value ( val, pos) )
793
+ . map ( |val| self . interpolate_value ( val, None , pos) )
745
794
. collect :: < Result < Vec < _ > , _ > > ( ) ?;
746
795
Ok ( r:: Value :: List ( vals) )
747
796
}
748
797
q:: Value :: Object ( map) => {
749
798
let mut rmap = BTreeMap :: new ( ) ;
750
799
for ( key, value) in map. into_iter ( ) {
751
- let value = self . interpolate_value ( value, pos) ?;
800
+ let value = self . interpolate_value ( value, None , pos) ?;
752
801
rmap. insert ( key, value) ;
753
802
}
754
803
Ok ( r:: Value :: object ( rmap) )
@@ -762,6 +811,7 @@ impl Transform {
762
811
fn interpolate_directives (
763
812
& self ,
764
813
dirs : Vec < q:: Directive > ,
814
+ defns : & Vec < s:: Directive > ,
765
815
) -> Result < ( Vec < a:: Directive > , bool ) , QueryExecutionError > {
766
816
let dirs = dirs
767
817
. into_iter ( )
@@ -771,7 +821,13 @@ impl Transform {
771
821
position,
772
822
arguments,
773
823
} = dir;
774
- self . interpolate_arguments ( arguments, & position)
824
+ let defaults = DirectiveDefaults (
825
+ defns
826
+ . iter ( )
827
+ . find ( |defn| defn. name == name)
828
+ . map ( |defn| & defn. arguments ) ,
829
+ ) ;
830
+ self . interpolate_arguments ( arguments, & defaults, & position)
775
831
. map ( |arguments| a:: Directive {
776
832
name,
777
833
position,
@@ -882,12 +938,13 @@ impl Transform {
882
938
) ]
883
939
} ) ?;
884
940
885
- let ( directives, skip) = self . interpolate_directives ( directives) ?;
941
+ let ( directives, skip) = self . interpolate_directives ( directives, & field_type . directives ) ?;
886
942
if skip {
887
943
return Ok ( None ) ;
888
944
}
889
945
890
- let mut arguments = self . interpolate_arguments ( arguments, & position) ?;
946
+ let mut arguments =
947
+ self . interpolate_arguments ( arguments, & FieldArgumentDefaults ( & field_type) , & position) ?;
891
948
self . coerce_argument_values ( & mut arguments, parent_type, & name) ?;
892
949
893
950
let is_leaf_type = self . schema . document ( ) . is_leaf_type ( & field_type. field_type ) ;
@@ -1003,7 +1060,7 @@ impl Transform {
1003
1060
ty : ObjectOrInterface ,
1004
1061
newset : & mut a:: SelectionSet ,
1005
1062
) -> Result < ( ) , Vec < QueryExecutionError > > {
1006
- let ( directives, skip) = self . interpolate_directives ( directives) ?;
1063
+ let ( directives, skip) = self . interpolate_directives ( directives, & vec ! [ ] ) ?;
1007
1064
// Field names in fragment spreads refer to this type, which will
1008
1065
// usually be different from the outer type
1009
1066
let ty = match frag_cond {
0 commit comments