From 891b1de7f655e2daa358dad0c66fa0ad217a4a14 Mon Sep 17 00:00:00 2001 From: Abhishoya Lunavat Date: Mon, 30 Oct 2023 12:27:48 -0400 Subject: [PATCH] Optional executionContext --- .../api/cache/GraphQLProdCacheKey.java | 53 +++++++++++++------ .../graphQL/api/execute/GraphQLExecute.java | 42 ++++++++++----- .../graphQL/api/test/TestGraphQLAPI.java | 6 +-- 3 files changed, 68 insertions(+), 33 deletions(-) diff --git a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-query/src/main/java/org/finos/legend/engine/query/graphQL/api/cache/GraphQLProdCacheKey.java b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-query/src/main/java/org/finos/legend/engine/query/graphQL/api/cache/GraphQLProdCacheKey.java index f931373a3b1..e7c0a8c27e2 100644 --- a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-query/src/main/java/org/finos/legend/engine/query/graphQL/api/cache/GraphQLProdCacheKey.java +++ b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-query/src/main/java/org/finos/legend/engine/query/graphQL/api/cache/GraphQLProdCacheKey.java @@ -26,26 +26,37 @@ public class GraphQLProdCacheKey implements GraphQLCacheKey private String queryClassPath; private String query; private String dataspacePath; + private String executionContext; - public GraphQLProdCacheKey(String groupID, String artifactId, String versionId, String mappingPath, String runtimePath, String queryClassPath, String query) + GraphQLProdCacheKey() { - this.groupID = groupID; - this.artifactId = artifactId; - this.versionId = versionId; - this.mappingPath = mappingPath; - this.runtimePath = runtimePath; - this.queryClassPath = queryClassPath; - this.query = query; + + } + + public static GraphQLProdCacheKey newGraphQLProdCacheKey(String groupID, String artifactId, String versionId, String mappingPath, String runtimePath, String queryClassPath, String query) + { + GraphQLProdCacheKey graphQLProdCacheKey = new GraphQLProdCacheKey(); + graphQLProdCacheKey.groupID = groupID; + graphQLProdCacheKey.artifactId = artifactId; + graphQLProdCacheKey.versionId = versionId; + graphQLProdCacheKey.mappingPath = mappingPath; + graphQLProdCacheKey.runtimePath = runtimePath; + graphQLProdCacheKey.queryClassPath = queryClassPath; + graphQLProdCacheKey.query = query; + return graphQLProdCacheKey; } - public GraphQLProdCacheKey(String groupID, String artifactId, String versionId, String dataspacePath, String queryClassPath, String query) + public static GraphQLProdCacheKey newGraphQLProdCacheKeyWithDataspace(String groupID, String artifactId, String versionId, String dataspacePath, String executionContext, String queryClassPath, String query) { - this.groupID = groupID; - this.artifactId = artifactId; - this.versionId = versionId; - this.dataspacePath = dataspacePath; - this.queryClassPath = queryClassPath; - this.query = query; + GraphQLProdCacheKey graphQLProdCacheKey = new GraphQLProdCacheKey(); + graphQLProdCacheKey.groupID = groupID; + graphQLProdCacheKey.artifactId = artifactId; + graphQLProdCacheKey.versionId = versionId; + graphQLProdCacheKey.dataspacePath = dataspacePath; + graphQLProdCacheKey.executionContext = executionContext; + graphQLProdCacheKey.queryClassPath = queryClassPath; + graphQLProdCacheKey.query = query; + return graphQLProdCacheKey; } @Override @@ -60,12 +71,20 @@ public boolean equals(Object o) return false; } GraphQLProdCacheKey that = (GraphQLProdCacheKey) o; - return Objects.equal(groupID, that.groupID) && Objects.equal(artifactId, that.artifactId) && Objects.equal(versionId, that.versionId) && Objects.equal(mappingPath, that.mappingPath) && Objects.equal(runtimePath, that.runtimePath) && Objects.equal(queryClassPath, that.queryClassPath) && Objects.equal(query, that.query) && Objects.equal(dataspacePath, that.dataspacePath); + return Objects.equal(groupID, that.groupID) + && Objects.equal(artifactId, that.artifactId) + && Objects.equal(versionId, that.versionId) + && Objects.equal(mappingPath, that.mappingPath) + && Objects.equal(runtimePath, that.runtimePath) + && Objects.equal(queryClassPath, that.queryClassPath) + && Objects.equal(query, that.query) + && Objects.equal(dataspacePath, that.dataspacePath) + && Objects.equal(executionContext, that.executionContext); } @Override public int hashCode() { - return Objects.hashCode(groupID, artifactId, versionId, mappingPath, runtimePath, queryClassPath, query, dataspacePath); + return Objects.hashCode(groupID, artifactId, versionId, mappingPath, runtimePath, queryClassPath, query, dataspacePath, executionContext); } } diff --git a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-query/src/main/java/org/finos/legend/engine/query/graphQL/api/execute/GraphQLExecute.java b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-query/src/main/java/org/finos/legend/engine/query/graphQL/api/execute/GraphQLExecute.java index 490deef6a47..4d0bd65edc3 100644 --- a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-query/src/main/java/org/finos/legend/engine/query/graphQL/api/execute/GraphQLExecute.java +++ b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-query/src/main/java/org/finos/legend/engine/query/graphQL/api/execute/GraphQLExecute.java @@ -89,10 +89,12 @@ import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; +import javax.ws.rs.DefaultValue; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @@ -236,7 +238,7 @@ private Response executeIntrospection(String queryClassPath, Document document, "}").type(MediaType.TEXT_HTML_TYPE).build(); } - private Response executeGraphQLQuery(String queryClassPath, String dataspacePath, Document document, GraphQLCacheKey graphQLCacheKey, MutableList profiles, Callable modelLoader) + private Response executeGraphQLQueryWithDataspace(String queryClassPath, String dataspacePath, String executionContext, Document document, GraphQLCacheKey graphQLCacheKey, MutableList profiles, Callable modelLoader) { List planWithSerialized; OperationDefinition graphQLQuery = GraphQLExecutionHelper.findQuery(document); @@ -257,7 +259,7 @@ private Response executeGraphQLQuery(String queryClassPath, String dataspacePath { LOGGER.debug(new LogInfo(profiles, LoggingEventType.GRAPHQL_EXECUTE, "Cache miss. Generating new plan").toString()); pureModel = modelLoader.call(); - planWithSerialized = buildPlanWithParameter(queryClassPath, dataspacePath, document, graphQLQuery, pureModel, graphQLCacheKey); + planWithSerialized = buildPlanWithParameterUsingDataspace(queryClassPath, dataspacePath, executionContext, document, graphQLQuery, pureModel, graphQLCacheKey); graphQLPlanCache.put(graphQLCacheKey, planWithSerialized); } else @@ -268,7 +270,7 @@ private Response executeGraphQLQuery(String queryClassPath, String dataspacePath else //no cache so we generate the plan { pureModel = modelLoader.call(); - planWithSerialized = buildPlanWithParameter(queryClassPath, dataspacePath, document, graphQLQuery, pureModel, graphQLCacheKey); + planWithSerialized = buildPlanWithParameterUsingDataspace(queryClassPath, dataspacePath, executionContext, document, graphQLQuery, pureModel, graphQLCacheKey); } } } @@ -426,22 +428,36 @@ private List buildExtensionsPlanWithParameter(String rootF return serializedNamedPlans; } - private Root_meta_pure_metamodel_dataSpace_DataSpaceExecutionContext getDataspaceDefaultExecutionContext(String dataspacePath, PureModel pureModel) + private Root_meta_pure_metamodel_dataSpace_DataSpaceExecutionContext getDataspaceExecutionContext(String dataspacePath, String executionContext, PureModel pureModel) { PackageableElement packageableElement = pureModel.getPackageableElement(dataspacePath); Assert.assertTrue(packageableElement instanceof Root_meta_pure_metamodel_dataSpace_DataSpace, () -> "Can't find data space '" + dataspacePath + "'"); - return ((Root_meta_pure_metamodel_dataSpace_DataSpace) packageableElement)._executionContexts().select(dataSpaceExecutionContext -> dataSpaceExecutionContext._name().equals(((Root_meta_pure_metamodel_dataSpace_DataSpace) packageableElement)._defaultExecutionContext()._name())).toList().get(0); + if (executionContext.equals("defaultExecutionContext")) + { + return ((Root_meta_pure_metamodel_dataSpace_DataSpace) packageableElement)._executionContexts().select(dataSpaceExecutionContext -> dataSpaceExecutionContext._name().equals(((Root_meta_pure_metamodel_dataSpace_DataSpace) packageableElement)._defaultExecutionContext()._name())).toList().get(0); + } + else + { + try + { + return ((Root_meta_pure_metamodel_dataSpace_DataSpace) packageableElement)._executionContexts().select(dataSpaceExecutionContext -> dataSpaceExecutionContext._name().equals(executionContext)).toList().get(0); + } + catch (Exception e) + { + throw new RuntimeException("Invalid execution context " + executionContext, e); + } + } } - private List buildPlanWithParameter(String queryClassPath, String dataspacePath, Document document, OperationDefinition query, PureModel pureModel, GraphQLCacheKey graphQLCacheKey) + private List buildPlanWithParameterUsingDataspace(String queryClassPath, String dataspacePath, String executionContext, Document document, OperationDefinition query, PureModel pureModel, GraphQLCacheKey graphQLCacheKey) { RichIterable extensions = this.extensionsFunc.apply(pureModel); org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.type.Class _class = pureModel.getClass(queryClassPath); org.finos.legend.pure.generated.Root_meta_external_query_graphQL_metamodel_sdl_Document queryDoc = toPureModel(document, pureModel); - Root_meta_pure_metamodel_dataSpace_DataSpaceExecutionContext executionContext = getDataspaceDefaultExecutionContext(dataspacePath, pureModel); - Mapping mapping = executionContext._mapping(); - Root_meta_core_runtime_Runtime runtime = executionContext._defaultRuntime()._runtimeValue(); + Root_meta_pure_metamodel_dataSpace_DataSpaceExecutionContext executionContextPureElement = getDataspaceExecutionContext(dataspacePath, executionContext, pureModel); + Mapping mapping = executionContextPureElement._mapping(); + Root_meta_core_runtime_Runtime runtime = executionContextPureElement._defaultRuntime()._runtimeValue(); return getSerializedNamedPlans(pureModel, extensions, _class, mapping, runtime, document, query, queryDoc, graphQLCacheKey); } @@ -536,7 +552,7 @@ public Response executeProd(@Context HttpServletRequest request, @PathParam("gro try (Scope scope = GlobalTracer.get().buildSpan("GraphQL: Execute").startActive(true)) { Document document = GraphQLGrammarParser.newInstance().parseDocument(query.query); - GraphQLProdCacheKey key = new GraphQLProdCacheKey(groupId, artifactId, versionId, mappingPath, runtimePath, queryClassPath, objectMapper.writeValueAsString(createCachableGraphQLQuery(document))); + GraphQLProdCacheKey key = GraphQLProdCacheKey.newGraphQLProdCacheKey(groupId, artifactId, versionId, mappingPath, runtimePath, queryClassPath, objectMapper.writeValueAsString(createCachableGraphQLQuery(document))); return this.executeGraphQLQuery(queryClassPath, mappingPath, runtimePath, document, key, profiles, () -> loadProjectModel(profiles, groupId, artifactId, versionId)); } @@ -550,15 +566,15 @@ public Response executeProd(@Context HttpServletRequest request, @PathParam("gro @ApiOperation(value = "Execute a GraphQL query in the context of a mapping and a runtime") @Path("execute/prod/{groupId}/{artifactId}/{versionId}/query/{queryClassPath}/dataspace/{dataspacePath}") @Consumes({MediaType.APPLICATION_JSON, APPLICATION_ZLIB}) - public Response executeProd(@Context HttpServletRequest request, @PathParam("groupId") String groupId, @PathParam("artifactId") String artifactId, @PathParam("versionId") String versionId, @PathParam("dataspacePath") String dataspacePath, @PathParam("queryClassPath") String queryClassPath, Query query, @ApiParam(hidden = true) @Pac4JProfileManager ProfileManager pm) + public Response executeProdWithDataspace(@Context HttpServletRequest request, @PathParam("groupId") String groupId, @PathParam("artifactId") String artifactId, @PathParam("versionId") String versionId, @PathParam("dataspacePath") String dataspacePath, @QueryParam("executionContext") @DefaultValue("defaultExecutionContext") String executionContext, @PathParam("queryClassPath") String queryClassPath, Query query, @ApiParam(hidden = true) @Pac4JProfileManager ProfileManager pm) { MutableList profiles = ProfileManagerHelper.extractProfiles(pm); try (Scope scope = GlobalTracer.get().buildSpan("GraphQL: Execute").startActive(true)) { Document document = GraphQLGrammarParser.newInstance().parseDocument(query.query); - GraphQLProdCacheKey key = new GraphQLProdCacheKey(groupId, artifactId, versionId, dataspacePath, queryClassPath, objectMapper.writeValueAsString(createCachableGraphQLQuery(document))); + GraphQLProdCacheKey key = GraphQLProdCacheKey.newGraphQLProdCacheKeyWithDataspace(groupId, artifactId, versionId, dataspacePath, queryClassPath, executionContext, objectMapper.writeValueAsString(createCachableGraphQLQuery(document))); - return this.executeGraphQLQuery(queryClassPath, dataspacePath, document, key, profiles, () -> loadProjectModel(profiles, groupId, artifactId, versionId)); + return this.executeGraphQLQueryWithDataspace(queryClassPath, dataspacePath, executionContext, document, key, profiles, () -> loadProjectModel(profiles, groupId, artifactId, versionId)); } catch (Exception ex) { diff --git a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-query/src/test/java/org/finos/legend/engine/query/graphQL/api/test/TestGraphQLAPI.java b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-query/src/test/java/org/finos/legend/engine/query/graphQL/api/test/TestGraphQLAPI.java index 3aa6b1b6f37..6b7c744bbb9 100644 --- a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-query/src/test/java/org/finos/legend/engine/query/graphQL/api/test/TestGraphQLAPI.java +++ b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-query/src/test/java/org/finos/legend/engine/query/graphQL/api/test/TestGraphQLAPI.java @@ -183,7 +183,7 @@ public void testGraphQLExecuteProdAPI_Relational_With_Dataspace() throws Excepti " }\n" + " }\n" + " }"; - Response response = graphQLExecute.executeProd(mockRequest, "org.finos.legend.graphql", "model.one", "1.0.0", "simple::dataspace", "simple::model::Query", query, null); + Response response = graphQLExecute.executeProdWithDataspace(mockRequest, "org.finos.legend.graphql", "model.one", "1.0.0", "simple::dataspace", "defaultExecutionContext", "simple::model::Query", query, null); String expected = "{" + "\"data\":{" + @@ -214,7 +214,7 @@ public void testGraphQLExecuteProdAPI_Relational_With_Dataspace_With_Caching() t " }\n" + " }\n" + " }"; - Response response = graphQLExecute.executeProd(mockRequest, "org.finos.legend.graphql", "model.one", "1.0.0", "simple::dataspace", "simple::model::Query", query, null); + Response response = graphQLExecute.executeProdWithDataspace(mockRequest, "org.finos.legend.graphql", "model.one", "1.0.0", "simple::dataspace", "defaultExecutionContext", "simple::model::Query", query, null); String expected = "{" + "\"data\":{" + @@ -229,7 +229,7 @@ public void testGraphQLExecuteProdAPI_Relational_With_Dataspace_With_Caching() t Assert.assertEquals(0, cache.getCache().stats().hitCount(), 0); Assert.assertEquals(1, cache.getCache().stats().missCount(), 0); - response = graphQLExecute.executeProd(mockRequest, "org.finos.legend.graphql", "model.one", "1.0.0", "simple::dataspace", "simple::model::Query", query, null); + response = graphQLExecute.executeProdWithDataspace(mockRequest, "org.finos.legend.graphql", "model.one", "1.0.0", "simple::dataspace", "defaultExecutionContext", "simple::model::Query", query, null); Assert.assertEquals(expected, responseAsString(response)); Assert.assertEquals(1, cache.getCache().stats().hitCount(), 0); Assert.assertEquals(1, cache.getCache().stats().missCount(), 0);