diff --git a/ls/server/src/main/java/org/opencds/cqf/cql/ls/server/command/CqlCommand.java b/ls/server/src/main/java/org/opencds/cqf/cql/ls/server/command/CqlCommand.java index b14077f..c1531c5 100644 --- a/ls/server/src/main/java/org/opencds/cqf/cql/ls/server/command/CqlCommand.java +++ b/ls/server/src/main/java/org/opencds/cqf/cql/ls/server/command/CqlCommand.java @@ -2,10 +2,10 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.Callable; import org.apache.commons.lang3.tuple.Pair; import org.cqframework.cql.cql2elm.CqlTranslatorOptions; @@ -35,6 +35,7 @@ import org.opencds.cqf.fhir.cql.engine.terminology.TerminologySettings.VALUESET_MEMBERSHIP_MODE; import org.opencds.cqf.fhir.cql.engine.terminology.TerminologySettings.VALUESET_PRE_EXPANSION_MODE; import org.opencds.cqf.fhir.utility.repository.ProxyRepository; +import org.opencds.cqf.fhir.utility.repository.RestRepository; import org.opencds.cqf.fhir.utility.repository.ig.IgRepository; import org.slf4j.LoggerFactory; import picocli.CommandLine.ArgGroup; @@ -95,7 +96,7 @@ static class LibraryParameter { public List parameters; @Option(names = {"-e", "--expression"}) - public String[] expression; + public Set expression; @ArgGroup(multiplicity = "0..1", exclusive = false) public ContextParameter context; @@ -125,10 +126,9 @@ static class ParameterParameter { } } - private static class Logger implements ILoggingService { - - private final org.slf4j.Logger log = LoggerFactory.getLogger(Logger.class); + private static final org.slf4j.Logger log = LoggerFactory.getLogger(Logger.class); + private static class Logger implements ILoggingService { @Override public void logMessage(String s) { log.warn(s); @@ -198,15 +198,9 @@ public Integer call() throws Exception { for (LibraryParameter library : libraries) { var libraryPath = Paths.get(Uris.parseOrNull(library.libraryUrl)); - var modelPath = library.model != null - ? Paths.get(Uris.parseOrNull(library.model.modelUrl)) - : null; + var modelUrl = library.model != null ? library.model.modelUrl : null; - var terminologyPath = library.terminologyUrl != null - ? Paths.get(Uris.parseOrNull(library.terminologyUrl)) - : null; - - var repository = createRepository(fhirContext, terminologyPath, modelPath); + var repository = createRepository(fhirContext, library.terminologyUrl, modelUrl); var engine = Engines.forRepositoryAndSettings( evaluationSettings, repository, null, new NpmProcessor(igContext), true); @@ -226,7 +220,7 @@ public Integer call() throws Exception { contextParameter = Pair.of(library.context.contextName, library.context.contextValue); } - EvaluationResult result = engine.evaluate(identifier, contextParameter); + EvaluationResult result = engine.evaluate(identifier, library.expression, contextParameter); writeResult(result); } @@ -234,22 +228,26 @@ public Integer call() throws Exception { return 0; } - private Repository createRepository(FhirContext fhirContext, Path terminologyPath, Path modelPath) { + private Repository createRepository(FhirContext fhirContext, String terminologyUrl, String modelUrl) { Repository data = null; Repository terminology = null; - if (terminologyPath == null && modelPath == null) { + if (terminologyUrl == null && modelUrl == null) { return new NoOpRepository(fhirContext); } - if (modelPath != null) { - data = new IgRepository(fhirContext, modelPath); + if (modelUrl == null) { + data = new NoOpRepository(fhirContext); + } else if (modelUrl.startsWith("file:///")) { + data = new IgRepository(fhirContext, Paths.get(Uris.parseOrNull(modelUrl))); + } else if (modelUrl.startsWith("http://") || modelUrl.startsWith(("https://"))) { + data = new RestRepository(fhirContext.newRestfulGenericClient(modelUrl)); } else { data = new NoOpRepository(fhirContext); } - if (terminologyPath != null) { - terminology = new IgRepository(fhirContext, terminologyPath); + if (terminologyUrl != null) { + terminology = new IgRepository(fhirContext, Paths.get(Uris.parseOrNull(terminologyUrl))); } else { terminology = new NoOpRepository(fhirContext); } diff --git a/ls/server/src/test/java/org/opencds/cqf/cql/ls/server/command/DebugCqlCommandContributionTest.java b/ls/server/src/test/java/org/opencds/cqf/cql/ls/server/command/DebugCqlCommandContributionTest.java new file mode 100644 index 0000000..d4cb27e --- /dev/null +++ b/ls/server/src/test/java/org/opencds/cqf/cql/ls/server/command/DebugCqlCommandContributionTest.java @@ -0,0 +1,156 @@ +package org.opencds.cqf.cql.ls.server.command; + +import static org.junit.jupiter.api.Assertions.*; + +import com.google.gson.JsonParser; +import java.io.File; +import java.net.URI; +import java.util.Arrays; +import java.util.stream.Collectors; +import org.apache.commons.lang3.SystemUtils; +import org.eclipse.lsp4j.ExecuteCommandParams; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.opencds.cqf.cql.ls.core.ContentService; +import org.opencds.cqf.cql.ls.server.manager.IgContextManager; +import org.opencds.cqf.cql.ls.server.service.TestContentService; + +class DebugCqlCommandContributionTest { + + private static final String FILE_UNC_PREFIX = "file:///"; + + private static DebugCqlCommandContribution contribution; + + @BeforeAll + static void beforeAll() { + ContentService cs = new TestContentService(); + contribution = new DebugCqlCommandContribution(new IgContextManager((cs))); + } + + @Test + void getCommands() { + assertEquals(1, contribution.getCommands().size()); + assertEquals( + "org.opencds.cqf.cql.ls.plugin.debug.startDebugSession", + contribution.getCommands().toArray()[0]); + } + + @Test + void withOnlyLibrary() { + ExecuteCommandParams params = new ExecuteCommandParams(); + + String libraryPath = normalizePath( + "file://" + System.getProperty("user.dir") + "/src/test/resources/org/opencds/cqf/cql/ls/server/"); + + params.setCommand("org.opencds.cqf.cql.ls.plugin.debug.startDebugSession"); + params.setArguments(Arrays.asList("cql", "-fv=R4", "-m=FHIR", "-ln=One", "-lu=" + libraryPath).stream() + .map(str -> "\"" + str + "\"") + .map(JsonParser::parseString) + .collect(Collectors.toList())); + Object result = contribution.executeCommand(params).join(); + assertInstanceOf(String.class, result); + assertTrue(((String) result).trim().endsWith("One=1")); + } + + @Test + void withTerminology() { + ExecuteCommandParams params = new ExecuteCommandParams(); + + String libraryPath = normalizePath( + "file://" + System.getProperty("user.dir") + "/src/test/resources/org/opencds/cqf/cql/ls/server/"); + + params.setCommand("org.opencds.cqf.cql.ls.plugin.debug.startDebugSession"); + params.setArguments( + Arrays.asList("cql", "-fv=R4", "-m=FHIR", "-ln=One", "-lu=" + libraryPath, "-t=" + libraryPath).stream() + .map(str -> "\"" + str + "\"") + .map(JsonParser::parseString) + .collect(Collectors.toList())); + Object result = contribution.executeCommand(params).join(); + assertInstanceOf(String.class, result); + assertTrue(((String) result).trim().endsWith("One=1")); + } + + @Test + void withFileModel() { + ExecuteCommandParams params = new ExecuteCommandParams(); + + String modelPath = normalizePath( + "file://" + System.getProperty("user.dir") + "/src/test/resources/org/opencds/cqf/cql/ls/server/"); + String libraryPath = normalizePath( + "file://" + System.getProperty("user.dir") + "/src/test/resources/org/opencds/cqf/cql/ls/server/"); + + params.setCommand("org.opencds.cqf.cql.ls.plugin.debug.startDebugSession"); + params.setArguments(Arrays.asList( + "cql", + "-fv=R4", + "-m=FHIR", + "-mu=" + modelPath, + "-ln=One", + "-lu=" + libraryPath, + "-t=" + libraryPath) + .stream() + .map(str -> "\"" + str + "\"") + .map(JsonParser::parseString) + .collect(Collectors.toList())); + Object result = contribution.executeCommand(params).join(); + assertInstanceOf(String.class, result); + assertTrue(((String) result).trim().endsWith("One=1")); + } + + // @Test + // void withRemoteModel() { + // ExecuteCommandParams params = new ExecuteCommandParams(); + // + // String modelPath = "http://localhost:8000"; + // String libraryPath = normalizePath("file://" + System.getProperty("user.dir") + + // "/src/test/resources/org/opencds/cqf/cql/ls/server/"); + // + // params.setCommand("org.opencds.cqf.cql.ls.plugin.debug.startDebugSession"); + // params.setArguments(Arrays.asList( + // "cql", + // "-fv=R4", + // "-m=FHIR", + // "-mu=" + modelPath, + // "-ln=One", + // "-lu=" + libraryPath, + // "-t=" + libraryPath + // ).stream().map(str -> "\"" + str + "\"").map(JsonParser::parseString).collect(Collectors.toList())); + // Object result = contribution.executeCommand(params).join(); + // assertInstanceOf(String.class, result); + // assertTrue(((String) result).trim().endsWith("One=1")); + // } + + @Test + void withRootDir() { + ExecuteCommandParams params = new ExecuteCommandParams(); + + String libraryPath = normalizePath( + "file://" + System.getProperty("user.dir") + "/src/test/resources/org/opencds/cqf/cql/ls/server/"); + + params.setCommand("org.opencds.cqf.cql.ls.plugin.debug.startDebugSession"); + params.setArguments( + Arrays.asList("cql", "-fv=R4", "-m=FHIR", "--root-dir=" + libraryPath, "-ln=One", "-lu=" + libraryPath) + .stream() + .map(str -> "\"" + str + "\"") + .map(JsonParser::parseString) + .collect(Collectors.toList())); + Object result = contribution.executeCommand(params).join(); + assertInstanceOf(String.class, result); + assertTrue(((String) result).trim().endsWith("One=1")); + } + + private static String normalizePath(String path) { + if (SystemUtils.IS_OS_WINDOWS && path.startsWith(FILE_UNC_PREFIX)) { + String wPath = path; + try { + URI uri = new URI(path); + wPath = new File(uri.getSchemeSpecificPart()).toURI().getRawPath(); + } catch (Exception e) { + } + + return wPath.replace('\\', '/'); + } + + return path.replace('\\', '/'); + } +} diff --git a/ls/server/src/test/resources/org/opencds/cqf/cql/ls/server/One.xml b/ls/server/src/test/resources/org/opencds/cqf/cql/ls/server/One.xml index c5fe2a4..7bf6ecd 100644 --- a/ls/server/src/test/resources/org/opencds/cqf/cql/ls/server/One.xml +++ b/ls/server/src/test/resources/org/opencds/cqf/cql/ls/server/One.xml @@ -1,12 +1,12 @@ - + library One - + @@ -22,4 +22,4 @@ - \ No newline at end of file + \ No newline at end of file