From 1760878502dcfc1047adbfc624cbb1f71589e325 Mon Sep 17 00:00:00 2001 From: Rafael Bey <24432403+rafaelbey@users.noreply.github.com> Date: Wed, 30 Oct 2024 16:13:12 -0400 Subject: [PATCH] Display TDS using REPL print API (#254) * Display TDS using REPL print API * Update engine to 4.64.1 --- .../core/FunctionExecutionSupport.java | 28 +++++--- .../notebook/PureBookLSPGrammarExtension.java | 49 ++++++++++++-- .../TestPureBookLSPGrammarExtension.java | 66 +++++++++++++++++++ .../execution/LegendExecutionResult.java | 11 +++- pom.xml | 2 +- 5 files changed, 139 insertions(+), 17 deletions(-) diff --git a/legend-engine-ide-lsp-default-extensions/src/main/java/org/finos/legend/engine/ide/lsp/extension/core/FunctionExecutionSupport.java b/legend-engine-ide-lsp-default-extensions/src/main/java/org/finos/legend/engine/ide/lsp/extension/core/FunctionExecutionSupport.java index 579cd95a..e1b1167c 100644 --- a/legend-engine-ide-lsp-default-extensions/src/main/java/org/finos/legend/engine/ide/lsp/extension/core/FunctionExecutionSupport.java +++ b/legend-engine-ide-lsp-default-extensions/src/main/java/org/finos/legend/engine/ide/lsp/extension/core/FunctionExecutionSupport.java @@ -298,11 +298,7 @@ static void executePlan(GlobalState globalState, FunctionExecutionSupport execut } else { - PlanExecutor planExecutor = extension.getPlanExecutor(); - MutableMap parametersToConstantResult = Maps.mutable.empty(); - ExecuteNodeParameterTransformationHelper.buildParameterToConstantResult(executionPlan, inputParameters, parametersToConstantResult); - Identity identity = getIdentity(); - Result result = planExecutor.execute(executionPlan, parametersToConstantResult, identity.getName(), identity, context); + Result result = executePlan(executionPlan, context, inputParameters, extension); collectResults(executionSupport, entityPath, result, docId, sectionNum, inputParameters, format, results::add); } } @@ -312,6 +308,15 @@ static void executePlan(GlobalState globalState, FunctionExecutionSupport execut } } + static Result executePlan(SingleExecutionPlan executionPlan, PlanExecutionContext context, Map inputParameters, AbstractLSPGrammarExtension extension) + { + PlanExecutor planExecutor = extension.getPlanExecutor(); + MutableMap parametersToConstantResult = Maps.mutable.empty(); + ExecuteNodeParameterTransformationHelper.buildParameterToConstantResult(executionPlan, inputParameters, parametersToConstantResult); + Identity identity = getIdentity(); + return planExecutor.execute(executionPlan, parametersToConstantResult, identity.getName(), identity, context); + } + static Iterable generateExecutionPlan(FunctionExecutionSupport executionSupport, SectionState section, String entityPath, Map executableArgs, Map inputParameters) { AbstractLSPGrammarExtension extension = executionSupport.getExtension(); @@ -474,7 +479,7 @@ private static Identity getIdentity() return Optional.ofNullable(subject).map(Identity::makeIdentity).orElseGet(Identity::getAnonymousIdentity); } - private static void collectResults(FunctionExecutionSupport executionSupport, String entityPath, org.finos.legend.engine.plan.execution.result.Result result, String docId, int secNum, Map inputParameters, SerializationFormat format, Consumer consumer) + static void collectResults(FunctionExecutionSupport executionSupport, String entityPath, org.finos.legend.engine.plan.execution.result.Result result, String docId, int secNum, Map inputParameters, SerializationFormat format, Consumer consumer) { AbstractLSPGrammarExtension extension = executionSupport.getExtension(); @@ -544,9 +549,9 @@ class FunctionLegendExecutionResult extends LegendExecutionResult private final int sectionNum; private final Map inputParameters; - public FunctionLegendExecutionResult(List ids, Type type, String message, String logMessage, String uri, int sectionNum, Map inputParameters) + private FunctionLegendExecutionResult(List ids, Type type, String message, String logMessage, String uri, int sectionNum, Map inputParameters, String messageType) { - super(ids, type, message, logMessage, null); + super(ids, type, message, logMessage, null, messageType); this.uri = uri; this.sectionNum = sectionNum; this.inputParameters = inputParameters; @@ -567,9 +572,14 @@ public Map getInputParameters() return inputParameters; } + public static FunctionLegendExecutionResult newResult(String id, Type type, String message, String logMessage, String uri, int sectionNum, Map inputParameters, String messageType) + { + return new FunctionLegendExecutionResult(Collections.singletonList(id), type, message, logMessage, uri, sectionNum, inputParameters, messageType); + } + public static FunctionLegendExecutionResult newResult(String id, Type type, String message, String logMessage, String uri, int sectionNum, Map inputParameters) { - return new FunctionLegendExecutionResult(Collections.singletonList(id), type, message, logMessage, uri, sectionNum, inputParameters); + return newResult(id, type, message, logMessage, uri, sectionNum, inputParameters, "json"); } } diff --git a/legend-engine-ide-lsp-default-extensions/src/main/java/org/finos/legend/engine/ide/lsp/extension/notebook/PureBookLSPGrammarExtension.java b/legend-engine-ide-lsp-default-extensions/src/main/java/org/finos/legend/engine/ide/lsp/extension/notebook/PureBookLSPGrammarExtension.java index 017aad54..d0b1d18f 100644 --- a/legend-engine-ide-lsp-default-extensions/src/main/java/org/finos/legend/engine/ide/lsp/extension/notebook/PureBookLSPGrammarExtension.java +++ b/legend-engine-ide-lsp-default-extensions/src/main/java/org/finos/legend/engine/ide/lsp/extension/notebook/PureBookLSPGrammarExtension.java @@ -23,6 +23,7 @@ import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import java.util.stream.Stream; import org.eclipse.collections.api.factory.Lists; import org.eclipse.collections.api.list.MutableList; @@ -40,6 +41,7 @@ import org.finos.legend.engine.ide.lsp.extension.diagnostic.LegendDiagnostic; import org.finos.legend.engine.ide.lsp.extension.execution.LegendExecutionResult; import org.finos.legend.engine.ide.lsp.extension.reference.LegendReference; +import org.finos.legend.engine.ide.lsp.extension.repl.extension.LegendREPLExtensionFeature; import org.finos.legend.engine.ide.lsp.extension.state.DocumentState; import org.finos.legend.engine.ide.lsp.extension.state.GlobalState; import org.finos.legend.engine.ide.lsp.extension.state.NotebookDocumentState; @@ -52,13 +54,16 @@ import org.finos.legend.engine.language.pure.grammar.from.domain.DomainParser; import org.finos.legend.engine.language.pure.grammar.from.extension.PureGrammarParserExtensions; import org.finos.legend.engine.plan.execution.PlanExecutionContext; +import org.finos.legend.engine.plan.execution.result.Result; +import org.finos.legend.engine.plan.execution.result.serialization.SerializationFormat; import org.finos.legend.engine.protocol.pure.v1.model.SourceInformation; import org.finos.legend.engine.protocol.pure.v1.model.context.EngineErrorType; import org.finos.legend.engine.protocol.pure.v1.model.executionPlan.SingleExecutionPlan; import org.finos.legend.engine.protocol.pure.v1.model.valueSpecification.raw.Lambda; import org.finos.legend.engine.repl.autocomplete.Completer; +import org.finos.legend.engine.repl.autocomplete.CompleterExtension; import org.finos.legend.engine.repl.autocomplete.CompletionResult; -import org.finos.legend.engine.repl.relational.autocomplete.RelationalCompleterExtension; +import org.finos.legend.engine.repl.core.ReplExtension; import org.finos.legend.engine.shared.core.operational.errorManagement.EngineException; import org.finos.legend.engine.shared.javaCompiler.JavaCompileException; import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.LambdaFunction; @@ -74,6 +79,8 @@ public class PureBookLSPGrammarExtension implements LegendLSPGrammarExtension private DomainParser domainParser; private PureGrammarParserContext parserContext; private PureLSPGrammarExtension pureGrammarExtension; + private MutableList replExtensions; + private MutableList completerExtensions; @Override public String getName() @@ -89,6 +96,20 @@ public void startup(GlobalState globalState) this.pureGrammarExtension = globalState.findGrammarExtensionThatImplements(PureLSPGrammarExtension.class) .findAny() .orElseThrow(() -> new UnsupportedOperationException("Notebook requires pure grammar extension")); + + List replFeatures = globalState + .findFeatureThatImplements(LegendREPLExtensionFeature.class) + .collect(Collectors.toList()); + + this.replExtensions = replFeatures.stream() + .map(LegendREPLExtensionFeature::getReplExtensions) + .flatMap(List::stream) + .collect(Collectors.toCollection(Lists.mutable::empty)); + + this.completerExtensions = replFeatures.stream() + .map(LegendREPLExtensionFeature::getCompleterExtensions) + .flatMap(List::stream) + .collect(Collectors.toCollection(Lists.mutable::empty)); } @Override @@ -219,9 +240,9 @@ public Stream getLegendReferences(SectionState sectionState) pureModel.getContext() ); } - catch (Exception ignore) + catch (Exception e) { - // ignore for now... + LOGGER.warn("Failed to compute references", e); } return Stream.empty(); } @@ -273,7 +294,25 @@ private Iterable executeCell(SectionState secti private MutableList executePlan(SectionState section, Pair planContext, Map inputParameters) { MutableList results = Lists.mutable.empty(); - FunctionExecutionSupport.executePlan(section.getDocumentState().getGlobalState(), this.pureGrammarExtension, section.getDocumentState().getDocumentId(), section.getSectionNumber(), planContext.getOne(), planContext.getTwo(), "notebook_cell", inputParameters, results); + Result result = FunctionExecutionSupport.executePlan(planContext.getOne(), planContext.getTwo(), inputParameters, this.pureGrammarExtension); + + Optional extension = this.replExtensions + .stream() + .filter(x -> x.supports(result)) + .findAny(); + + String docId = section.getDocumentState().getDocumentId(); + int secNum = section.getSectionNumber(); + + if (extension.isPresent()) + { + results.add(FunctionExecutionSupport.FunctionLegendExecutionResult.newResult("notebook_cell", LegendExecutionResult.Type.SUCCESS, extension.get().print(result), null, docId, secNum, inputParameters, "text")); + } + else + { + FunctionExecutionSupport.collectResults(this.pureGrammarExtension, "notebook_cell", result, docId, secNum, inputParameters, SerializationFormat.DEFAULT, results::add); + } + return results; } @@ -311,7 +350,7 @@ public Iterable getCompletions(SectionState section, String functionExpression = section.getSection().getInterval(section.getSection().getStartLine(), 0, location.getLine(), column).trim(); functionExpression = functionExpression.replace("\n", "").replace("\r", ""); PureModel pureModel = this.pureGrammarExtension.getCompileResult(section).getPureModel(); - CompletionResult completionResult = new Completer(pureModel, Lists.mutable.with(new RelationalCompleterExtension())).complete(functionExpression); + CompletionResult completionResult = new Completer(pureModel, this.completerExtensions).complete(functionExpression); return completionResult.getCompletion().collect(c -> new LegendCompletion(c.getDisplay(), c.getCompletion())); } catch (Exception e) diff --git a/legend-engine-ide-lsp-default-extensions/src/test/java/org/finos/legend/engine/ide/lsp/extension/notebook/TestPureBookLSPGrammarExtension.java b/legend-engine-ide-lsp-default-extensions/src/test/java/org/finos/legend/engine/ide/lsp/extension/notebook/TestPureBookLSPGrammarExtension.java index deb850ad..5609fc54 100644 --- a/legend-engine-ide-lsp-default-extensions/src/test/java/org/finos/legend/engine/ide/lsp/extension/notebook/TestPureBookLSPGrammarExtension.java +++ b/legend-engine-ide-lsp-default-extensions/src/test/java/org/finos/legend/engine/ide/lsp/extension/notebook/TestPureBookLSPGrammarExtension.java @@ -158,6 +158,72 @@ void executeCell() ); } + @Test + void relationRendering() + { + SectionState notebook = stateForTestFactory.newPureBookSectionState("notebook.purebook", "#>{test::h2Store.personTable}#->select()->from(test::h2Runtime)"); + GlobalState gs = notebook.getDocumentState().getGlobalState(); + stateForTestFactory.newSectionState(gs, "database.pure", + "###Relational\n" + + "Database test::h2Store\n" + + "(\n" + + " Table personTable\n" + + " (\n" + + " fullName VARCHAR(100),\n" + + " firmName VARCHAR(100),\n" + + " addressName VARCHAR(100)\n" + + " )\n" + + " Table anotherPersonTable\n" + + " (\n" + + " fullName VARCHAR(100),\n" + + " firmName VARCHAR(100),\n" + + " addressName VARCHAR(100)\n" + + " )\n" + + ")"); + + stateForTestFactory.newSectionState(gs, "connection.pure", + "###Connection\n" + + "RelationalDatabaseConnection test::h2Conn\n" + + "{\n" + + " store: test::h2Store; \n" + + " type: H2;\n" + + " specification: LocalH2\n" + + " {\n" + + " testDataSetupCSV: 'default\\npersonTable\\nfullName,firmName,addressName\\nP1,F1,A1\\nP2,F2,A2\\nP3,,\\nP4,,A3\\nP5,F1,A1\\n---';\n" + + " };\n" + + " auth: DefaultH2;\n" + + "}"); + + stateForTestFactory.newSectionState(gs, "runtime.pure", + "###Runtime\n" + + "Runtime test::h2Runtime\n" + + "{\n" + + " mappings: [];\n" + + " connectionStores:\n" + + " [\n" + + " test::h2Conn: [ test::h2Store ]\n" + + " ];\n" + + "}"); + + Assertions.assertEquals( + List.of(FunctionExecutionSupport.FunctionLegendExecutionResult.newResult("notebook_cell", LegendExecutionResult.Type.SUCCESS, + "+--------------+--------------+--------------+\n" + + "| fullName | firmName | addressName |\n" + + "| VARCHAR(100) | VARCHAR(100) | VARCHAR(100) |\n" + + "+--------------+--------------+--------------+\n" + + "| P1 | F1 | A1 |\n" + + "| P2 | F2 | A2 |\n" + + "| P3 | | |\n" + + "| P4 | | A3 |\n" + + "| P5 | F1 | A1 |\n" + + "+--------------+--------------+--------------+\n" + + "5 rows -- 3 columns", null, notebook.getDocumentState().getDocumentId(), 0, Map.of())), + this.extension.execute(notebook, "notebook", "executeCell", Map.of()) + ); + + + } + @Test void completions() { diff --git a/legend-engine-ide-lsp-extension-api/src/main/java/org/finos/legend/engine/ide/lsp/extension/execution/LegendExecutionResult.java b/legend-engine-ide-lsp-extension-api/src/main/java/org/finos/legend/engine/ide/lsp/extension/execution/LegendExecutionResult.java index e0e5005e..e32b760d 100644 --- a/legend-engine-ide-lsp-extension-api/src/main/java/org/finos/legend/engine/ide/lsp/extension/execution/LegendExecutionResult.java +++ b/legend-engine-ide-lsp-extension-api/src/main/java/org/finos/legend/engine/ide/lsp/extension/execution/LegendExecutionResult.java @@ -29,10 +29,11 @@ public class LegendExecutionResult private final List ids; private final Type type; private final String message; + private final String messageType; private final String logMessage; private final TextLocation location; - protected LegendExecutionResult(List ids, Type type, String message, String logMessage, TextLocation location) + protected LegendExecutionResult(List ids, Type type, String message, String logMessage, TextLocation location, String messageType) { Objects.requireNonNull(ids, "ids may not be null").forEach(id -> Objects.requireNonNull(id, "id may not be null")); if (ids.isEmpty()) @@ -42,6 +43,7 @@ protected LegendExecutionResult(List ids, Type type, String message, Str this.ids = ids; this.type = Objects.requireNonNull(type, "type is required"); this.message = Objects.requireNonNull(message, "message is required"); + this.messageType = messageType; this.logMessage = logMessage; this.location = location; } @@ -57,6 +59,11 @@ public TextLocation getLocation() return this.location; } + public String getMessageType() + { + return messageType; + } + public static LegendExecutionResult errorResult(Throwable t, String message, String entityPath, TextLocation location) { StringWriter writer = new StringWriter(); @@ -182,7 +189,7 @@ public String toString() */ public static LegendExecutionResult newResult(List ids, Type type, String message, String logMessage, TextLocation location) { - return new LegendExecutionResult(ids, type, message, logMessage, location); + return new LegendExecutionResult(ids, type, message, logMessage, location, null); } /** diff --git a/pom.xml b/pom.xml index 8a79de59..05cbccc5 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ - 4.63.1 + 4.64.1 0.177.0 1.4.14