diff --git a/legend-engine-config/legend-engine-repl/legend-engine-repl-client/src/main/java/org/finos/legend/engine/repl/core/legend/LegendInterface.java b/legend-engine-config/legend-engine-repl/legend-engine-repl-client/src/main/java/org/finos/legend/engine/repl/core/legend/LegendInterface.java index af06c5f5aad..d02cd09c75f 100644 --- a/legend-engine-config/legend-engine-repl/legend-engine-repl-client/src/main/java/org/finos/legend/engine/repl/core/legend/LegendInterface.java +++ b/legend-engine-config/legend-engine-repl/legend-engine-repl-client/src/main/java/org/finos/legend/engine/repl/core/legend/LegendInterface.java @@ -22,7 +22,14 @@ public interface LegendInterface { - PureModelContextData parse(String txt); + default PureModelContextData parse(String txt) + { + return this.parse(txt, true); + } + + PureModelContextData parse(String txt, boolean returnSourceInformation); + + String render(PureModelContextData model); PureModel compile(PureModelContextData model); diff --git a/legend-engine-config/legend-engine-repl/legend-engine-repl-client/src/main/java/org/finos/legend/engine/repl/core/legend/LocalLegendInterface.java b/legend-engine-config/legend-engine-repl/legend-engine-repl-client/src/main/java/org/finos/legend/engine/repl/core/legend/LocalLegendInterface.java index 6fcd5667ea8..fcf844e97ce 100644 --- a/legend-engine-config/legend-engine-repl/legend-engine-repl-client/src/main/java/org/finos/legend/engine/repl/core/legend/LocalLegendInterface.java +++ b/legend-engine-config/legend-engine-repl/legend-engine-repl-client/src/main/java/org/finos/legend/engine/repl/core/legend/LocalLegendInterface.java @@ -14,13 +14,14 @@ package org.finos.legend.engine.repl.core.legend; -import java.util.concurrent.ForkJoinPool; import org.eclipse.collections.api.RichIterable; import org.eclipse.collections.api.tuple.Pair; import org.finos.legend.engine.language.pure.compiler.Compiler; import org.finos.legend.engine.language.pure.compiler.toPureGraph.PureModel; import org.finos.legend.engine.language.pure.compiler.toPureGraph.PureModelProcessParameter; import org.finos.legend.engine.language.pure.grammar.from.PureGrammarParser; +import org.finos.legend.engine.language.pure.grammar.to.PureGrammarComposer; +import org.finos.legend.engine.language.pure.grammar.to.PureGrammarComposerContext; import org.finos.legend.engine.plan.generation.PlanGenerator; import org.finos.legend.engine.plan.platform.PlanPlatform; import org.finos.legend.engine.protocol.pure.v1.model.context.PureModelContextData; @@ -31,6 +32,7 @@ import org.finos.legend.pure.generated.Root_meta_pure_extension_Extension; import java.net.URL; +import java.util.concurrent.ForkJoinPool; import static org.finos.legend.engine.repl.shared.ExecutionHelper.REPL_RUN_FUNCTION_QUALIFIED_PATH; @@ -39,7 +41,7 @@ public class LocalLegendInterface implements LegendInterface private final ForkJoinPool forkJoinPool = new ForkJoinPool(Runtime.getRuntime().availableProcessors()); @Override - public PureModelContextData parse(String txt) + public PureModelContextData parse(String txt, boolean returnSourceInformation) { // txt = "#>{a::DB.test}#->filter(t|$t.name->startsWith('Dr'))->meta::pure::mapping::from(^meta::core::runtime::Runtime\n" + // " (\n" + @@ -52,7 +54,7 @@ public PureModelContextData parse(String txt) // " )\n" + // " )\n" + // " )"; - return PureGrammarParser.newInstance().parseModel(txt); + return PureGrammarParser.newInstance().parseModel(txt, returnSourceInformation); // // "" + // "###Runtime\n" + @@ -78,6 +80,12 @@ public PureModelContextData parse(String txt) // "function a::b::c::d():Any[*]{"+txt+"}"); } + @Override + public String render(PureModelContextData model) + { + return PureGrammarComposer.newInstance(PureGrammarComposerContext.Builder.newInstance().build()).renderPureModelContextData(model); + } + @Override public PureModel compile(PureModelContextData pureModelContextData) { @@ -87,7 +95,7 @@ public PureModel compile(PureModelContextData pureModelContextData) @Override public Root_meta_pure_executionPlan_ExecutionPlan generatePlan(PureModel pureModel, boolean debug) { - RichIterable extensions = PureCoreExtensionLoader.extensions().flatCollect(e -> e.extraPureCoreExtensions(pureModel.getExecutionSupport())); + RichIterable extensions = PureCoreExtensionLoader.extensions().flatCollect(e -> e.extraPureCoreExtensions(pureModel.getExecutionSupport())); Pair res = PlanGenerator.generateExecutionPlanAsPure(pureModel.getConcreteFunctionDefinition_safe(REPL_RUN_FUNCTION_QUALIFIED_PATH), null, pureModel, PlanPlatform.JAVA, "", debug, extensions); if (debug) { diff --git a/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/REPLServerHelpers.java b/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/REPLServerHelpers.java index 799b0fd25d8..db0e9a5e083 100644 --- a/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/REPLServerHelpers.java +++ b/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/REPLServerHelpers.java @@ -30,22 +30,32 @@ import org.finos.legend.engine.plan.execution.PlanExecutor; import org.finos.legend.engine.plan.execution.result.builder.tds.TDSBuilder; import org.finos.legend.engine.plan.execution.stores.relational.result.RelationalResult; +import org.finos.legend.engine.protocol.pure.v1.model.context.EngineErrorType; import org.finos.legend.engine.protocol.pure.v1.model.context.PureModelContextData; import org.finos.legend.engine.protocol.pure.v1.model.executionPlan.nodes.SQLExecutionNode; import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.connection.Connection; +import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.connection.ConnectionPointer; +import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.connection.PackageableConnection; import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.domain.Function; import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.runtime.PackageableRuntime; +import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.section.SectionIndex; +import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.store.relational.connection.DatabaseType; +import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.store.relational.connection.RelationalDatabaseConnection; +import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.store.relational.model.Database; +import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.store.relational.model.Schema; +import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.store.relational.model.Table; import org.finos.legend.engine.protocol.pure.v1.model.valueSpecification.ValueSpecification; import org.finos.legend.engine.protocol.pure.v1.model.valueSpecification.application.AppliedFunction; import org.finos.legend.engine.protocol.pure.v1.model.valueSpecification.raw.ClassInstance; -import org.finos.legend.engine.protocol.pure.v1.model.valueSpecification.raw.packageableElement.PackageableElementPtr; import org.finos.legend.engine.protocol.pure.v1.model.valueSpecification.raw.classInstance.relation.ColSpec; import org.finos.legend.engine.protocol.pure.v1.model.valueSpecification.raw.classInstance.relation.ColSpecArray; +import org.finos.legend.engine.protocol.pure.v1.model.valueSpecification.raw.classInstance.relation.RelationStoreAccessor; +import org.finos.legend.engine.protocol.pure.v1.model.valueSpecification.raw.packageableElement.PackageableElementPtr; import org.finos.legend.engine.repl.client.Client; import org.finos.legend.engine.repl.core.legend.LegendInterface; -import org.finos.legend.engine.repl.dataCube.server.model.DataCubeQuery; import org.finos.legend.engine.repl.dataCube.server.model.DataCubeQueryColumn; import org.finos.legend.engine.repl.shared.ExecutionHelper; +import org.finos.legend.engine.shared.core.operational.errorManagement.EngineException; import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.relation.RelationType; import org.finos.legend.pure.m3.navigation.M3Paths; import org.finos.legend.pure.m3.navigation.generictype.GenericType; @@ -62,12 +72,26 @@ public class REPLServerHelpers { - public static void handleResponse(HttpExchange exchange, int responseCode, String response, REPLServerState state) + public static void handleJSONResponse(HttpExchange exchange, int responseCode, String response, REPLServerState state) + { + handleResponse(exchange, responseCode, response, state, "application/json"); + } + + public static void handleTextResponse(HttpExchange exchange, int responseCode, String response, REPLServerState state) + { + handleResponse(exchange, responseCode, response, state, "text/plain"); + } + + private static void handleResponse(HttpExchange exchange, int responseCode, String response, REPLServerState state, String contentType) { try { OutputStream os = exchange.getResponseBody(); byte[] byteResponse = response != null ? response.getBytes(StandardCharsets.UTF_8) : new byte[0]; + if (contentType != null) + { + exchange.getResponseHeaders().add("Content-Type", contentType); + } exchange.sendResponseHeaders(responseCode, byteResponse.length); os.write(byteResponse); os.close(); @@ -87,8 +111,9 @@ public static class REPLServerState public Long startTime; private PureModelContextData currentPureModelContextData; - private DataCubeQuery query; - private Map source; + private String query; + private Map queryConfiguration; + private Map querySource; public REPLServerState(Client client, ObjectMapper objectMapper, PlanExecutor planExecutor, LegendInterface legendInterface) { @@ -108,8 +133,8 @@ private void initialize(PureModelContextData pureModelContextData, Listfrom(), such as when mapping is specified Function function = (Function) ListIterate.select(pureModelContextData.getElements(), e -> e.getPath().equals(REPL_RUN_FUNCTION_QUALIFIED_PATH)).getFirst(); - String runtime = null; - String mapping = null; + String runtimePath = null; + String mappingPath = null; Deque fns = new LinkedList<>(); ValueSpecification currentExpression = function.body.get(0); while (currentExpression instanceof AppliedFunction) @@ -121,23 +146,23 @@ private void initialize(PureModelContextData pureModelContextData, Listfrom(), only one is expected"); } - runtime = newRuntime; + runtimePath = newRuntime; } else if (fn.parameters.size() == 3) { // TODO: verify the type of the element (i.e. Mapping & Runtime) String newMapping = ((PackageableElementPtr) fn.parameters.get(1)).fullPath; String newRuntime = ((PackageableElementPtr) fn.parameters.get(2)).fullPath; - if ((mapping != null && !mapping.equals(newMapping)) || (runtime != null && !runtime.equals(newRuntime))) + if ((mappingPath != null && !mappingPath.equals(newMapping)) || (runtimePath != null && !runtimePath.equals(newRuntime))) { throw new RuntimeException("Can't launch DataCube. Source query contains multiple different ->from(), only one is expected"); } - mapping = newMapping; - runtime = newRuntime; + mappingPath = newMapping; + runtimePath = newRuntime; } } else @@ -151,29 +176,105 @@ else if (fn.parameters.size() == 3) fn.parameters.set(0, currentExpression); currentExpression = fn; } - Connection connection = null; - if (runtime != null) + + // Build the minimal PMCD needed to persist to run the query + // NOTE: the ONLY use case we want to support right now is when user uses a single DB with relation store accessor + // with a single connection in a single runtime, no mapping, no join, etc. + // Those cases would be too complex to handle and result in too big of a PMCD to persist. + boolean isLocal = false; + boolean isPersistenceSupported = false; + PureModelContextData model = null; + PackageableRuntime runtime = null; + if (runtimePath != null) + { + String _runtimePath = runtimePath; + runtime = (PackageableRuntime) ListIterate.select(pureModelContextData.getElements(), e -> e.getPath().equals(_runtimePath)).getOnly(); + } + Database database = null; + if (currentExpression instanceof ClassInstance && ((ClassInstance) currentExpression).value instanceof RelationStoreAccessor) + { + RelationStoreAccessor accessor = (RelationStoreAccessor) ((ClassInstance) currentExpression).value; + + if (accessor.path.size() <= 1) + { + throw new EngineException("Error in the accessor definition. Please provide a table.", accessor.sourceInformation, EngineErrorType.COMPILATION); + } + String schemaName = (accessor.path.size() == 3) ? accessor.path.get(1) : "default"; + String tableName = (accessor.path.size() == 3) ? accessor.path.get(2) : accessor.path.get(1); + + // clone the database, only extract the schema and table that we need + Database _database = (Database) ListIterate.select(pureModelContextData.getElements(), e -> e.getPath().equals(accessor.path.get(0))).getOnly(); + Schema _schema = ListIterate.select(_database.schemas, s -> s.name.equals(schemaName)).getOnly(); + Table _table = ListIterate.select(_schema.tables, t -> t.name.equals(tableName)).getOnly(); + database = new Database(); + database.name = _database.name; + database._package = _database._package; + Schema schema = new Schema(); + schema.name = _schema.name; + Table table = new Table(); + table.name = _table.name; + table.columns = _table.columns; + schema.tables = Lists.mutable.with(table); + database.schemas = Lists.mutable.with(schema); + } + PackageableConnection connection = null; + if (runtimePath != null) { - String _runtime = runtime; - PackageableRuntime rt = (PackageableRuntime) ListIterate.select(pureModelContextData.getElements(), e -> e.getPath().equals(_runtime)).getFirst(); + String _runtime = runtimePath; + PackageableRuntime rt = (PackageableRuntime) ListIterate.select(pureModelContextData.getElements(), e -> e.getPath().equals(_runtime)).getOnly(); if (rt != null && rt.runtimeValue.connections.size() == 1 && rt.runtimeValue.connections.get(0).storeConnections.size() == 1) { - connection = rt.runtimeValue.connections.get(0).storeConnections.get(0).connection; + Connection conn = rt.runtimeValue.connections.get(0).storeConnections.get(0).connection; + if (conn instanceof ConnectionPointer) + { + PackageableConnection _connection = (PackageableConnection) ListIterate.select(pureModelContextData.getElements(), e -> e.getPath().equals(((ConnectionPointer) conn).connection)).getOnly(); + if (_connection.connectionValue instanceof RelationalDatabaseConnection) + { + connection = _connection; + isLocal = DatabaseType.DuckDB.equals(((RelationalDatabaseConnection) _connection.connectionValue).databaseType); + } + } + } + } + // The only case we want to support persisting the model is when we have a single DB and connection + if (database != null && connection != null && runtime != null && mappingPath == null) + { + model = PureModelContextData.newBuilder() + .withSerializer(pureModelContextData.serializer) + .withElements(Lists.mutable.with(database, connection, runtime)) + .build(); + try + { + this.legendInterface.compile(model); + model = this.legendInterface.parse(this.legendInterface.render(model), false); + model = PureModelContextData.newBuilder().withSerializer(model.serializer).withElements(ListIterate.reject(model.getElements(), el -> el instanceof SectionIndex)).build(); + isPersistenceSupported = true; + } + catch (Exception e) + { + this.client.printDebug("Error while compiling persistent model: " + e.getMessage()); + // something was wrong with the assembled model, reset it + model = null; } } + Map source = Maps.mutable.empty(); source.put("_type", "repl"); - source.put("timestamp", this.startTime); source.put("query", currentExpression.accept(DEPRECATED_PureGrammarComposerCore.Builder.newInstance().build())); - source.put("runtime", runtime); - source.put("mapping", mapping); + source.put("runtime", runtimePath); + source.put("model", model); + // some extra analytics metadata which would not be part of the persistent query source.put("columns", columns); - source.put("connection", connection); - this.source = source; + source.put("mapping", mappingPath); + source.put("timestamp", this.startTime); + source.put("isLocal", isLocal); + source.put("isPersistenceSupported", isPersistenceSupported); + this.querySource = source; + + // -------------------- CONFIGURATION -------------------- + this.queryConfiguration = null; // initially, the config is not initialized // -------------------- QUERY -------------------- - DataCubeQuery query = new DataCubeQuery(); - query.configuration = null; // initially, the config is not initialized // NOTE: for this, the initial query is going to be a select all AppliedFunction partialFn = new AppliedFunction(); partialFn.function = "select"; @@ -185,8 +286,7 @@ else if (fn.parameters.size() == 3) return colSpec; }); partialFn.parameters = Lists.mutable.with(new ClassInstance("colSpecArray", colSpecArray, null)); - query.query = partialFn.accept(DEPRECATED_PureGrammarComposerCore.Builder.newInstance().build()); - this.query = query; + this.query = partialFn.accept(DEPRECATED_PureGrammarComposerCore.Builder.newInstance().build()); } public void initializeFromTable(PureModelContextData pureModelContextData) @@ -253,14 +353,19 @@ public PureModelContextData getCurrentPureModelContextData() return data; } - public DataCubeQuery getQuery() + public String getQuery() { return this.query; } - public Map getSource() + public Map getQueryConfiguration() + { + return this.queryConfiguration; + } + + public Map getQuerySource() { - return this.source; + return this.querySource; } } diff --git a/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/handler/DataCubeInfrastructure.java b/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/handler/DataCubeInfrastructure.java index 44915cda55d..ccdef4a7c32 100644 --- a/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/handler/DataCubeInfrastructure.java +++ b/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/handler/DataCubeInfrastructure.java @@ -19,6 +19,8 @@ import org.finos.legend.engine.repl.dataCube.server.REPLServer; import org.finos.legend.engine.repl.dataCube.server.model.DataCubeInfrastructureInfo; import org.finos.legend.engine.repl.dataCube.shared.DataCubeSampleData; +import org.finos.legend.engine.shared.core.identity.Identity; +import org.finos.legend.engine.shared.core.kerberos.SubjectTools; import java.io.InputStream; import java.io.OutputStream; @@ -39,14 +41,28 @@ public HttpHandler getHandler(REPLServerState state) try { DataCubeInfrastructureInfo info = new DataCubeInfrastructureInfo(); - info.gridClientLicense = System.getProperty("legend.repl.dataCube.gridLicenseKey") == null ? "" : System.getProperty("legend.repl.dataCube.gridLicenseKey"); + try + { + Identity identity = Identity.makeIdentity(SubjectTools.getLocalSubject()); + if (identity != null) + { + info.currentUser = identity.getName(); + } + } + catch (Exception ignored) + { + // do nothing + } + info.gridClientLicense = System.getProperty("legend.repl.dataCube.gridLicenseKey"); + info.queryServerBaseUrl = System.getProperty("legend.repl.dataCube.queryServerBaseUrl"); + info.hostedApplicationBaseUrl = System.getProperty("legend.repl.dataCube.hostedApplicationBaseUrl"); info.simpleSampleDataTableName = DataCubeSampleData.TREE.tableName; info.complexSampleDataTableName = DataCubeSampleData.SPORT.tableName; - handleResponse(exchange, 200, state.objectMapper.writeValueAsString(info), state); + handleJSONResponse(exchange, 200, state.objectMapper.writeValueAsString(info), state); } catch (Exception e) { - handleResponse(exchange, 500, e.getMessage(), state); + handleTextResponse(exchange, 500, e.getMessage(), state); } } }; @@ -93,7 +109,7 @@ else if (resourcePath.endsWith(".css")) } catch (Exception e) { - handleResponse(exchange, 500, e.getMessage(), state); + handleTextResponse(exchange, 500, e.getMessage(), state); } } }; diff --git a/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/handler/DataCubeQueryBuilder.java b/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/handler/DataCubeQueryBuilder.java index 9debbe9347a..8766944751d 100644 --- a/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/handler/DataCubeQueryBuilder.java +++ b/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/handler/DataCubeQueryBuilder.java @@ -58,11 +58,18 @@ public HttpHandler getHandler(REPLServerState state) String requestBody = bufferReader.lines().collect(Collectors.joining()); DataCubeParseQueryInput input = state.objectMapper.readValue(requestBody, DataCubeParseQueryInput.class); ValueSpecification result = DataCubeHelpers.parseQuery(input.code, input.returnSourceInformation); - handleResponse(exchange, 200, state.objectMapper.writeValueAsString(result), state); + handleJSONResponse(exchange, 200, state.objectMapper.writeValueAsString(result), state); } catch (Exception e) { - handleResponse(exchange, 400, e instanceof EngineException ? state.objectMapper.writeValueAsString(new DataCubeQueryBuilderError((EngineException) e)) : e.getMessage(), state); + if (e instanceof EngineException) + { + handleJSONResponse(exchange, 400, state.objectMapper.writeValueAsString(new DataCubeQueryBuilderError((EngineException) e)), state); + } + else + { + handleTextResponse(exchange, 500, e.getMessage(), state); + } } } }; @@ -84,11 +91,11 @@ public HttpHandler getHandler(REPLServerState state) BufferedReader bufferReader = new BufferedReader(inputStreamReader); String requestBody = bufferReader.lines().collect(Collectors.joining()); DataCubeGetValueSpecificationCodeInput input = state.objectMapper.readValue(requestBody, DataCubeGetValueSpecificationCodeInput.class); - handleResponse(exchange, 200, DataCubeHelpers.getQueryCode(input.value, input.pretty), state); + handleTextResponse(exchange, 200, DataCubeHelpers.getQueryCode(input.value, input.pretty), state); } catch (Exception e) { - handleResponse(exchange, 400, e.getMessage(), state); + handleTextResponse(exchange, 400, e.getMessage(), state); } } }; @@ -122,11 +129,11 @@ public HttpHandler getHandler(REPLServerState state) result.queries.put(key, null); } }); - handleResponse(exchange, 200, state.objectMapper.writeValueAsString(result), state); + handleJSONResponse(exchange, 200, state.objectMapper.writeValueAsString(result), state); } catch (Exception e) { - handleResponse(exchange, 400, e.getMessage(), state); + handleTextResponse(exchange, 400, e.getMessage(), state); } } }; @@ -149,11 +156,11 @@ public HttpHandler getHandler(REPLServerState state) String requestBody = bufferReader.lines().collect(Collectors.joining()); DataCubeQueryTypeaheadInput input = state.objectMapper.readValue(requestBody, DataCubeQueryTypeaheadInput.class); CompletionResult result = DataCubeHelpers.getCodeTypeahead(input.code, input.baseQuery, input.isolated ? null : state.getCurrentPureModelContextData(), state.client.getCompleterExtensions(), state.legendInterface); - handleResponse(exchange, 200, state.objectMapper.writeValueAsString(result.getCompletion()), state); + handleJSONResponse(exchange, 200, state.objectMapper.writeValueAsString(result.getCompletion()), state); } catch (Exception e) { - handleResponse(exchange, 500, e.getMessage(), state); + handleTextResponse(exchange, 500, e.getMessage(), state); } } }; @@ -175,11 +182,18 @@ public HttpHandler getHandler(REPLServerState state) BufferedReader bufferReader = new BufferedReader(inputStreamReader); String requestBody = bufferReader.lines().collect(Collectors.joining()); DataCubeGetQueryRelationReturnTypeInput input = state.objectMapper.readValue(requestBody, DataCubeGetQueryRelationReturnTypeInput.class); - handleResponse(exchange, 200, state.objectMapper.writeValueAsString(DataCubeHelpers.getRelationReturnType(state.legendInterface, input.query, input.isolated ? null : state.getCurrentPureModelContextData())), state); + handleJSONResponse(exchange, 200, state.objectMapper.writeValueAsString(DataCubeHelpers.getRelationReturnType(state.legendInterface, input.query, input.isolated ? null : state.getCurrentPureModelContextData())), state); } catch (Exception e) { - handleResponse(exchange, 500, e instanceof EngineException ? state.objectMapper.writeValueAsString(new DataCubeQueryBuilderError((EngineException) e)) : e.getMessage(), state); + if (e instanceof EngineException) + { + handleJSONResponse(exchange, 500, state.objectMapper.writeValueAsString(new DataCubeQueryBuilderError((EngineException) e)), state); + } + else + { + handleTextResponse(exchange, 500, e.getMessage(), state); + } } } }; @@ -224,19 +238,26 @@ public HttpHandler getHandler(REPLServerState state) { PureModelContextData data = PureGrammarParser.newInstance().parseModel(graphCode); RelationType relationType = DataCubeHelpers.getRelationReturnType(state.legendInterface, data); - handleResponse(exchange, 200, state.objectMapper.writeValueAsString(relationType), state); + handleJSONResponse(exchange, 200, state.objectMapper.writeValueAsString(relationType), state); } catch (EngineException e) { SourceInformation sourceInformation = e.getSourceInformation(); sourceInformation.startLine -= lineOffset; sourceInformation.endLine -= lineOffset; - handleResponse(exchange, 400, state.objectMapper.writeValueAsString(new DataCubeQueryBuilderError(new EngineException(e.getMessage(), sourceInformation, e.getErrorType()))), state); + handleJSONResponse(exchange, 400, state.objectMapper.writeValueAsString(new DataCubeQueryBuilderError(new EngineException(e.getMessage(), sourceInformation, e.getErrorType()))), state); } } catch (Exception e) { - handleResponse(exchange, 500, e instanceof EngineException ? state.objectMapper.writeValueAsString(new DataCubeQueryBuilderError((EngineException) e)) : e.getMessage(), state); + if (e instanceof EngineException) + { + handleJSONResponse(exchange, 500, state.objectMapper.writeValueAsString(new DataCubeQueryBuilderError((EngineException) e)), state); + } + else + { + handleTextResponse(exchange, 500, e.getMessage(), state); + } } } }; @@ -254,14 +275,16 @@ public HttpHandler getHandler(REPLServerState state) { try { - DataCubeQuery query = state.getQuery(); - Map source = state.getSource(); + String query = state.getQuery(); + Map configuration = state.getQueryConfiguration(); + Map source = state.getQuerySource(); if (query != null) { DataCubeGetBaseQueryResult result = new DataCubeGetBaseQueryResult(); result.query = query; + result.configuration = configuration; result.source = source; - handleResponse(exchange, 200, state.objectMapper.writeValueAsString(result), state); + handleJSONResponse(exchange, 200, state.objectMapper.writeValueAsString(result), state); } else { @@ -270,7 +293,7 @@ public HttpHandler getHandler(REPLServerState state) } catch (Exception e) { - handleResponse(exchange, 500, e.getMessage(), state); + handleTextResponse(exchange, 500, e.getMessage(), state); } } }; diff --git a/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/handler/DataCubeQueryExecutor.java b/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/handler/DataCubeQueryExecutor.java index 7609dbad1dd..cc8e94b03f4 100644 --- a/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/handler/DataCubeQueryExecutor.java +++ b/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/handler/DataCubeQueryExecutor.java @@ -50,11 +50,11 @@ public HttpHandler getHandler(REPLServerState state) Lambda lambda = input.query; PureModelContextData data = DataCubeHelpers.injectNewFunction(state.getCurrentPureModelContextData(), lambda).getOne(); DataCubeExecutionResult result = executeQuery(state.client, state.legendInterface, state.planExecutor, data, debug); - handleResponse(exchange, 200, state.objectMapper.writeValueAsString(result), state); + handleJSONResponse(exchange, 200, state.objectMapper.writeValueAsString(result), state); } catch (Exception e) { - handleResponse(exchange, 500, e.getMessage(), state); + handleTextResponse(exchange, 500, e.getMessage(), state); } } }; diff --git a/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/model/DataCubeGetBaseQueryResult.java b/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/model/DataCubeGetBaseQueryResult.java index b73ab865282..666ada393df 100644 --- a/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/model/DataCubeGetBaseQueryResult.java +++ b/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/model/DataCubeGetBaseQueryResult.java @@ -18,6 +18,7 @@ public class DataCubeGetBaseQueryResult { - public DataCubeQuery query; + public String query; + public Map configuration; public Map source; } diff --git a/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/model/DataCubeInfrastructureInfo.java b/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/model/DataCubeInfrastructureInfo.java index c61b90614d2..b90cc257973 100644 --- a/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/model/DataCubeInfrastructureInfo.java +++ b/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/model/DataCubeInfrastructureInfo.java @@ -16,7 +16,10 @@ public class DataCubeInfrastructureInfo { + public String currentUser; public String gridClientLicense; + public String queryServerBaseUrl; + public String hostedApplicationBaseUrl; public String simpleSampleDataTableName; public String complexSampleDataTableName; } diff --git a/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/model/DataCubeQuery.java b/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/model/DataCubeQuery.java deleted file mode 100644 index ec6ba099076..00000000000 --- a/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/server/model/DataCubeQuery.java +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2024 Goldman Sachs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package org.finos.legend.engine.repl.dataCube.server.model; - -import java.util.Map; - -public class DataCubeQuery -{ - public String query; - public Map configuration; -}