Commit 0299b114 authored by Georg Fette's avatar Georg Fette
Browse files

fixed all test cases

parent 71761b79
......@@ -14,23 +14,25 @@ public class Concept {
public Model model;
@JsonIgnore
public Concept parent;
public Concept parentConcept;
@JsonIgnore
// this field is for data type checks. In FHIR for example it is unusual for a Concept to indicate
// if it is an array. But for an operator interface is is an essential property of a data type if
// it is an array. This property is redundant and exists for Concepts as well as for Concept
// fields.
public boolean isArray;
@JsonIgnore
private boolean isArray;
public String name;
public String description;
public List<String> termCodes;
@JsonSerialize
private List<ConceptField> fields;
public String parentName;
public String parent;
// for serialization
private Concept() {
......@@ -39,17 +41,23 @@ public class Concept {
public Concept(String name, Model model) {
this.name = name;
this.model = model;
model.addConcept(this);
model.addConcept(this);
}
public Concept(Concept aConc, boolean isArray) {
this(aConc.name, aConc.model);
parent = model.ANY;
parentName = aConc.parentName;
this.name = aConc.name;
this.model = aConc.model;
parentConcept = model.ANY;
parent = aConc.parent;
this.isArray = isArray;
for (Concept x : model.getConcepts()) {
if (x.isArray()) {
int y = 0;
}
}
}
public void addField(String fieldName, List<String> fieldTypes, boolean isArrayFlag) {
public ConceptField addField(String fieldName, List<String> fieldTypes, boolean isArrayFlag) {
if (fields == null) {
fields = new ArrayList<ConceptField>();
}
......@@ -59,10 +67,14 @@ public class Concept {
field.possibleTypes = fieldTypes;
fields.add(field);
field.parent = this;
return field;
}
@JsonIgnore
public ConceptField getField(String aName) {
if (isArray()) {
throw new RuntimeException("array fields cannot access fields");
}
for (ConceptField aField : fields) {
if (aField.name.equals(aName)) {
return aField;
......@@ -78,15 +90,23 @@ public class Concept {
for (ConceptField aField : fields) {
aField.parent = this;
}
parent = model.getConcept(parentName);
if (parent != null) {
parentConcept = model.getConcept(parent);
}
}
@Override
public String toString() {
String result = name;
if (isArray) {
if (isArray()) {
result = "List<" + result + ">";
}
return result;
}
@JsonIgnore
public boolean isArray() {
return isArray;
}
}
......@@ -15,6 +15,8 @@ public class ConceptField {
public boolean isArray;
public String description;
@JsonIgnore
public Concept getDataType() {
if (possibleTypes.size() == 1) {
......@@ -25,4 +27,9 @@ public class ConceptField {
}
}
@Override
public String toString() {
return name;
}
}
......@@ -45,6 +45,9 @@ public class Model {
aConc.model = this;
conceptMap.put(aConc.name, aConc);
}
if (!containsConcept("Element")) {
new Concept("Element", this);
}
for (Concept aConc : concepts) {
aConc.initialize();
}
......@@ -60,6 +63,10 @@ public class Model {
conceptMap.remove(aConc.name);
}
public boolean containsConcept(String aName) {
return conceptMap.containsKey(aName);
}
public Concept getConcept(String aName) {
return getConcept(aName, false);
}
......@@ -82,6 +89,9 @@ public class Model {
public Concept getConcept(String aName, boolean isArray) {
Concept aConc = conceptMap.get(aName);
if (aConc == null) {
throw new RuntimeException("Concept '" + aName + "' does not exist");
}
return getConcept(aConc, isArray);
}
......
......@@ -15,6 +15,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.IParser;
import de.uniwue.misc.util.FileUtilsUniWue;
import de.uniwue.misc.util.ResourceUtil;
import de.uniwue.misc.util.StringUtilsUniWue;
public class StructureDef2ModelConverter {
......@@ -36,7 +37,7 @@ public class StructureDef2ModelConverter {
public void convertStructureDefsDir(File aStructureDefDir) throws Exception {
IParser parser = ctx.newXmlParser();
// parser = ctx.newJsonParser();
for (File aFile : aStructureDefDir.listFiles()) {
for (File aFile : FileUtilsUniWue.listFiles(aStructureDefDir, true)) {
System.out.println(aFile.getName());
String structureDefString = FileUtilsUniWue.file2String(aFile);
currentStrucDef = (StructureDefinition) parser.parseResource(structureDefString);
......@@ -73,7 +74,15 @@ public class StructureDef2ModelConverter {
List<String> result = new ArrayList<String>();
for (TypeRefComponent aType : anElem.getType()) {
String code = aType.getCode();
result.add(code);
if (code.equals("Reference")) {
String targetProfile = aType.getTargetProfile();
if (targetProfile != null) {
targetProfile = targetProfile.replaceAll(".*/", "");
result.add(targetProfile);
}
} else {
result.add(code);
}
}
return result;
}
......@@ -82,6 +91,11 @@ public class StructureDef2ModelConverter {
List<ElementDefinition> element = currentStrucDef.getSnapshot().getElement();
List<ElementDefinition> result = new ArrayList<ElementDefinition>();
for (ElementDefinition anElem : element) {
String contentReference = anElem.getContentReference();
if (contentReference != null) {
// TODO
continue;
}
String path = anElem.getPath();
if (!path.startsWith(basePath + ".")) {
// element has to begin with the basePath
......@@ -117,9 +131,11 @@ public class StructureDef2ModelConverter {
String name = path.substring(path.lastIndexOf(".") + 1);
boolean isList = isList(anElem);
List<String> fieldTypes = new ArrayList<String>();
fieldTypes.add("BackboneElement");
parentConcept.addField(name, fieldTypes, isList);
fieldTypes.add(path);
ConceptField addField = parentConcept.addField(name, fieldTypes, isList);
addField.description = anElem.getShort();
Concept nestedConcept = new Concept(path, model);
nestedConcept.parent = "DomainResource";
addBackboneComponents(path, nestedConcept);
addNonBackboneMembers(path, nestedConcept);
}
......@@ -132,7 +148,6 @@ public class StructureDef2ModelConverter {
}
private void addNonBackboneMembers(String parentName, Concept parentConcept) {
int x = 0;
List<ElementDefinition> elements = getElements(parentName, 1);
for (ElementDefinition anElem : elements) {
addNonBackboneElement(anElem, parentConcept);
......@@ -147,26 +162,47 @@ public class StructureDef2ModelConverter {
String path = anElem.getPath();
String name = path.substring(path.lastIndexOf(".") + 1);
name = name.replaceAll("\\.", "");
name = name.replaceAll("\\[x\\]", "");
List<String> fhirTypes = getTypes(anElem);
boolean isList = isList(anElem);
parentConcept.addField(name, fhirTypes, isList);
if (name.contains("[x]")) {
name = name.replaceAll("\\[x\\]", "");
boolean first = true;
for (String aType : fhirTypes) {
String concreteName = name + StringUtilsUniWue.firstUpperCase(aType);
List<String> singleTypeList = new ArrayList<String>();
singleTypeList.add(aType);
ConceptField addField = parentConcept.addField(concreteName, singleTypeList, isList);
addField.description = anElem.getShort();
}
} else {
ConceptField addField = parentConcept.addField(name, fhirTypes, isList);
addField.description = anElem.getShort();
}
}
private void addParentRelation(Concept aConcept) {
String baseDefinition = currentStrucDef.getBaseDefinition();
if (baseDefinition != null) {
String baseClass = baseDefinition.replaceAll("^.*/", "");
aConcept.parentName = baseClass;
aConcept.parent = model.getConcept(baseClass);
aConcept.parent = baseClass;
if (model.containsConcept(baseClass)) {
aConcept.parentConcept = model.getConcept(baseClass);
} else {
aConcept.parentConcept = new Concept(baseClass, model);
}
}
}
public void convertStrucDefToConcept() throws Exception {
String name = currentStrucDef.getName();
Concept concept = new Concept(name, model);
Concept concept;
if (model.containsConcept(name)) {
concept = model.getConcept(name);
} else {
concept = new Concept(name, model);
}
addParentRelation(concept);
if (!primitiveTypes.contains(name)) {
addParentRelation(concept);
addBackboneComponents(concept.name, concept);
addNonBackboneMembers(concept.name, concept);
}
......
......@@ -15,8 +15,8 @@ public class FHIRModelInitializer {
private static void initialize(Model model) {
model.ANY = model.getConcept("Resource");
for (Concept aConc : model.getConcepts()) {
if ((aConc.parent == null) && ((aConc != model.ANY))) {
aConc.parent = model.ANY;
if ((aConc.parentConcept == null) && ((aConc != model.ANY))) {
aConc.parentConcept = model.ANY;
}
}
model.CONCEPT = model.getConcept("Resource");
......@@ -26,9 +26,9 @@ public class FHIRModelInitializer {
model.DURATION = model.getConcept("Duration");
model.INTEGER = model.getConcept("integer");
model.NUMBER = new Concept("Number", model);
model.NUMBER.parent = model.ANY;
model.DOUBLE.parent = model.NUMBER;
model.INTEGER.parent = model.NUMBER;
model.NUMBER.parentConcept = model.ANY;
model.DOUBLE.parentConcept = model.NUMBER;
model.INTEGER.parentConcept = model.NUMBER;
model.PERIOD = model.getConcept("Period");
model.QUANTITY = model.getConcept("Quantity");
model.STRING = model.getConcept("string");
......@@ -39,8 +39,7 @@ public class FHIRModelInitializer {
model.LIST_OF_DATETIME = model.getConcept("dateTime", true);
model.LIST_OF_DOUBLE = model.getConcept("decimal", true);
model.LIST_OF_INTEGER = model.getConcept("integer", true);
model.LIST_OF_NUMBER = new Concept("Number", model);
model.LIST_OF_NUMBER.isArray = true;
model.LIST_OF_NUMBER = model.getConcept("Number", true);
model.LIST_OF_PERIOD = model.getConcept("Period", true);
model.LIST_OF_QUANTITY = model.getConcept("Quantity", true);
model.LIST_OF_STRING = model.getConcept("string", true);
......@@ -56,10 +55,10 @@ public class FHIRModelInitializer {
public static void main(String[] args) throws Exception {
FHIRModelInitializer initializer = new FHIRModelInitializer();
initializer.work();
initializer.createModelFileFromStructureDefs();
}
public void work() throws Exception {
public void createModelFileFromStructureDefs() throws Exception {
String profileTypesPath = "classpath:models/FHIR_v3/profiles-types.json";
String profileResourcesPath = "classpath:models/FHIR_v3/profiles-resources.json";
FhirContext ctx = FhirContext.forDstu3();
......
......@@ -2,8 +2,6 @@ package de.uniwue.model.models;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.springframework.core.io.Resource;
......@@ -17,50 +15,32 @@ import de.uniwue.model.StructureDef2ModelConverter;
public class OpenEHRModelInitializer {
private static void initialize(Model model) {
Concept rootConcept = model.getConcept("Resource");
if (rootConcept == null) {
rootConcept = new Concept("Resource", model);
}
model.ANY = rootConcept;
Concept root = new Concept("Element", model);
model.ANY = root;
for (Concept aConc : model.getConcepts()) {
if ((aConc.parent == null) && ((aConc != model.ANY))) {
aConc.parent = model.ANY;
if ((aConc.parentConcept == null) && ((aConc != model.ANY))) {
aConc.parentConcept = model.ANY;
}
}
model.CONCEPT = rootConcept;
model.CONCEPT = model.getConcept("DomainResource");
model.BOOLEAN = model.getConcept("boolean");
model.DATETIME = model.getConcept("dateTime");
model.DOUBLE = model.getConcept("decimal");
model.DURATION = model.getConcept("Duration");
model.INTEGER = model.getConcept("integer");
model.NUMBER = new Concept("Number", model);
model.NUMBER.parent = model.ANY;
model.DOUBLE.parent = model.NUMBER;
model.INTEGER.parent = model.NUMBER;
model.PERIOD = model.getConcept("Period");
model.QUANTITY = model.getConcept("Quantity");
model.NUMBER.parentConcept = model.ANY;
model.DOUBLE.parentConcept = model.NUMBER;
model.INTEGER.parentConcept = model.DOUBLE;
model.STRING = model.getConcept("string");
model.LIST_OF_ANY = model.getConcept(rootConcept, true);
model.LIST_OF_ANY = model.getConcept(root, true);
model.LIST_OF_BOOLEAN = model.getConcept("boolean", true);
model.LIST_OF_CONCEPT = model.getConcept(rootConcept, true);
model.LIST_OF_CONCEPT = model.getConcept(root, true);
model.LIST_OF_DATETIME = model.getConcept("dateTime", true);
model.LIST_OF_DOUBLE = model.getConcept("decimal", true);
model.LIST_OF_INTEGER = model.getConcept("integer", true);
model.LIST_OF_NUMBER = new Concept("Number", model);
model.LIST_OF_NUMBER.isArray = true;
model.LIST_OF_PERIOD = model.getConcept("Period", true);
model.LIST_OF_QUANTITY = model.getConcept("Quantity", true);
model.LIST_OF_NUMBER = model.getConcept("Number", true);
model.LIST_OF_STRING = model.getConcept("string", true);
Concept ehr = new Concept("EHR", model);
for (Concept aConc : model.getConcepts()) {
if (aConc != ehr) {
List<String> possibleFields = new ArrayList<String>();
possibleFields.add(aConc.name);
aConc.addField(aConc.name, possibleFields, true);
}
}
}
public static Model loadModel() throws IOException {
......@@ -73,10 +53,10 @@ public class OpenEHRModelInitializer {
public static void main(String[] args) throws Exception {
OpenEHRModelInitializer initializer = new OpenEHRModelInitializer();
initializer.work();
initializer.createModelFileFromStructureDefs();
}
public void work() throws Exception {
public void createModelFileFromStructureDefs() throws Exception {
FhirContext ctx = FhirContext.forDstu3();
StructureDef2ModelConverter converter = new StructureDef2ModelConverter(ctx);
String profileTypesPath = "classpath:models/FHIR_v3/profiles-types.json";
......@@ -86,7 +66,8 @@ public class OpenEHRModelInitializer {
converter.model.removeConcept(aConc);
}
}
String structureDefsDir = "classpath:models/openEHR/StructureDefs";
new Concept("DomainResource", converter.model);
String structureDefsDir = "classpath:models/openEHR/StructureDefs";
Resource resource = ResourceUtil.getResource(structureDefsDir);
converter.convertStructureDefsDir(resource.getFile());
String json = converter.model.toJSON();
......
......@@ -2,7 +2,6 @@ package de.uniwue.query.CQL;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.antlr.v4.runtime.ANTLRInputStream;
......@@ -93,8 +92,6 @@ public class CQL_2_Graph_Mapper extends System_2_Graph_Mapper {
private boolean parsingRetrieveClause;
private List<String> availableAliasNames;
public CQL_2_Graph_Mapper() {
super(cqlParser.ruleNames);
}
......@@ -107,8 +104,6 @@ public class CQL_2_Graph_Mapper extends System_2_Graph_Mapper {
protected void clear() {
super.clear();
parsingRetrieveClause = false;
availableAliasNames = new ArrayList<String>(
Arrays.asList(new String[] { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" }));
}
public void dispose() {
......@@ -142,14 +137,12 @@ public class CQL_2_Graph_Mapper extends System_2_Graph_Mapper {
QueryOperator firstConc = iteratorsRecursive.get(0);
String alias;
if (firstConc.alias == null) {
alias = availableAliasNames.get(0);
alias = getNewAliasName();
firstConc.alias = alias;
availableAliasNames.remove(alias);
} else {
alias = firstConc.alias;
}
QueryOperator aliasRef = addOp(OperatorType.ALIAS_REF);
aliasRef.addParameter(alias);
addAliasRef(currentOp, alias);
}
}
......@@ -229,13 +222,22 @@ public class CQL_2_Graph_Mapper extends System_2_Graph_Mapper {
} else if (term instanceof InvocationTermContext) {
InvocationTermContext itc = (InvocationTermContext) term;
InvocationContext invocation = itc.invocation();
currentOp = null;
parseInvocationContext(invocation);
// switchAliasRefIfAccessingWithoutField();
} else {
throw new RuntimeException("unexpected");
}
}
// private void switchAliasRefIfAccessingWithoutField() {
// List<QueryOperator> aliasRefs = currentOp.getOpsRecursiveWithType(OperatorType.ALIAS_REF);
// for (QueryOperator anAliasRef : aliasRefs) {
// if (anAliasRef.parent.type != OperatorType.FIELD) {
// anAliasRef.type = OperatorType.ALIAS_REF_2;
// }
// }
// }
private void parseTupleElementSelectorContext(TupleElementSelectorContext anElem) {
String prettyPrint = prettyPrint(anElem);
String text = anElem.identifier().getText();
......@@ -259,10 +261,9 @@ public class CQL_2_Graph_Mapper extends System_2_Graph_Mapper {
List<SortByItemContext> sortByItem = sortClause.sortByItem();
for (SortByItemContext anItem : sortByItem) {
ExpressionTermContext expressionTerm = anItem.expressionTerm();
// set the currentPath to point to the iterator of the surrounding query
QueryOperator asConcept = queryOp.getParameters().get(0).asConcept();
// the first parameter is the operator returning the list to be sorted
String alias = queryOp.getParameters().get(0).alias;
String alias = getNewAliasName();
queryOp.alias = alias;
startPathWithAliasRef(alias);
parseExpressionTerm(expressionTerm);
}
......@@ -290,7 +291,6 @@ public class CQL_2_Graph_Mapper extends System_2_Graph_Mapper {
}
String alias = aliasedQuerySource.alias().identifier().getText();
thisOp.alias = alias;
availableAliasNames.remove(alias);
lastPathElem = null;
}
......@@ -314,7 +314,12 @@ public class CQL_2_Graph_Mapper extends System_2_Graph_Mapper {
}
}
String text = qualifiedIdentifier.identifier().getText();
QueryOperator newElem = new QueryOperator(currentOp, lastPathElem, text, getModel());
QueryOperator newElem;
if (lastPathElem == null) {
newElem = addAliasRef(currentOp, text);
} else {
newElem = new QueryOperator(currentOp, lastPathElem, text, getModel());
}
lastPathElem = newElem;
return newElem;
}
......@@ -329,9 +334,8 @@ public class CQL_2_Graph_Mapper extends System_2_Graph_Mapper {
thisOp = root;
TerminologyContext terminology = retrieve.terminology();
if (terminology != null) {
String alias = availableAliasNames.get(0);
String alias = getNewAliasName();
root.alias = alias;
availableAliasNames.remove(alias);
currentOp.removeParameter(root);
thisOp = addOp(OperatorType.FILTER);
currentOp.addParameter(root);
......@@ -340,8 +344,7 @@ public class CQL_2_Graph_Mapper extends System_2_Graph_Mapper {
String codeText = qualifiedIdentifier.identifier().getText().replaceAll("\"", "");
QueryOperator inValSetOp = addOp(OperatorType.IN_VALUE_SET);
QueryOperator codeFieldOp = addOp(OperatorType.FIELD);
QueryOperator aliasRefOp = addOp(OperatorType.ALIAS_REF);
aliasRefOp.addParameter(alias);
addAliasRef(currentOp, alias);
codeFieldOp.addParameter("code");
inValSetOp.addParameter(codeText);
}
......
......@@ -96,10 +96,22 @@ public class Graph_2_CQL_Mapper extends Graph_2_System_Mapper {
}
private String writeReturn(QueryOperator returnOp) {
String result;
if (returnOp.getParameters().size() > 1) {
result = writeReturnMultipleExpressions(returnOp);
} else {
result = writeReturnSingleExpression(returnOp);
}
return result;
}
private String writeReturnSingleExpression(QueryOperator returnOp) {
String result = "";
Expression firstReturnParam = returnOp.getParameters().get(0);
if (firstReturnParam.isOperator()) {
QueryOperator firstReturnOp = firstReturnParam.asOperator();
Expression returnParam = returnOp.getParameters().get(0);
if (returnParam.isOperator()) {
// if the first returned thing is just the first iterator, then don't write this as a return,
// it is implicitly done
QueryOperator firstReturnOp = returnParam.asOperator();
if (firstReturnOp.type == OperatorType.ALIAS_REF) {
String alias = firstReturnOp.getParameters().get(0).asPrimitive().value;
if (alias.equals(query.getIteratorsRecursive().get(0).alias)) {
......@@ -107,6 +119,12 @@ public class Graph_2_CQL_Mapper extends Graph_2_System_Mapper {
}
}
}
result += "return " + writeExpr(returnParam);
return result;
}
private String writeReturnMultipleExpressions(QueryOperator returnOp) {
String result = "";
result += "return Tuple { ";
boolean first = true;
for (Expression anExp : returnOp.getParameters()) {
......@@ -359,9 +377,9 @@ public class Graph_2_CQL_Mapper extends Graph_2_System_Mapper {
} else if (anOp.type == OperatorType.ALIAS_REF) {
String string = writeAliasRef(anOp);
result += string;
// } else if (anOp.type == OperatorType.INTERVAL) {
// String intString = writeInterval(anOp);
// result += intString;
// } else if (anOp.type == OperatorType.INTERVAL) {
// String intString = writeInterval(anOp);
// result += intString;
} else if (anOp.type == OperatorType.EXISTS) {