1+ use std:: { collections:: HashSet , iter:: Iterator } ;
2+
13use crate :: {
24 ast:: InputValue ,
35 schema:: {
4- meta:: { EnumMeta , InputObjectMeta , MetaType } ,
6+ meta:: { Argument , EnumMeta , InputObjectMeta , MetaType } ,
57 model:: { SchemaType , TypeType } ,
68 } ,
79 value:: ScalarValue ,
810} ;
9- use std:: collections:: HashSet ;
1011
11- pub fn is_valid_literal_value < S > (
12+ /// Common error messages used in validation and execution of GraphQL operations
13+ pub ( crate ) mod error {
14+ use std:: fmt:: Display ;
15+
16+ pub ( crate ) fn non_null ( arg_type : impl Display ) -> String {
17+ format ! ( "\" null\" specified for not nullable type \" {arg_type}\" " )
18+ }
19+
20+ pub ( crate ) fn enum_value ( arg_value : impl Display , arg_type : impl Display ) -> String {
21+ format ! ( "Invalid value \" {arg_value}\" for enum \" {arg_type}\" " )
22+ }
23+
24+ pub ( crate ) fn type_value ( arg_value : impl Display , arg_type : impl Display ) -> String {
25+ format ! ( "Invalid value \" {arg_value}\" for type \" {arg_type}\" " )
26+ }
27+
28+ pub ( crate ) fn parser ( arg_type : impl Display , msg : impl Display ) -> String {
29+ format ! ( "Parser error for \" {arg_type}\" : {msg}" )
30+ }
31+
32+ pub ( crate ) fn not_input_object ( arg_type : impl Display ) -> String {
33+ format ! ( "\" {arg_type}\" is not an input object" )
34+ }
35+
36+ pub ( crate ) fn field (
37+ arg_type : impl Display ,
38+ field_name : impl Display ,
39+ error_message : impl Display ,
40+ ) -> String {
41+ format ! ( "Error on \" {arg_type}\" field \" {field_name}\" : {error_message}" )
42+ }
43+
44+ pub ( crate ) fn missing_fields ( arg_type : impl Display , missing_fields : impl Display ) -> String {
45+ format ! ( "\" {arg_type}\" is missing fields: {missing_fields}" )
46+ }
47+
48+ pub ( crate ) fn unknown_field ( arg_type : impl Display , field_name : impl Display ) -> String {
49+ format ! ( "Field \" {field_name}\" does not exist on type \" {arg_type}\" " )
50+ }
51+
52+ pub ( crate ) fn invalid_list_length (
53+ arg_value : impl Display ,
54+ actual : usize ,
55+ expected : usize ,
56+ ) -> String {
57+ format ! ( "Expected list of length {expected}, but \" {arg_value}\" has length {actual}" )
58+ }
59+ }
60+
61+ /// Validates the specified field of a GraphQL object and returns an error message if the field is
62+ /// invalid.
63+ fn validate_object_field < S > (
64+ schema : & SchemaType < S > ,
65+ object_type : & TypeType < S > ,
66+ object_fields : & [ Argument < S > ] ,
67+ field_value : & InputValue < S > ,
68+ field_key : & str ,
69+ ) -> Option < String >
70+ where
71+ S : ScalarValue ,
72+ {
73+ let field_type = object_fields
74+ . iter ( )
75+ . filter ( |f| f. name == field_key)
76+ . map ( |f| schema. make_type ( & f. arg_type ) )
77+ . next ( ) ;
78+
79+ if let Some ( field_arg_type) = field_type {
80+ let error_message = validate_literal_value ( schema, & field_arg_type, field_value) ;
81+
82+ error_message. map ( |m| error:: field ( object_type, field_key, m) )
83+ } else {
84+ Some ( error:: unknown_field ( object_type, field_key) )
85+ }
86+ }
87+
88+ /// Validates the specified GraphQL literal and returns an error message if the it's invalid.
89+ pub fn validate_literal_value < S > (
1290 schema : & SchemaType < S > ,
1391 arg_type : & TypeType < S > ,
1492 arg_value : & InputValue < S > ,
15- ) -> bool
93+ ) -> Option < String >
1694where
1795 S : ScalarValue ,
1896{
1997 match * arg_type {
2098 TypeType :: NonNull ( ref inner) => {
2199 if arg_value. is_null ( ) {
22- false
100+ Some ( error :: non_null ( arg_type ) )
23101 } else {
24- is_valid_literal_value ( schema, inner, arg_value)
102+ validate_literal_value ( schema, inner, arg_value)
25103 }
26104 }
27105 TypeType :: List ( ref inner, expected_size) => match * arg_value {
28- InputValue :: Null | InputValue :: Variable ( _) => true ,
106+ InputValue :: Null | InputValue :: Variable ( _) => None ,
29107 InputValue :: List ( ref items) => {
30108 if let Some ( expected) = expected_size {
31109 if items. len ( ) != expected {
32- return false ;
110+ return Some ( error :: invalid_list_length ( arg_value , items . len ( ) , expected ) ) ;
33111 }
34112 }
35113 items
36114 . iter ( )
37- . all ( |i| is_valid_literal_value ( schema, inner, & i. item ) )
115+ . find_map ( |i| validate_literal_value ( schema, inner, & i. item ) )
38116 }
39117 ref v => {
40118 if let Some ( expected) = expected_size {
41119 if expected != 1 {
42- return false ;
120+ return Some ( error :: invalid_list_length ( arg_value , 1 , expected ) ) ;
43121 }
44122 }
45- is_valid_literal_value ( schema, inner, v)
123+ validate_literal_value ( schema, inner, v)
46124 }
47125 } ,
48126 TypeType :: Concrete ( t) => {
@@ -51,19 +129,23 @@ where
51129 if let ( & InputValue :: Scalar ( _) , Some ( & MetaType :: Enum ( EnumMeta { .. } ) ) ) =
52130 ( arg_value, arg_type. to_concrete ( ) )
53131 {
54- return false ;
132+ return Some ( error :: enum_value ( arg_value , arg_type ) ) ;
55133 }
56134
57135 match * arg_value {
58- InputValue :: Null | InputValue :: Variable ( _) => true ,
136+ InputValue :: Null | InputValue :: Variable ( _) => None ,
59137 ref v @ InputValue :: Scalar ( _) | ref v @ InputValue :: Enum ( _) => {
60138 if let Some ( parse_fn) = t. input_value_parse_fn ( ) {
61- parse_fn ( v) . is_ok ( )
139+ if parse_fn ( v) . is_ok ( ) {
140+ None
141+ } else {
142+ Some ( error:: type_value ( arg_value, arg_type) )
143+ }
62144 } else {
63- false
145+ Some ( error :: parser ( arg_type , "no parser present" ) )
64146 }
65147 }
66- InputValue :: List ( _) => false ,
148+ InputValue :: List ( _) => Some ( "Input lists are not literals" . to_owned ( ) ) ,
67149 InputValue :: Object ( ref obj) => {
68150 if let MetaType :: InputObject ( InputObjectMeta {
69151 ref input_fields, ..
@@ -77,23 +159,33 @@ where
77159 } )
78160 . collect :: < HashSet < _ > > ( ) ;
79161
80- let all_types_ok = obj. iter ( ) . all ( |( key, value) | {
162+ let error_message = obj. iter ( ) . find_map ( |( key, value) | {
81163 remaining_required_fields. remove ( & key. item ) ;
82- if let Some ( ref arg_type) = input_fields
83- . iter ( )
84- . filter ( |f| f. name == key. item )
85- . map ( |f| schema. make_type ( & f. arg_type ) )
86- . next ( )
87- {
88- is_valid_literal_value ( schema, arg_type, & value. item )
89- } else {
90- false
91- }
164+ validate_object_field (
165+ schema,
166+ arg_type,
167+ input_fields,
168+ & value. item ,
169+ & key. item ,
170+ )
92171 } ) ;
93172
94- all_types_ok && remaining_required_fields. is_empty ( )
173+ if error_message. is_some ( ) {
174+ return error_message;
175+ }
176+
177+ if remaining_required_fields. is_empty ( ) {
178+ None
179+ } else {
180+ let missing_fields = remaining_required_fields
181+ . into_iter ( )
182+ . map ( |s| format ! ( "\" {}\" " , & * * s) )
183+ . collect :: < Vec < _ > > ( )
184+ . join ( ", " ) ;
185+ Some ( error:: missing_fields ( arg_type, missing_fields) )
186+ }
95187 } else {
96- false
188+ Some ( error :: not_input_object ( arg_type ) )
97189 }
98190 }
99191 }
0 commit comments