Commit 90ac20cf authored by Georg Fette's avatar Georg Fette
Browse files

- added some more aql 2 cypher stuff

- added an aql model generator
parent dd600c8d
......@@ -74,5 +74,16 @@
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openehr.java-libs</groupId>
<artifactId>oet-parser</artifactId>
<version>1.0.71</version>
<exclusions>
<exclusion>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
\ No newline at end of file
......@@ -77,13 +77,15 @@ public class Concept {
throw new RuntimeException("field '" + aName + "' does not exist");
}
// @JsonIgnore
// @JsonIgnore
public List<ConceptField> getFields() {
if (isArray()) {
throw new RuntimeException("array fields do not have fields");
}
List<ConceptField> result = new ArrayList<ConceptField>();
result.addAll(fields);
if (fields != null) {
result.addAll(fields);
}
return result;
}
......@@ -129,4 +131,8 @@ public class Concept {
}
}
public Concept getNonListConcept() {
return model.getConcept(name, false);
}
}
package de.uniwue.model.models;
package de.uniwue.model.FHIR;
import java.io.File;
import java.io.IOException;
......@@ -8,7 +8,6 @@ import de.uniwue.misc.util.FileUtilsUniWue;
import de.uniwue.misc.util.ResourceUtil;
import de.uniwue.model.Concept;
import de.uniwue.model.Model;
import de.uniwue.model.StructureDef2ModelConverter;
public class FHIRModelInitializer extends Model {
......
package de.uniwue.model;
package de.uniwue.model.FHIR;
import java.io.File;
import java.util.ArrayList;
......@@ -16,6 +16,10 @@ import ca.uhn.fhir.parser.IParser;
import de.uniwue.misc.util.FileUtilsUniWue;
import de.uniwue.misc.util.ResourceUtil;
import de.uniwue.misc.util.StringUtilsUniWue;
import de.uniwue.model.Concept;
import de.uniwue.model.ConceptField;
import de.uniwue.model.Model;
import de.uniwue.model.UnwantedStuff;
public class StructureDef2ModelConverter {
......
......@@ -18,7 +18,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import de.uniwue.query.opInterfaces.OperatorType;
import de.uniwue.query.OperatorType;
public class Model {
......
package de.uniwue.model.models;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.openehr.am.archetype.Archetype;
import org.openehr.am.archetype.constraintmodel.ArchetypeInternalRef;
import org.openehr.am.archetype.constraintmodel.ArchetypeSlot;
import org.openehr.am.archetype.constraintmodel.CAttribute;
import org.openehr.am.archetype.constraintmodel.CComplexObject;
import org.openehr.am.archetype.constraintmodel.CObject;
import org.openehr.am.archetype.ontology.ArchetypeOntology;
import org.openehr.am.archetype.ontology.ArchetypeTerm;
import org.openehr.am.openehrprofile.datatypes.text.CCodePhrase;
import org.openehr.rm.support.basic.Interval;
import de.uniwue.misc.util.FileUtilsUniWue;
import de.uniwue.model.Concept;
import de.uniwue.model.ConceptField;
import de.uniwue.model.Model;
import se.acode.openehr.parser.ADLParser;
import se.acode.openehr.parser.ParseException;
public class Archetype2ModelConverter {
// private File rootArchDir;
private Archetype parse;
private String originalLangCode;
private Model model;
public Archetype2ModelConverter() throws IOException {
}
public void convertArchetypes2StructureDefs(File rootArchDir, Model aModel)
throws ParseException, Exception {
this.model = aModel;
Collection<File> files = FileUtilsUniWue.listFiles(rootArchDir, true);
for (File aFile : files) {
// if (!aFile.getName().matches("openEHR-EHR-CLUSTER.laboratory_test_analyte.v1.adl")) {
// continue;
// }
System.out.println(aFile.getName());
String fileString = FileUtilsUniWue.file2String(aFile);
convertArchetype2StructureDef(rootArchDir, fileString);
}
}
private void enrichSnapshotWithMissingFields(Concept concept, String rmTypeName) {
Set<String> existingFields = new HashSet<String>();
for (ConceptField aField : concept.getFields()) {
existingFields.add(aField.name);
}
rmTypeName = rmTypeName.replaceAll("<.*>", "");
Concept rmType = model.getConcept(rmTypeName, false);
for (ConceptField anRMField : rmType.getFields()) {
if (!existingFields.contains(anRMField.name)) {
concept.addField(anRMField.name, anRMField.possibleTypes, anRMField.isArray);
}
}
}
private boolean isArray(CObject anObj) {
Interval<Integer> occurrences = anObj.getOccurrences();
if (occurrences.isUpperIncluded()) {
String occMaxValue = occurrences.getUpper().toString();
if (anObj.isRoot()) {
// as in openEHR the max value of the root element is by default 1 in FHIR it should be *
return true;
}
int parseInt = Integer.parseInt(occMaxValue);
if (parseInt > 1) {
return true;
}
} else {
return true;
}
return false;
}
@SuppressWarnings("unchecked")
private Set<String> primitiveTypes = new HashSet<String>(
Arrays.asList(new String[] { "DV_ABSOLUTE_QUANTITY", "DV_AMOUNT", "DV_BOOLEAN",
"DV_CODED_TEXT", "DV_COUNT", "DV_DATE_TIME", "DV_DATE", "DV_DURATION", "DV_EHR_URI",
"DV_ENCAPSULATED", "DV_IDENTIFIER", "DV_INTERVAL", "DV_MULTIMEDIA", "DV_ORDERED",
"DV_ORDINAL", "DV_PARAGRAPH", "DV_PARSABLE", "DV_PROPORTION", "DV_QUANTIFIED",
"DV_QUANTITY", "DV_STATE", "DV_TEMPORAL", "DV_TEXT", "DV_TIME", "DV_URI" }));
private Set<String> getPrimitiveTypeFields(CAttribute anAttr) {
Set<String> containedPrimitiveTypes = new HashSet<String>();
Set<String> nonPrimitiveTypes = new HashSet<String>();
for (CObject aChildObj : anAttr.getChildren()) {
String childRmTypeName = aChildObj.getRmTypeName();
childRmTypeName = childRmTypeName.replaceAll("<.*>", "");
if (primitiveTypes.contains(childRmTypeName)) {
containedPrimitiveTypes.add(childRmTypeName);
} else {
nonPrimitiveTypes.add(childRmTypeName);
}
}
if ((containedPrimitiveTypes.size() > 0) && (nonPrimitiveTypes.size() > 0)) {
throw new RuntimeException(
"strange, mixture of primitive and nonprimitve types in same container");
}
return containedPrimitiveTypes;
}
private void processObject(Concept concept, CObject anObj) throws ParseException, Exception {
if (anObj instanceof ArchetypeInternalRef) {
ArchetypeInternalRef ref = (ArchetypeInternalRef) anObj;
String targetPath = ref.getTargetPath();
anObj = parse.getPathNodeMap().get(targetPath);
}
if ((anObj instanceof CComplexObject) || (anObj instanceof CCodePhrase)) {
if (anObj instanceof CComplexObject) {
CComplexObject complexObj = (CComplexObject) anObj;
List<CAttribute> attributes = complexObj.getAttributes();
for (CAttribute anAttr : attributes) {
processAttributeOfComplexObject(concept, anAttr);
}
}
enrichSnapshotWithMissingFields(concept, anObj.getRmTypeName());
} else if (anObj instanceof ArchetypeSlot) {
// processArchetypesSlot(concept, (ArchetypeSlot) anObj);
}
}
private void processAttributeOfComplexObject(Concept concept, CAttribute anAttr)
throws ParseException, Exception {
Set<String> primitiveTypeFields = getPrimitiveTypeFields(anAttr);
if (primitiveTypeFields.size() > 0) {
for (CObject aChildObj : anAttr.getChildren()) {
String rmAttributeName = anAttr.getRmAttributeName();
boolean isArrayFlag = isArray(aChildObj);
ConceptField newValueElem = concept.addField(rmAttributeName,
new ArrayList<String>(primitiveTypeFields), isArrayFlag);
}
} else {
for (CObject aChildObj : anAttr.getChildren()) {
processObject(concept, aChildObj);
String cleanedOntName = getCleanedOntName(aChildObj);
// concept.name = cleanedOntName;
}
}
}
/*
* The rootArchDir is necessary because the archetype definitions can contain other archetypes
* that have to be lazy loaded
*/
private void convertArchetype2StructureDef(File rootArchDir, String adl)
throws ParseException, Exception {
// this.rootArchDir = rootArchDir;
ADLParser parser = new ADLParser(adl);
parse = parser.parse();
originalLangCode = parse.getOriginalLanguage().getCodeString();
if (originalLangCode == null) {
throw new RuntimeException("original language code has to be given");
}
CComplexObject def = parse.getDefinition();
String rmTypeName = def.getRmTypeName();
if (!rmTypeName.matches(
"CLUSTER|ELEMENT|EVENT|HISTORY|INTERVAL_EVENT|ITEM_LIST|ITEM_SINGLE|ITEM_STRUCTURE|ITEM_TABLE|ITEM_TREE|ITEM|"
+ "ACTION|ACTIVITY|ADMIN_ENTRY|CARE_ENTRY|COMPOSITION|CONTENT_ITEM|EHR|ENTRY|EVALUATION|EVENT_CONTEXT|INSTRUCTION|ISM_TRANSITION|OBSERVATION|SECTION|"
+ "ACTOR|ADDRESS|AGENT|CAPABILITY|CONTACT|GROUP|ORGANISATION|PARTY_IDENTITY|PARTY_RELATIONSHIP|PARTY|PERSON|ROLE|VERSIONED_PARTY")) {
throw new RuntimeException("derivation of other archetypes not yet implemented");
}
Concept parent = model.getConcept(rmTypeName);
Concept concept = new Concept(parent, false);
String name = parse.getArchetypeId().getValue();
concept.name = name;
processObject(concept, def);
}
// private void processArchetypesSlot(ConceptField parent, ArchetypeSlot archSlot)
// throws ParseException, Exception {
// Set<Assertion> includes = archSlot.getIncludes();
// if (includes == null) {
// System.out.println("empty includes for archetype slot definition...");
// return;
// }
// for (Assertion anIncAssert : includes) {
// String stringExpression = anIncAssert.getStringExpression();
// String archPattern = ((CString) ((ExpressionLeaf) ((ExpressionBinaryOperator) anIncAssert
// .getExpression()).getRightOperand()).getItem()).getPattern();
// Set<String> targetProfiles = new HashSet<String>();
// if (!archPattern.equals(".*")) {
// Collection<File> files = FileUtilsUniWue.listFiles(rootArchDir, true);
// for (File aFile : files) {
// String filename = aFile.getName().replace(".adl", "");
// if (filename.matches(archPattern)) {
// String file2String = FileUtilsUniWue.file2String(aFile);
// ADLParser parser = new ADLParser(file2String);
// Archetype refArchetypes = parser.parse();
// CComplexObject def = refArchetypes.getDefinition();
// // clear the cache
// existingPaths2Elements = new HashMap<String, HashMap<String, String>>();
// String targetProfile = getCleanedOntName(refArchetypes, def, "");
// targetProfiles.add(targetProfile);
// }
// }
// }
// if (targetProfiles.isEmpty()) {
// // strange, we have not found a fitting archetypes. Just add a root
// targetProfiles.add("DomainResource");
// }
// addType(parent, "Reference", targetProfiles);
// }
// }
private String cleanID(String anID) {
StringBuilder b = new StringBuilder();
String[] split = anID.split("[^A-Za-z0-9\\-\\.]");
for (String part : split) {
b.append(StringUtils.capitalize(part));
}
return b.toString();
}
private String getCleanedOntName(Archetype anArch, CObject anObj) {
String nodeID = anObj.getNodeId();
String text = getOntName(anArch, nodeID);
String baseID = cleanID(text);
return baseID;
}
private String getCleanedOntName(CObject anObj) {
return getCleanedOntName(parse, anObj);
}
private String getOntName(Archetype anArch, String code) {
ArchetypeOntology ontology = anArch.getOntology();
ArchetypeTerm termDefinition = ontology.termDefinition(originalLangCode, code);
if (termDefinition == null) {
return "";
}
String text = termDefinition.getText();
return text;
}
}
......@@ -10,7 +10,7 @@ import de.uniwue.misc.util.FileUtilsUniWue;
import de.uniwue.misc.util.ResourceUtil;
import de.uniwue.model.Concept;
import de.uniwue.model.Model;
import de.uniwue.model.StructureDef2ModelConverter;
import de.uniwue.model.FHIR.StructureDef2ModelConverter;
public class OpenEHRModelInitializer extends Model {
......@@ -23,7 +23,7 @@ public class OpenEHRModelInitializer extends Model {
aConc.parentConcept = ANY;
}
}
CONCEPT = getConcept("DomainResource");
CONCEPT = getConcept("DomainResource");
BOOLEAN = getConcept("boolean");
DATETIME = getConcept("dateTime");
DOUBLE = getConcept("decimal");
......@@ -55,19 +55,24 @@ public class OpenEHRModelInitializer extends Model {
public void createModelFileFromStructureDefs() throws Exception {
FhirContext ctx = FhirContext.forDstu3();
StructureDef2ModelConverter converter = new StructureDef2ModelConverter(ctx);
StructureDef2ModelConverter strDefConverter = new StructureDef2ModelConverter(ctx);
String profileTypesPath = "classpath:models/FHIR_v3/profiles-types.json";
converter.convertStructureDefsBundle(profileTypesPath);
for (Concept aConc : converter.model.getConcepts()) {
strDefConverter.convertStructureDefsBundle(profileTypesPath);
for (Concept aConc : strDefConverter.model.getConcepts()) {
if (!Character.isLowerCase(aConc.name.charAt(0))) {
converter.model.removeConcept(aConc);
strDefConverter.model.removeConcept(aConc);
}
}
new Concept("DomainResource", converter.model);
String structureDefsDir = "classpath:models/openEHR/StructureDefs";
new Concept("DomainResource", strDefConverter.model);
String structureDefsDir = "classpath:models/openEHR/StructureDefs_openEHR_RM";
Resource resource = ResourceUtil.getResource(structureDefsDir);
converter.convertStructureDefsDir(resource.getFile());
String json = converter.model.toJSON();
strDefConverter.convertStructureDefsDir(resource.getFile());
Archetype2ModelConverter archTypeConverster = new Archetype2ModelConverter();
String archetypeDefsDir = "classpath:models/openEHR/Archetypes";
Resource archDefsDirResource = ResourceUtil.getResource(archetypeDefsDir);
archTypeConverster.convertArchetypes2StructureDefs(archDefsDirResource.getFile(),
strDefConverter.model);
String json = strDefConverter.model.toJSON();
FileUtilsUniWue.saveString2File(json, new File("D:\\tmp\\openEHR_model.json"));
}
}
......@@ -81,12 +81,12 @@ import org.cqframework.cql.gen.cqlParser.WithClauseContext;
import de.uniwue.misc.util.RegexUtil;
import de.uniwue.model.Model;
import de.uniwue.query.OperatorType;
import de.uniwue.query.Primitive;
import de.uniwue.query.PrimitiveDateTime;
import de.uniwue.query.QueryOperator;
import de.uniwue.query.QueryParseException;
import de.uniwue.query.System_2_Graph_Mapper;
import de.uniwue.query.opInterfaces.OperatorType;
public class CQL_2_Graph_Mapper extends System_2_Graph_Mapper {
......@@ -576,7 +576,7 @@ public class CQL_2_Graph_Mapper extends System_2_Graph_Mapper {
String prettyPrint = prettyPrint(ditc);
QueryOperator lastOp = currentOp;
QueryOperator thisOp;
thisOp = addOp(OperatorType.DURATIONIN);
thisOp = addOp(OperatorType.DURATION_IN);
ExpressionTermContext expressionTerm = ditc.expressionTerm();
PluralDateTimePrecisionContext pluralDateTimePrecision = ditc.pluralDateTimePrecision();
String text = pluralDateTimePrecision.getText();
......
......@@ -10,9 +10,9 @@ import java.util.Set;
import de.uniwue.model.Model;
import de.uniwue.query.Expression;
import de.uniwue.query.Graph_2_System_Mapper;
import de.uniwue.query.OperatorType;
import de.uniwue.query.Primitive;
import de.uniwue.query.QueryOperator;
import de.uniwue.query.opInterfaces.OperatorType;
public class Graph_2_CQL_Mapper extends Graph_2_System_Mapper {
......
package de.uniwue.query;
import de.uniwue.model.Concept;
import de.uniwue.query.opInterfaces.OperatorType;
public abstract class Expression {
......
......@@ -11,8 +11,7 @@ import java.util.Set;
import de.uniwue.model.Concept;
import de.uniwue.model.ConceptField;
import de.uniwue.model.Model;
import de.uniwue.query.opInterfaces.OperatorType;
import de.uniwue.query.opInterfaces.OperatorType.InterfaceFlags;
import de.uniwue.query.OperatorType.InterfaceFlags;
public class Fuzzer {
......@@ -242,7 +241,7 @@ public class Fuzzer {
result.add(model.QUANTITY);
result.add(model.DATETIME);
}
} else if (aContainerOp.type.interfaceFlags.contains(InterfaceFlags.AggregateOp)) {
} else if (aContainerOp.type.interfaceFlags.contains(InterfaceFlags.IsAggregateOp)) {
result.add(model.LIST_OF_NUMBER);
result.add(model.LIST_OF_QUANTITY);
} else if (aContainerOp.type.interfaceFlags.contains(InterfaceFlags.UnlimitedParams)) {
......
......@@ -18,19 +18,24 @@ public abstract class LanguageManager {
public QueryOperator parse(String aQuery) throws QueryParseException {
QueryOperator parse = system_2_graph_mapper.parse(aQuery);
List<StructureProblem> checkProblems = parse.checkProblems();
if (checkProblems.size() > 0) {
throw new RuntimeException("problems with query");
}
checkProblems(parse);
return parse;
}
public String parse(QueryOperator anOp) throws QueryParseException {
List<StructureProblem> checkProblems = anOp.checkProblems();
checkProblems(anOp);
return graph_2_system_mapper.parse(anOp);
}
private void checkProblems(QueryOperator parse) {
List<StructureProblem> checkProblems = parse.checkProblems();
if (checkProblems.size() > 0) {
throw new RuntimeException("problems with query");
String problems = "";
for (StructureProblem aProblem : checkProblems) {
problems += aProblem.message + "\n";
}
throw new RuntimeException("problems with query:\n" + problems);
}
return graph_2_system_mapper.parse(anOp);
}
}
......@@ -6,7 +6,6 @@ import java.util.List;
import java.util.Map;
import de.uniwue.model.Model;
import de.uniwue.query.opInterfaces.OperatorType;
public class OperatorManager {
......
package de.uniwue.query.opInterfaces;
package de.uniwue.query;
import java.util.ArrayList;
import java.util.Arrays;
......@@ -9,13 +9,21 @@ import java.util.Set;
import de.uniwue.model.Concept;
import de.uniwue.model.Model;
import de.uniwue.query.Expression;
import de.uniwue.query.QueryOperator;
import de.uniwue.query.StructureProblem;
import de.uniwue.query.StructureProblem.ProblemType;
import de.uniwue.query.specialOpInterfaces.OpAliasRef;
import de.uniwue.query.specialOpInterfaces.OpContains;
import de.uniwue.query.specialOpInterfaces.OpContainsType;
import de.uniwue.query.specialOpInterfaces.OpField;
import de.uniwue.query.specialOpInterfaces.OpFieldWithType;
import de.uniwue.query.specialOpInterfaces.OpIn;
import de.uniwue.query.specialOpInterfaces.OpIndexedField;
import de.uniwue.query.specialOpInterfaces.OpIterate;
import de.uniwue.query.specialOpInterfaces.OpList;
public class OperatorType {
public static boolean doTypeChecking = true;
public static HashMap<String, OperatorType> allOpTypes = new HashMap<String, OperatorType>();
// boolean
......@@ -24,11 +32,11 @@ public class OperatorType {
// comparators
public static OperatorType EQUALS, NOT_EQUALS, IN, IN_VALUE_SET, DURING, DURATION_BETWEEN, LESS,
LESS_OR_EQUAL, MORE, MORE_OR_EQUAL, BETWEEN, CONTAINS, IS, MATCHES, MATCHES_AQL, AFTER,
BEFORE, DURATIONIN;
BEFORE, DURATION_IN;
// list
public static OperatorType FILTER, COLLECT, FIRST, LAST, SORT, FIRST_N, EXISTS, DEMOTE,
CONTAINS_TYPE, SELECT_INDEX;
CONTAINS_TYPE/* , SELECT_INDEX */;
// interval
public static OperatorType END, START;
......@@ -44,7 +52,8 @@ public class OperatorType {
public static OperatorType NOW, TODAY, TIMEOFDAY, TIME, DATETIME;
// system
public static OperatorType ITERATE, FIELD_WITH_TYPE, FIELD, RETURN, QUERY, ALIAS_REF;
public static OperatorType ITERATE, FIELD_WITH_TYPE, FIELD, INDEXED_FIELD, RETURN, QUERY,
ALIAS_REF;
// constructors
public static OperatorType QUANTITY, DURATION, LIST;
......@@ -62,7 +71,8 @@ public class OperatorType {
public static enum InterfaceFlags {
AllParamsTheSame, UnlimitedParams, AllParamsMayBeAllQuantityTypes, FirstParamMayBeAllQuantityTypes, //
ListOp, ParamsHaveToConform, ReturnFirstParamType, ReturnFirstParamTypeNonList, ReturnSecondParamTypeAsList, //
DontCheck, AggregateOp, AllParamsOnlyPrimitives, AllParamButFirstOnlyPrimitives, AllParamsNoLists
DontCheck, IsAggregateOp, AllParamsOnlyPrimitives, AllParamButFirstOnlyPrimitives, AllParamsNoLists, //
IsComparatorOp
}
protected OperatorType(String name, Concept[] parameterTypes, Concept returnType,
......@@ -142,44 +152,60 @@ public class OperatorType {
// comparators
AFTER = new OperatorType("AFTER", new Concept[] { aModel.DATETIME, aModel.DATETIME },
aModel.BOOLEAN);
aModel.BOOLEAN, new InterfaceFlags[] { InterfaceFlags.IsComparatorOp });
BEFORE = new OperatorType("BEFORE", new Concept[] { aModel.DATETIME, aModel.DATETIME },
aModel.BOOLEAN);
aModel.BOOLEAN, new InterfaceFlags[] { InterfaceFlags.IsComparatorOp });
EQUALS = new OperatorType("EQUALS", new Concept[] { aModel.ANY }, aModel.BOOLEAN,
new InterfaceFlags[] { InterfaceFlags.ParamsHaveToConform,
InterfaceFlags.AllParamsNoLists },
InterfaceFlags.AllParamsNoLists, InterfaceFlags.IsComparatorOp },
2, 2);
NOT_EQUALS = new OperatorType("NOT_EQUALS", new Concept[] { aModel.ANY }, aModel.BOOLEAN,
new InterfaceFlags[] { InterfaceFlags.ParamsHaveToConform,
InterfaceFlags.AllParamsNoLists },
InterfaceFlags.AllParamsNoLists, InterfaceFlags.IsComparatorOp },
2, 2);
IN = new OpIn("IN", new Concept[] { aModel.ANY, aModel.LIST_OF_ANY }, aModel.BOOLEAN);
IN = new OpIn("IN", new Concept[] { aModel.ANY, aModel.LIST_OF_ANY }, aModel.BOOLEAN,
new InterfaceFlags[] { InterfaceFlags.AllParamsNoLists,