1010import graphql .execution .instrumentation .NoOpInstrumentation ;
1111import graphql .execution .instrumentation .parameters .InstrumentationExecutionParameters ;
1212import graphql .execution .instrumentation .parameters .InstrumentationValidationParameters ;
13+ import graphql .execution .preparsed .NoOpPreparsedDocumentProvider ;
14+ import graphql .execution .preparsed .PreparsedDocumentEntry ;
15+ import graphql .execution .preparsed .PreparsedDocumentProvider ;
1316import graphql .language .Document ;
1417import graphql .language .SourceLocation ;
1518import graphql .parser .Parser ;
@@ -39,6 +42,7 @@ public class GraphQL {
3942 private final ExecutionStrategy subscriptionStrategy ;
4043 private final ExecutionIdProvider idProvider ;
4144 private final Instrumentation instrumentation ;
45+ private final PreparsedDocumentProvider preparsedDocumentProvider ;
4246
4347
4448 /**
@@ -79,7 +83,7 @@ public GraphQL(GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy) {
7983 */
8084 @ Internal
8185 public GraphQL (GraphQLSchema graphQLSchema , ExecutionStrategy queryStrategy , ExecutionStrategy mutationStrategy ) {
82- this (graphQLSchema , queryStrategy , mutationStrategy , null , DEFAULT_EXECUTION_ID_PROVIDER , NoOpInstrumentation .INSTANCE );
86+ this (graphQLSchema , queryStrategy , mutationStrategy , null , DEFAULT_EXECUTION_ID_PROVIDER , NoOpInstrumentation .INSTANCE , NoOpPreparsedDocumentProvider . INSTANCE );
8387 }
8488
8589 /**
@@ -94,16 +98,17 @@ public GraphQL(GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy, Exe
9498 */
9599 @ Internal
96100 public GraphQL (GraphQLSchema graphQLSchema , ExecutionStrategy queryStrategy , ExecutionStrategy mutationStrategy , ExecutionStrategy subscriptionStrategy ) {
97- this (graphQLSchema , queryStrategy , mutationStrategy , subscriptionStrategy , DEFAULT_EXECUTION_ID_PROVIDER , NoOpInstrumentation .INSTANCE );
101+ this (graphQLSchema , queryStrategy , mutationStrategy , subscriptionStrategy , DEFAULT_EXECUTION_ID_PROVIDER , NoOpInstrumentation .INSTANCE , NoOpPreparsedDocumentProvider . INSTANCE );
98102 }
99103
100- private GraphQL (GraphQLSchema graphQLSchema , ExecutionStrategy queryStrategy , ExecutionStrategy mutationStrategy , ExecutionStrategy subscriptionStrategy , ExecutionIdProvider idProvider , Instrumentation instrumentation ) {
104+ private GraphQL (GraphQLSchema graphQLSchema , ExecutionStrategy queryStrategy , ExecutionStrategy mutationStrategy , ExecutionStrategy subscriptionStrategy , ExecutionIdProvider idProvider , Instrumentation instrumentation , PreparsedDocumentProvider preparsedDocumentProvider ) {
101105 this .graphQLSchema = assertNotNull (graphQLSchema , "queryStrategy must be non null" );
102106 this .queryStrategy = queryStrategy != null ? queryStrategy : new SimpleExecutionStrategy ();
103107 this .mutationStrategy = mutationStrategy != null ? mutationStrategy : new SimpleExecutionStrategy ();
104108 this .subscriptionStrategy = subscriptionStrategy != null ? subscriptionStrategy : new SimpleExecutionStrategy ();
105109 this .idProvider = assertNotNull (idProvider , "idProvider must be non null" );
106110 this .instrumentation = instrumentation ;
111+ this .preparsedDocumentProvider = assertNotNull (preparsedDocumentProvider , "preparsedDocumentProvider must be non null" );
107112 }
108113
109114 /**
@@ -126,6 +131,7 @@ public static class Builder {
126131 private ExecutionStrategy subscriptionExecutionStrategy = new SimpleExecutionStrategy ();
127132 private ExecutionIdProvider idProvider = DEFAULT_EXECUTION_ID_PROVIDER ;
128133 private Instrumentation instrumentation = NoOpInstrumentation .INSTANCE ;
134+ private PreparsedDocumentProvider preparsedDocumentProvider = NoOpPreparsedDocumentProvider .INSTANCE ;
129135
130136
131137 public Builder (GraphQLSchema graphQLSchema ) {
@@ -157,6 +163,11 @@ public Builder instrumentation(Instrumentation instrumentation) {
157163 return this ;
158164 }
159165
166+ public Builder preparsedDocumentProvider (PreparsedDocumentProvider preparsedDocumentProvider ) {
167+ this .preparsedDocumentProvider = assertNotNull (preparsedDocumentProvider , "PreparsedDocumentProvider must be non null" );
168+ return this ;
169+ }
170+
160171 public Builder executionIdProvider (ExecutionIdProvider executionIdProvider ) {
161172 this .idProvider = assertNotNull (executionIdProvider , "ExecutionIdProvider must be non null" );
162173 return this ;
@@ -166,7 +177,7 @@ public GraphQL build() {
166177 assertNotNull (graphQLSchema , "queryStrategy must be non null" );
167178 assertNotNull (queryExecutionStrategy , "queryStrategy must be non null" );
168179 assertNotNull (idProvider , "idProvider must be non null" );
169- return new GraphQL (graphQLSchema , queryExecutionStrategy , mutationExecutionStrategy , subscriptionExecutionStrategy , idProvider , instrumentation );
180+ return new GraphQL (graphQLSchema , queryExecutionStrategy , mutationExecutionStrategy , subscriptionExecutionStrategy , idProvider , instrumentation , preparsedDocumentProvider );
170181 }
171182 }
172183
@@ -289,18 +300,29 @@ public ExecutionResult execute(ExecutionInput executionInput) {
289300 }
290301
291302 private ExecutionResult parseValidateAndExecute (ExecutionInput executionInput ) {
292- ParseResult parseResult = parse (executionInput );
293- if (parseResult .isFailure ()) {
294- return toParseFailureExecutionResult (parseResult .getException ());
303+ PreparsedDocumentEntry preparsedDocumentEntry = preparsedDocumentProvider .get (executionInput .getQuery ());
304+ if (preparsedDocumentEntry == null ) {
305+ ParseResult parseResult = parse (executionInput );
306+ if (parseResult .isFailure ()) {
307+ preparsedDocumentEntry = new PreparsedDocumentEntry (toInvalidSyntaxError (parseResult .getException ()));
308+ } else {
309+ final Document document = parseResult .getDocument ();
310+
311+ final List <ValidationError > errors = validate (executionInput , document );
312+ if (!errors .isEmpty ()) {
313+ preparsedDocumentEntry = new PreparsedDocumentEntry (errors );
314+ } else {
315+ preparsedDocumentEntry = new PreparsedDocumentEntry (document );
316+ }
317+ }
318+ preparsedDocumentProvider .put (executionInput .getQuery (), preparsedDocumentEntry );
295319 }
296- final Document document = parseResult .getDocument ();
297320
298- final List <ValidationError > errors = validate (executionInput , document );
299- if (!errors .isEmpty ()) {
300- return new ExecutionResultImpl (errors );
321+ if (preparsedDocumentEntry .hasErrors ()) {
322+ return new ExecutionResultImpl (preparsedDocumentEntry .getErrors ());
301323 }
302324
303- return execute (executionInput , document );
325+ return execute (executionInput , preparsedDocumentEntry . getDocument () );
304326 }
305327
306328 private ParseResult parse (ExecutionInput executionInput ) {
@@ -339,11 +361,6 @@ private ExecutionResult execute(ExecutionInput executionInput, Document document
339361 return execution .execute (document , graphQLSchema , executionId , executionInput );
340362 }
341363
342- private ExecutionResult toParseFailureExecutionResult (RecognitionException exception ) {
343- InvalidSyntaxError invalidSyntaxError = toInvalidSyntaxError (exception );
344- return new ExecutionResultImpl (invalidSyntaxError );
345- }
346-
347364 private InvalidSyntaxError toInvalidSyntaxError (RecognitionException recognitionException ) {
348365 SourceLocation sourceLocation = null ;
349366 if (recognitionException != null ) {
0 commit comments