Skip to content

Commit

Permalink
#684: Fixed an issue with data requirements not being reported correc…
Browse files Browse the repository at this point in the history
…tly for dependencies
  • Loading branch information
brynrhodes committed Nov 28, 2021
1 parent db96b2e commit 9ef9f54
Show file tree
Hide file tree
Showing 12 changed files with 1,015 additions and 590 deletions.
10 changes: 10 additions & 0 deletions Src/cql-lm/schema/elm/expression.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,16 @@
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="ParameterTypeSpecifier">
<xs:annotation>
<xs:documentation>A type which is generic class parameter such as T in MyGeneric&lt;T extends SomeType&gt;.</xs:documentation>
</xs:annotation>
<xs:complexContent>
<xs:extension base="TypeSpecifier">
<xs:attribute name="parameterName" type="xs:string" use="required"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="Expression" abstract="true">
<xs:annotation>
<xs:documentation>The Expression type defines the abstract base type for all expressions used in the ELM expression language.</xs:documentation>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.cqframework.cql.cql2elm;

import org.cqframework.cql.cql2elm.CqlTranslator;
import org.cqframework.cql.cql2elm.model.*;
import org.cqframework.cql.cql2elm.model.invocation.*;
import org.cqframework.cql.elm.tracking.TrackBack;
Expand All @@ -11,18 +10,16 @@
import org.hl7.cql_annotations.r1.ErrorSeverity;
import org.hl7.cql_annotations.r1.ErrorType;
import org.hl7.elm.r1.*;
import org.hl7.elm_modelinfo.r1.ModelInfo;

import javax.xml.namespace.QName;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;
import java.util.List;

/**
* Created by Bryn on 12/29/2016.
*/
public class LibraryBuilder {
public class LibraryBuilder implements ModelResolver {
public static enum SignatureLevel {
/*
Indicates signatures will never be included in operator invocations
Expand Down Expand Up @@ -61,6 +58,7 @@ public LibraryBuilder(NamespaceInfo namespaceInfo, ModelManager modelManager, Li
this.namespaceInfo = namespaceInfo; // Note: allowed to be null, implies global namespace
this.modelManager = modelManager;
this.libraryManager = libraryManager;
this.typeBuilder = new TypeBuilder(of, this);

this.library = of.createLibrary()
.withSchemaIdentifier(of.createVersionedIdentifier()
Expand Down Expand Up @@ -131,6 +129,7 @@ public ConversionMap getConversionMap() {
private UcumService ucumService = null;
private CqlTranslatorOptions options;
private CqlToElmInfo cqlToElmInfo = null;
private TypeBuilder typeBuilder = null;

public void enableListTraversal() {
listTraversal = true;
Expand Down Expand Up @@ -452,7 +451,7 @@ public Model getModel(UsingDef usingDef) {
}

private void loadSystemLibrary() {
TranslatedLibrary systemLibrary = SystemLibraryHelper.load(getSystemModel());
TranslatedLibrary systemLibrary = SystemLibraryHelper.load(getSystemModel(), typeBuilder);
libraries.put(systemLibrary.getIdentifier().getId(), systemLibrary);
loadConversionMap(systemLibrary);
}
Expand Down Expand Up @@ -1839,91 +1838,15 @@ public Interval createInterval(Expression low, boolean lowClosed, Expression hig
}

public QName dataTypeToQName(DataType type) {
if (type instanceof NamedType) {
NamedType namedType = (NamedType)type;
ModelInfo modelInfo = getModel(namedType.getNamespace()).getModelInfo();
return new QName(modelInfo.getTargetUrl() != null ? modelInfo.getTargetUrl() : modelInfo.getUrl(),
namedType.getTarget() != null ? namedType.getTarget() : namedType.getSimpleName());
}

// ERROR:
throw new IllegalArgumentException("A named type is required in this context.");
return typeBuilder.dataTypeToQName(type);
}

public Iterable<TypeSpecifier> dataTypesToTypeSpecifiers(Iterable<DataType> types) {
ArrayList<TypeSpecifier> result = new ArrayList<TypeSpecifier>();
for (DataType type : types) {
result.add(dataTypeToTypeSpecifier(type));
}
return result;
return typeBuilder.dataTypesToTypeSpecifiers(types);
}

public TypeSpecifier dataTypeToTypeSpecifier(DataType type) {
// Convert the given type into an ELM TypeSpecifier representation.
if (type instanceof NamedType) {
return (TypeSpecifier)of.createNamedTypeSpecifier().withName(dataTypeToQName(type)).withResultType(type);
}
else if (type instanceof ListType) {
return listTypeToTypeSpecifier((ListType)type);
}
else if (type instanceof IntervalType) {
return intervalTypeToTypeSpecifier((IntervalType)type);
}
else if (type instanceof TupleType) {
return tupleTypeToTypeSpecifier((TupleType)type);
}
else if (type instanceof ChoiceType) {
return choiceTypeToTypeSpecifier((ChoiceType)type);
}
else {
throw new IllegalArgumentException(String.format("Could not convert type %s to a type specifier.", type));
}
}

private TypeSpecifier listTypeToTypeSpecifier(ListType type) {
return (TypeSpecifier)of.createListTypeSpecifier()
.withElementType(dataTypeToTypeSpecifier(type.getElementType()))
.withResultType(type);
}

private TypeSpecifier intervalTypeToTypeSpecifier(IntervalType type) {
return (TypeSpecifier)of.createIntervalTypeSpecifier()
.withPointType(dataTypeToTypeSpecifier(type.getPointType()))
.withResultType(type);
}

private TypeSpecifier tupleTypeToTypeSpecifier(TupleType type) {
return (TypeSpecifier)of.createTupleTypeSpecifier()
.withElement(tupleTypeElementsToTupleElementDefinitions(type.getElements()))
.withResultType(type);
}

private TupleElementDefinition[] tupleTypeElementsToTupleElementDefinitions(Iterable<TupleTypeElement> elements) {
List<TupleElementDefinition> definitions = new ArrayList<>();

for (TupleTypeElement element : elements) {
definitions.add(of.createTupleElementDefinition()
.withName(element.getName())
.withElementType(dataTypeToTypeSpecifier(element.getType())));
}

return definitions.toArray(new TupleElementDefinition[definitions.size()]);
}

private TypeSpecifier choiceTypeToTypeSpecifier(ChoiceType type) {
return (TypeSpecifier)of.createChoiceTypeSpecifier()
.withChoice(choiceTypeTypesToTypeSpecifiers(type))
.withResultType(type);
}

private TypeSpecifier[] choiceTypeTypesToTypeSpecifiers(ChoiceType choiceType) {
List<TypeSpecifier> specifiers = new ArrayList<>();

for (DataType type : choiceType.getTypes()) {
specifiers.add(dataTypeToTypeSpecifier(type));
}

return specifiers.toArray(new TypeSpecifier[specifiers.size()]);
return typeBuilder.dataTypeToTypeSpecifier(type);
}

public DataType resolvePath(DataType sourceType, String path) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public class ModelManager {
private ModelInfoLoader modelInfoLoader;
private final Map<String, Model> models = new HashMap<>();
private final Set<String> loadingModels = new HashSet<>();
private final Map<String, Model> modelsByUri = new HashMap<>();

public ModelManager() {
namespaceManager = new NamespaceManager();
Expand Down Expand Up @@ -116,6 +117,7 @@ public Model resolveModel(VersionedIdentifier modelIdentifier) {
if (model == null) {
model = buildModel(modelIdentifier);
models.put(modelPath, model);
modelsByUri.put(model.getModelInfo().getUrl(), model);
}

if (modelIdentifier.getVersion() != null && !modelIdentifier.getVersion().equals(model.getModelInfo().getVersion())) {
Expand All @@ -125,4 +127,13 @@ public Model resolveModel(VersionedIdentifier modelIdentifier) {

return model;
}

public Model resolveModelByUri(String namespaceUri) {
Model model = modelsByUri.get(namespaceUri);
if (model == null) {
throw new IllegalArgumentException(String.format("Could not resolve model with namespace %s", namespaceUri));
}

return model;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.cqframework.cql.cql2elm;

import org.cqframework.cql.cql2elm.model.Model;

public interface ModelResolver {
Model getModel(String modelName);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package org.cqframework.cql.cql2elm;

import org.cqframework.cql.cql2elm.model.Model;
import org.hl7.cql.model.*;
import org.hl7.elm.r1.ObjectFactory;
import org.hl7.elm.r1.ParameterTypeSpecifier;
import org.hl7.elm.r1.TupleElementDefinition;
import org.hl7.elm.r1.TypeSpecifier;
import org.hl7.elm_modelinfo.r1.ModelInfo;

import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.List;

public class TypeBuilder {

private ObjectFactory of;
private ModelResolver mr;

public class InternalModelResolver implements ModelResolver {
private ModelManager modelManager;

public InternalModelResolver(ModelManager modelManager) {
this.modelManager = modelManager;
}

public Model getModel(String modelName) {
return this.modelManager.resolveModel(modelName);
}
}

public TypeBuilder(ObjectFactory of, ModelResolver mr) {
this.of = of;
this.mr = mr;
}

public TypeBuilder(ModelManager modelManager) {
this.of = new ObjectFactory();
this.mr = new InternalModelResolver(modelManager);
}

public QName dataTypeToQName(DataType type) {
if (type instanceof NamedType) {
NamedType namedType = (NamedType)type;
ModelInfo modelInfo = mr.getModel(namedType.getNamespace()).getModelInfo();
return new QName(modelInfo.getTargetUrl() != null ? modelInfo.getTargetUrl() : modelInfo.getUrl(),
namedType.getTarget() != null ? namedType.getTarget() : namedType.getSimpleName());
}

// ERROR:
throw new IllegalArgumentException("A named type is required in this context.");
}

public Iterable<TypeSpecifier> dataTypesToTypeSpecifiers(Iterable<DataType> types) {
ArrayList<TypeSpecifier> result = new ArrayList<TypeSpecifier>();
for (DataType type : types) {
result.add(dataTypeToTypeSpecifier(type));
}
return result;
}

public TypeSpecifier dataTypeToTypeSpecifier(DataType type) {
// Convert the given type into an ELM TypeSpecifier representation.
if (type instanceof NamedType) {
return (TypeSpecifier)of.createNamedTypeSpecifier().withName(dataTypeToQName(type)).withResultType(type);
}
else if (type instanceof ListType) {
return listTypeToTypeSpecifier((ListType)type);
}
else if (type instanceof IntervalType) {
return intervalTypeToTypeSpecifier((IntervalType)type);
}
else if (type instanceof TupleType) {
return tupleTypeToTypeSpecifier((TupleType)type);
}
else if (type instanceof ChoiceType) {
return choiceTypeToTypeSpecifier((ChoiceType)type);
}
else if (type instanceof TypeParameter) {
return typeParameterToTypeSpecifier((TypeParameter)type);
}
else {
throw new IllegalArgumentException(String.format("Could not convert type %s to a type specifier.", type));
}
}

private TypeSpecifier listTypeToTypeSpecifier(ListType type) {
return (TypeSpecifier)of.createListTypeSpecifier()
.withElementType(dataTypeToTypeSpecifier(type.getElementType()))
.withResultType(type);
}

private TypeSpecifier intervalTypeToTypeSpecifier(IntervalType type) {
return (TypeSpecifier)of.createIntervalTypeSpecifier()
.withPointType(dataTypeToTypeSpecifier(type.getPointType()))
.withResultType(type);
}

private TypeSpecifier tupleTypeToTypeSpecifier(TupleType type) {
return (TypeSpecifier)of.createTupleTypeSpecifier()
.withElement(tupleTypeElementsToTupleElementDefinitions(type.getElements()))
.withResultType(type);
}

private TupleElementDefinition[] tupleTypeElementsToTupleElementDefinitions(Iterable<TupleTypeElement> elements) {
List<TupleElementDefinition> definitions = new ArrayList<>();

for (TupleTypeElement element : elements) {
definitions.add(of.createTupleElementDefinition()
.withName(element.getName())
.withElementType(dataTypeToTypeSpecifier(element.getType())));
}

return definitions.toArray(new TupleElementDefinition[definitions.size()]);
}

private TypeSpecifier choiceTypeToTypeSpecifier(ChoiceType type) {
return (TypeSpecifier)of.createChoiceTypeSpecifier()
.withChoice(choiceTypeTypesToTypeSpecifiers(type))
.withResultType(type);
}

private TypeSpecifier[] choiceTypeTypesToTypeSpecifiers(ChoiceType choiceType) {
List<TypeSpecifier> specifiers = new ArrayList<>();

for (DataType type : choiceType.getTypes()) {
specifiers.add(dataTypeToTypeSpecifier(type));
}

return specifiers.toArray(new TypeSpecifier[specifiers.size()]);
}

private TypeSpecifier typeParameterToTypeSpecifier(TypeParameter type) {
return new ParameterTypeSpecifier().withParameterName(type.getIdentifier());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,17 @@ public static Operator fromFunctionDef(FunctionDef functionDef) {
for (OperandDef operand : functionDef.getOperand()) {
operandTypes.add(operand.getResultType());
}
return new Operator(functionDef.getName(), new Signature(operandTypes.toArray(new DataType[operandTypes.size()])),
return new Operator(functionDef, functionDef.getName(), new Signature(operandTypes.toArray(new DataType[operandTypes.size()])),
functionDef.getResultType()).withAccessLevel(functionDef.getAccessLevel())
.withFluent(functionDef.isFluent() != null ? functionDef.isFluent() : false)
.withExternal(functionDef.isExternal() != null ? functionDef.isExternal() : false);
}

public Operator(String name, Signature signature, DataType resultType) {
this(null, name, signature, resultType);
}

public Operator(FunctionDef functionDef, String name, Signature signature, DataType resultType) {
if (name == null || name.equals("")) {
throw new IllegalArgumentException("name is null or empty");
}
Expand All @@ -29,6 +33,7 @@ public Operator(String name, Signature signature, DataType resultType) {
throw new IllegalArgumentException("signature is null");
}

this.functionDef = functionDef;
this.name = name;
this.signature = signature;
this.resultType = resultType;
Expand Down Expand Up @@ -84,6 +89,18 @@ public Operator withExternal(boolean isExternal) {
return this;
}

private FunctionDef functionDef;
public FunctionDef getFunctionDef() {
return this.functionDef;
}
public void setFunctionDef(FunctionDef functionDef) {
this.functionDef = functionDef;
}
public Operator withFunctionDef(FunctionDef functionDef) {
setFunctionDef(functionDef);
return this;
}

private String name;
public String getName() {
return this.name;
Expand Down
Loading

0 comments on commit 9ef9f54

Please sign in to comment.