@@ -2,8 +2,10 @@ use graph::data::graphql::DocumentExt as _;
2
2
use graph:: data:: value:: Object ;
3
3
use graphql_parser:: Pos ;
4
4
use graphql_tools:: validation:: rules:: * ;
5
+ use graphql_tools:: validation:: utils:: ValidationError ;
5
6
use graphql_tools:: validation:: validate:: { validate, ValidationPlan } ;
6
7
use lazy_static:: lazy_static;
8
+ use parking_lot:: Mutex ;
7
9
use std:: collections:: { BTreeMap , HashMap , HashSet } ;
8
10
use std:: hash:: { Hash , Hasher } ;
9
11
use std:: iter:: FromIterator ;
@@ -25,6 +27,11 @@ use crate::schema::ast::{self as sast};
25
27
use crate :: values:: coercion;
26
28
use crate :: { execution:: get_field, schema:: api:: ErrorPolicy } ;
27
29
30
+ lazy_static ! {
31
+ static ref GRAPHQL_VALIDATION_CACHE : Mutex <HashMap <u64 , Vec <ValidationError >>> =
32
+ Mutex :: new( HashMap :: <u64 , Vec <ValidationError >>:: new( ) ) ;
33
+ }
34
+
28
35
lazy_static ! {
29
36
static ref GRAPHQL_VALIDATION_PLAN : ValidationPlan =
30
37
ValidationPlan :: from( if !ENV_VARS . graphql. enable_validations {
@@ -137,6 +144,54 @@ pub struct Query {
137
144
pub query_id : String ,
138
145
}
139
146
147
+ fn validate_query (
148
+ logger : & Logger ,
149
+ query : & GraphDataQuery ,
150
+ document : & s:: Document ,
151
+ ) -> Result < ( ) , Vec < QueryExecutionError > > {
152
+ let errors = {
153
+ let cached = GRAPHQL_VALIDATION_CACHE
154
+ . lock ( )
155
+ . get ( & query. shape_hash )
156
+ . cloned ( ) ;
157
+ match cached {
158
+ Some ( cached) => cached,
159
+ None => {
160
+ let validation_errors =
161
+ validate ( & document, & query. document , & GRAPHQL_VALIDATION_PLAN ) ;
162
+ GRAPHQL_VALIDATION_CACHE
163
+ . lock ( )
164
+ . insert ( query. shape_hash , validation_errors. clone ( ) ) ;
165
+ validation_errors
166
+ }
167
+ }
168
+ } ;
169
+
170
+ if !errors. is_empty ( ) {
171
+ if !ENV_VARS . graphql . silent_graphql_validations {
172
+ return Err ( errors
173
+ . into_iter ( )
174
+ . map ( |e| {
175
+ QueryExecutionError :: ValidationError (
176
+ e. locations . first ( ) . cloned ( ) ,
177
+ e. message . clone ( ) ,
178
+ )
179
+ } )
180
+ . collect ( ) ) ;
181
+ } else {
182
+ warn ! (
183
+ & logger,
184
+ "GraphQL Validation failure" ;
185
+ "query" => & query. query_text,
186
+ "variables" => & query. variables_text,
187
+ "errors" => format!( "[{:?}]" , errors. iter( ) . map( |e| e. message. clone( ) ) . collect:: <Vec <_>>( ) . join( ", " ) )
188
+ ) ;
189
+ }
190
+ }
191
+
192
+ Ok ( ( ) )
193
+ }
194
+
140
195
impl Query {
141
196
/// Process the raw GraphQL query `query` and prepare for executing it.
142
197
/// The returned `Query` has already been validated and, if `max_complexity`
@@ -150,30 +205,7 @@ impl Query {
150
205
max_complexity : Option < u64 > ,
151
206
max_depth : u8 ,
152
207
) -> Result < Arc < Self > , Vec < QueryExecutionError > > {
153
- let validation_errors =
154
- validate ( schema. document ( ) , & query. document , & GRAPHQL_VALIDATION_PLAN ) ;
155
-
156
- if !validation_errors. is_empty ( ) {
157
- if !ENV_VARS . graphql . silent_graphql_validations {
158
- return Err ( validation_errors
159
- . into_iter ( )
160
- . map ( |e| {
161
- QueryExecutionError :: ValidationError (
162
- e. locations . first ( ) . cloned ( ) ,
163
- e. message ,
164
- )
165
- } )
166
- . collect ( ) ) ;
167
- } else {
168
- warn ! (
169
- & logger,
170
- "GraphQL Validation failure" ;
171
- "query" => & query. query_text,
172
- "variables" => & query. variables_text,
173
- "errors" => format!( "[{:?}]" , validation_errors. iter( ) . map( |e| e. message. clone( ) ) . collect:: <Vec <_>>( ) . join( ", " ) )
174
- ) ;
175
- }
176
- }
208
+ validate_query ( logger, & query, & schema. document ( ) ) ?;
177
209
178
210
let mut operation = None ;
179
211
let mut fragments = HashMap :: new ( ) ;
0 commit comments