From 13b8a03a41a76682b28695a22d25e3c216f58c88 Mon Sep 17 00:00:00 2001 From: Igor Dianov Date: Wed, 8 Apr 2020 10:32:40 -0700 Subject: [PATCH] fix: remove readOnly transaction attribute in GraphQLController --- .../jpa/query/web/GraphQLController.java | 55 +++++++++---------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/graphql-jpa-query-web/src/main/java/com/introproventures/graphql/jpa/query/web/GraphQLController.java b/graphql-jpa-query-web/src/main/java/com/introproventures/graphql/jpa/query/web/GraphQLController.java index c2ea94578..ca775dc58 100644 --- a/graphql-jpa-query-web/src/main/java/com/introproventures/graphql/jpa/query/web/GraphQLController.java +++ b/graphql-jpa-query-web/src/main/java/com/introproventures/graphql/jpa/query/web/GraphQLController.java @@ -44,7 +44,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.introproventures.graphql.jpa.query.schema.GraphQLExecutor; import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor; - import graphql.DeferredExecutionResult; import graphql.ExecutionResult; import graphql.GraphQL; @@ -56,7 +55,7 @@ * */ @RestController -@Transactional(readOnly = true) +@Transactional public class GraphQLController { private static final String PATH = "${spring.graphql.jpa.query.path:/graphql}"; @@ -76,7 +75,7 @@ public GraphQLController(GraphQLExecutor graphQLExecutor, ObjectMapper mapper) { this.graphQLExecutor = graphQLExecutor; this.mapper = mapper; } - + @GetMapping(value = PATH, consumes = MediaType.TEXT_EVENT_STREAM_VALUE, produces = MediaType.TEXT_EVENT_STREAM_VALUE) @@ -85,18 +84,18 @@ public SseEmitter getEventStream(@RequestParam(name = "query") final String quer Map variablesMap = variablesStringToMap(variables); ExecutionResult executionResult = graphQLExecutor.execute(query, variablesMap); - + SseEmitter sseEmitter = new SseEmitter(180_000L); // FIXME need to add parameter sseEmitter.onTimeout(sseEmitter::complete); - + if(!executionResult.getErrors().isEmpty()) { sseEmitter.send(executionResult.toSpecification(), MediaType.APPLICATION_JSON); sseEmitter.completeWithError(new RuntimeException(executionResult.getErrors().toString())); return sseEmitter; } - - Publisher deferredResults = executionResult.getData(); - + + Publisher deferredResults = executionResult.getData(); + // now send each deferred part which is given to us as a reactive stream // of deferred values deferredResults.subscribe(new Subscriber() { @@ -115,7 +114,7 @@ public void onNext(ExecutionResult executionResult) { try { SseEventBuilder event = wrap(executionResult); - + sseEmitter.send(event); } catch (IOException e) { sseEmitter.completeWithError(e); @@ -131,21 +130,21 @@ public void onError(Throwable t) { public void onComplete() { sseEmitter.complete(); } - + SseEventBuilder wrap(ExecutionResult executionResult) { Map result = executionResult.getData(); String name = result.keySet().iterator().next(); - + return SseEmitter.event() .id((id++).toString()) .name(name) .data(result, MediaType.APPLICATION_JSON); - + } - }); - + }); + return sseEmitter; - } + } /** * Handle standard GraphQL POST request that consumes @@ -191,11 +190,11 @@ public void postJson(@RequestBody @Valid final GraphQLQueryRequest queryRequest, public void getQuery(@RequestParam(name = "query") final String query, @RequestParam(name = "variables", required = false) final String variables, HttpServletResponse httpServletResponse) throws IOException { - + Map variablesMap = variablesStringToMap(variables); ExecutionResult executionResult = graphQLExecutor.execute(query, variablesMap); - + sendResponse(httpServletResponse, executionResult); } @@ -220,7 +219,7 @@ public void postForm(@RequestParam(name = "query") final String query, Map variablesMap = variablesStringToMap(variables); ExecutionResult executionResult = graphQLExecutor.execute(query, variablesMap); - + sendResponse(httpServletResponse, executionResult); } @@ -312,11 +311,11 @@ public void setVariables(Map variables) { } } - + private void sendResponse(HttpServletResponse response, ExecutionResult executionResult) throws IOException { if (hasDeferredResults(executionResult)) { sendDeferredResponse(response, executionResult, executionResult.getExtensions()); - } + } else if (hasPublisherResults(executionResult)) { sendMultipartResponse(response, executionResult, executionResult.getData()); } else { @@ -328,8 +327,8 @@ private void sendNormalResponse(HttpServletResponse response, ExecutionResult ex response.setContentType("application/json"); response.setStatus(HttpServletResponse.SC_OK); mapper.writeValue(response.getOutputStream(), executionResult.toSpecification()); - } - + } + private boolean hasDeferredResults(ExecutionResult executionResult) { return Optional.ofNullable(executionResult.getExtensions()) .map(it -> it.containsKey(GraphQL.DEFERRED_RESULTS)) @@ -339,12 +338,12 @@ private boolean hasDeferredResults(ExecutionResult executionResult) { private boolean hasPublisherResults(ExecutionResult executionResult) { return Publisher.class.isInstance(executionResult.getData()); } - + private static final String CRLF = "\r\n"; @SuppressWarnings("unchecked") - private void sendDeferredResponse(HttpServletResponse response, - ExecutionResult executionResult, + private void sendDeferredResponse(HttpServletResponse response, + ExecutionResult executionResult, Map extensions) { Publisher deferredResults = (Publisher) extensions.get(GraphQL.DEFERRED_RESULTS); try { @@ -354,8 +353,8 @@ private void sendDeferredResponse(HttpServletResponse response, } } - private void sendMultipartResponse(HttpServletResponse response, - ExecutionResult executionResult, + private void sendMultipartResponse(HttpServletResponse response, + ExecutionResult executionResult, Publisher deferredResults) { // this implements this Apollo defer spec: https://github.com/apollographql/apollo-server/blob/defer-support/docs/source/defer-support.md // the spec says CRLF + "-----" + CRLF is needed at the end, but it works without it and with it we get client @@ -445,6 +444,6 @@ private String bodyToString() { throw new RuntimeException(e); } } - } + } }