Skip to content

Commit

Permalink
Merge branch 'develop' into MAT-7481_UpdateConfigValues
Browse files Browse the repository at this point in the history
  • Loading branch information
gregory-akins authored Jul 30, 2024
2 parents 57e8c89 + 942403f commit eaf2166
Show file tree
Hide file tree
Showing 13 changed files with 251 additions and 46 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@
<dependency>
<groupId>gov.cms.madie</groupId>
<artifactId>madie-java-models</artifactId>
<version>0.6.30-SNAPSHOT</version>
<version>0.6.42-SNAPSHOT</version>
<exclusions>
<exclusion>
<artifactId>jackson-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import gov.cms.madie.models.dto.TranslatedLibrary;
import gov.cms.madie.models.measure.Measure;
import gov.cms.mat.cql_elm_translation.dto.CqlBuilderLookup;
import gov.cms.mat.cql_elm_translation.dto.CqlLookupRequest;
import gov.cms.mat.cql_elm_translation.dto.CqlLookups;
import gov.cms.mat.cql_elm_translation.dto.SourceDataCriteria;
Expand Down Expand Up @@ -103,4 +104,14 @@ public ResponseEntity<CqlLookups> getCqlLookups(
cqlParsingService.getCqlLookups(
lookupRequest.getCql(), lookupRequest.getMeasureExpressions(), accessToken));
}

@PutMapping(
value = "/cql-builder-lookups",
produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<CqlBuilderLookup> getCqlBuilderLookups(
@RequestBody String cql, @RequestHeader("Authorization") String accessToken) {
log.info("Preparing CqlBuilder Lookups");
return ResponseEntity.ok(cqlParsingService.getCqlBuilderLookups(cql, accessToken));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package gov.cms.mat.cql_elm_translation.dto;

import lombok.Builder;
import lombok.Data;

import java.util.Set;

@Data
@Builder
public class CqlBuilderLookup {
private Set<Lookup> parameters;
private Set<Lookup> definitions;
private Set<Lookup> functions;
private Set<Lookup> fluentFunctions;

@Builder
public static class Lookup {
private String name;
private String libraryName;
private String libraryAlias;
private String logic;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package gov.cms.mat.cql_elm_translation.service;

import gov.cms.mat.cql_elm_translation.dto.CqlBuilderLookup;
import gov.cms.mat.cql_elm_translation.dto.CqlLookups;
import gov.cms.mat.cql_elm_translation.dto.ElementLookup;
import gov.cms.mat.cql_elm_translation.utils.cql.CQLTools;
Expand Down Expand Up @@ -45,13 +46,13 @@ public Set<CQLDefinition> getAllDefinitions(String cql, String accessToken) {
}

/**
* Parses the CQL and generates cql artifacts(including for the CQL of the included Libraries).
* refer CQL artifacts- gov.cms.mat.cql_elm_translation.dto.CQLLookups
* Parses the CQL and generates only used cql artifacts(including for the CQL of the included
* Libraries). refer CQL artifacts- gov.cms.mat.cql_elm_translation.dto.CQLLookups
*
* @param cql- measure cql
* @param measureExpressions- set of cql definitions used in measure groups, SDEs & RAVs
* @param accessToken Requesting User's Okta Bearer token
* @return CQLLookups
* @return CQLLookups -> building blocks for HQMF and Human Readable generation
*/
public CqlLookups getCqlLookups(String cql, Set<String> measureExpressions, String accessToken) {
if (StringUtils.isBlank(cql) || CollectionUtils.isEmpty(measureExpressions)) {
Expand Down Expand Up @@ -104,6 +105,78 @@ public CqlLookups getCqlLookups(String cql, Set<String> measureExpressions, Stri
.build();
}

/**
* Parses the CQL and collect all CQL building blocks irrespective of used or unused(including for
* the CQL of the included Libraries)
*
* @param cql- measure cql
* @param accessToken Requesting User's Okta Bearer token
* @return CqlBuilderLookup -> building blocks for CQL Definition UI builder
*/
public CqlBuilderLookup getCqlBuilderLookups(String cql, String accessToken) {
if (StringUtils.isBlank(cql)) {
return null;
}

CQLTools cqlTools = parseCql(cql, accessToken, cqlLibraryService, null);
// all parameters
Set<CqlBuilderLookup.Lookup> parameters =
cqlTools.getAllParameters().stream().map(this::buildParameterLookup).collect(toSet());

// get all CQLDefinitions including functions
Set<CQLDefinition> allCqlDefinitions = buildCqlDefinitions(cqlTools);
// prepare lookups for definitions, functions and fluent functions from CQLDefinitions
Set<CqlBuilderLookup.Lookup> definitions = new HashSet<>();
Set<CqlBuilderLookup.Lookup> functions = new HashSet<>();
Set<CqlBuilderLookup.Lookup> fluentFunctions = new HashSet<>();
for (CQLDefinition cqlDefinition : allCqlDefinitions) {
CqlBuilderLookup.Lookup lookup =
buildCqlBuilderLookup(
cqlDefinition.getName(),
cqlDefinition.getLogic(),
cqlDefinition.getParentLibrary(),
cqlDefinition.getLibraryDisplayName());
if (cqlDefinition.isFunction()) {
if (StringUtils.startsWith(cqlDefinition.getLogic(), "define fluent function")) {
fluentFunctions.add(lookup);
} else {
functions.add(lookup);
}
} else {
definitions.add(lookup);
}
}
return CqlBuilderLookup.builder()
.parameters(parameters)
.definitions(definitions)
.functions(functions)
.fluentFunctions(fluentFunctions)
.build();
}

private CqlBuilderLookup.Lookup buildParameterLookup(CQLParameter parameter) {
String[] parts = parameter.getParameterName().split("\\|");
String name = parameter.getParameterName();
String libraryName = null;
String libraryAlias = null;
if (parts.length == 3) {
libraryName = parts[0].split("-")[0];
libraryAlias = parts[1];
name = parts[2];
}
return buildCqlBuilderLookup(name, parameter.getParameterLogic(), libraryName, libraryAlias);
}

private CqlBuilderLookup.Lookup buildCqlBuilderLookup(
String name, String logic, String libraryName, String libraryAlias) {
return CqlBuilderLookup.Lookup.builder()
.name(name)
.logic(logic)
.libraryName(libraryName)
.libraryAlias(libraryAlias)
.build();
}

/**
* Maps the references between CQL Definitions. In other words, which CQL Definitions and
* Functions are called by which other CQL Definition.
Expand Down Expand Up @@ -328,13 +401,7 @@ private CQLDefinition buildCqlDefinition(DefinitionContent definitionContent) {
definition.setLibraryVersion(libraryParts[1]);
}
}
// TODO could use a stronger comparator for determining if node is Definition or Function
definition.setFunction(definition.getDefinitionLogic().startsWith("define function"));
definition.setFunction(definitionContent.isFunction());
return definition;
}

public Map<String, Set<String>> getUsedFunctions(String cql, String accessToken) {
CQLTools cqlTools = parseCql(cql, accessToken, cqlLibraryService, null);
return cqlTools.getUsedFunctions();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ public class DataCriteriaService extends CqlTooling {

private final CqlLibraryService cqlLibraryService;

public DataCriteria parseDataCriteriaFromCql(String cql, String accessToken) {
return parseCql(cql, accessToken, cqlLibraryService, null).getDataCriteria();
}

public Set<SourceDataCriteria> getRelevantElements(Measure measure, String accessToken) {
if (StringUtils.isBlank(measure.getCql())) {
log.info("Data criteria not found as cql is blank");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ public class CQLTools {
private Set<String> usedCodeSystems = new HashSet<>();
private DataCriteria dataCriteria = new DataCriteria();
private Set<DefinitionContent> definitionContents = new HashSet<>();
private Set<CQLParameter> allParameters = new HashSet<>();
private Map<String, Set<String>> callstack = new HashMap<>();
private UsingProperties usingProperties;

Expand Down Expand Up @@ -140,6 +141,7 @@ public void generate() throws IOException {
walker.walk(listener, tree);

definitionContents.addAll(listener.getDefinitionContents());
allParameters.addAll(listener.getParameters());
callstack = graph.getAdjacencyList();

Set<CQLIncludeLibrary> librariesSet = new HashSet<>(listener.getLibraries());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,20 @@ public void enterCodesystemDefinition(cqlParser.CodesystemDefinitionContext ctx)
CQLCodeSystem codeSystem = new CQLCodeSystem();
codeSystem.setId(csDef.getId());
codeSystem.setOID(csDef.getId());
codeSystem.setCodeSystemVersion(getParsedVersion(csDef.getVersion()));
codeSystem.setCodeSystemName(csDef.getName());

codeSystemMap.putIfAbsent(identifier, codeSystem);
}
}

private String getParsedVersion(String version) {
if (version != null && version.startsWith("urn:hl7:version:")) {
return version.substring("urn:hl7:version:".length());
}
return version;
}

@Override
public void enterQualifiedFunction(QualifiedFunctionContext ctx) {
if (ctx.identifierOrFunctionIdentifier() != null
Expand Down Expand Up @@ -201,6 +209,14 @@ public void enterQualifiedIdentifierExpression(QualifiedIdentifierExpressionCont
}
}

@Override
public void enterLocalIdentifier(cqlParser.LocalIdentifierContext ctx) {
String identifier = parseString(ctx.identifier().getText());
if (shouldResolve(identifier)) {
resolve(identifier, getCurrentLibraryContext());
}
}

@Override
public void enterReferentialIdentifier(ReferentialIdentifierContext ctx) {
String identifier = parseString(ctx.getText());
Expand Down Expand Up @@ -275,6 +291,7 @@ public void enterFunctionDefinition(@NotNull cqlParser.FunctionDefinitionContext
.name(currentContext)
.content(content)
.functionArguments(functionArguments)
.function(true)
.build());
graph.addNode(currentContext);
}
Expand Down Expand Up @@ -335,6 +352,9 @@ public void enterParameterDefinition(@NotNull cqlParser.ParameterDefinitionConte
String identifier = parseString(ctx.identifier().getText());
this.currentContext = libraryIdentifier + identifier;
graph.addNode(currentContext);
if (shouldResolve(identifier)) {
resolve(identifier, getCurrentLibraryContext());
}
}

@Override
Expand Down Expand Up @@ -555,18 +575,29 @@ private Element resolve(String identifier, CompiledLibrary library) {
currentContext, def.getPath() + "-" + def.getVersion() + "|" + def.getLocalIdentifier());
libraryAccessor = def;
try {
parseChildLibraries(def);
libraries.add(
CQLIncludeLibrary.builder()
.cqlLibraryName(def.getPath())
.aliasName(def.getLocalIdentifier())
.version(def.getVersion())
// TODO: should be taken from librarySetId
.id(def.getTrackerId().toString())
.setId(def.getTrackerId().toString())
.build());
var parsedLibrary =
libraries.stream()
.filter(
l ->
l.getCqlLibraryName().equalsIgnoreCase(def.getPath())
&& l.getVersion().equalsIgnoreCase(def.getVersion()))
.findFirst();
if (parsedLibrary.isEmpty()) {
parseChildLibraries(def);
libraries.add(
CQLIncludeLibrary.builder()
.cqlLibraryName(def.getPath())
.aliasName(def.getLocalIdentifier())
.version(def.getVersion())
// TODO: should be taken from librarySetId
.id(def.getTrackerId().toString())
.setId(def.getTrackerId().toString())
.build());
}
} catch (IOException e) {
e.printStackTrace();
log.error(
"IOException while parsing child library [{}] " + e.getMessage(),
def.getPath() + "-" + def.getVersion());
}
} else if (element instanceof CodeDef codeDef) {
codes.add(formattedIdentifier);
Expand All @@ -577,6 +608,8 @@ private Element resolve(String identifier, CompiledLibrary library) {
.codeName(codeDef.getDisplay())
.codeSystemName(codeDef.getCodeSystem().getName())
.codeSystemOID(cqlCodeSystem == null ? null : cqlCodeSystem.getOID())
.codeSystemVersion(
cqlCodeSystem == null ? null : cqlCodeSystem.getCodeSystemVersion())
.codeIdentifier(formattedIdentifier)
.build();
declaredCodes.add(declaredCode);
Expand Down Expand Up @@ -633,9 +666,6 @@ private void parseChildLibraries(IncludeDef def) throws IOException {
cqlLexer lexer = new cqlLexer(CharStreams.fromStream(stream));
CommonTokenStream tokens = new CommonTokenStream(lexer);
cqlParser parser = new cqlParser(tokens);

// CompiledLibrary childLibrary = this.translatedLibraryMap.get(def.getPath() + "-" +
// def.getVersion());
CompiledLibrary childLibrary = this.translatedLibraryMap.get(def.getPath());
Cql2ElmListener listener =
new Cql2ElmListener(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import java.util.Queue;
import java.util.Set;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class CQLGraph {

private final Map<String, Set<String>> graph = new HashMap<>();
Expand Down Expand Up @@ -49,20 +52,32 @@ public boolean isPath(String source, String destination) {

while (!queue.isEmpty()) {
String currentNode = queue.remove();
List<String> adjacentVertices = new ArrayList<>(this.graph.get(currentNode));

for (String adjacentNode : adjacentVertices) {
// we've found the destination node that we were looking for, so return true.
if (adjacentNode.equals(destination)) {
return true;
}

// if it's not the destination node and the node hasn't been visited yet, add it to the
// queue to be visited.
if (!visited.contains(adjacentNode)) {
visited.add(adjacentNode);
queue.add(adjacentNode);
if (this.graph.get(currentNode) != null) {
List<String> adjacentVertices = new ArrayList<>(this.graph.get(currentNode));

for (String adjacentNode : adjacentVertices) {
// we've found the destination node that we were looking for, so return true.
if (adjacentNode.equals(destination)) {
return true;
}

// if it's not the destination node and the node hasn't been visited yet, add it to the
// queue to be visited.
if (!visited.contains(adjacentNode)) {
visited.add(adjacentNode);
queue.add(adjacentNode);
}
}
} else {
log.error(
"source = "
+ source
+ " destination = "
+ destination
+ " this.graph.get currentNode: "
+ currentNode
+ " is null");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ public class DefinitionContent {
private String name;
private String content;
private List<CQLFunctionArgument> functionArguments;
private boolean function;
}
7 changes: 3 additions & 4 deletions src/main/resources/application.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
server:
port: 8083
servlet:
context-path: /api/fhir

context-path: /api/qdm
spring:
profiles:
active: local
Expand All @@ -29,8 +28,8 @@ madie:
cql:
uri: /cql-libraries/cql
translatorVersion:
currentVersion: ${CURRENT_TRANSLATOR_VERSION:3.3.2}
mostRecentVersion: ${MOST_RECENT_TRANSLATOR_VERSION:3.3.2}
currentVersion: ${CURRENT_TRANSLATOR_VERSION:3.11.0}
mostRecentVersion: ${MOST_RECENT_TRANSLATOR_VERSION:3.11.0}

springdoc:
swagger-ui:
Expand Down
Loading

0 comments on commit eaf2166

Please sign in to comment.