Commit f4a51c90 authored by Georg Fette's avatar Georg Fette
Browse files

further work

parent 097cdf40
......@@ -38,6 +38,25 @@ public class QueryOperator extends Expression {
addParameter(fieldName);
}
public QueryOperator(QueryOperator aContainerOp, QueryOperator aParentConc, String fieldName,
boolean asAlias) {
this(aContainerOp, aParentConc, fieldName, OperatorType.FIELD, asAlias);
}
public QueryOperator(QueryOperator aContainerOp, QueryOperator aParentConc, String fieldName,
OperatorType opType, boolean asAlias) {
this(aContainerOp, opType);
if (asAlias) {
QueryOperator aliasRef = new QueryOperator(OperatorType.ALIAS_REF);
aliasRef.addParameter(aParentConc.alias);
addParameter(aliasRef);
} else {
aContainerOp.removeParameter(aParentConc);
addParameter(aParentConc);
}
addParameter(fieldName);
}
public QueryOperator(String conceptCode) {
this(null, conceptCode);
}
......
package de.uniwue.query.i2b2;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
......@@ -200,24 +201,26 @@ public class Graph_2_I2B2_Mapper extends Graph_2_System_Mapper {
addElemWithInnerText(constrainElem, "value_type", valueType);
}
private void addPanelItem(Element panel, QueryOperator aConcept, QueryOperator anOp)
throws XMLStreamException {
private void addPanelItem(Element panel, QueryOperator aFilter) throws XMLStreamException {
Element item = new Element("item");
panel.addContent(item);
QueryOperator aConcept = aFilter.getParameters().get(0).asOperator();
addPanelItemHeader(item, aConcept);
if (anOp != null) {
addPanelItemOperators(item, aConcept, anOp);
if (aFilter.getParameters().size() > 1) {
QueryOperator aConstrain = aFilter.getParameters().get(1).asOperator();
addPanelItemOperators(item, aConcept, aConstrain);
}
// TODO: add temporal relations
}
private RequestedLevel getRequestedLevel(QueryOperator anOr) {
List<QueryOperator> conceptsRecursive = anOr.getIteratorsRecursive();
private RequestedLevel getRequestedLevel(List<QueryOperator> oredOps) {
List<QueryOperator> conceptsRecursive = new ArrayList<QueryOperator>();
for (QueryOperator aConc : oredOps) {
conceptsRecursive.addAll(aConc.getIteratorsRecursive());
}
for (QueryOperator aConc : conceptsRecursive) {
if (aConc.getIteratorSelector().equals(VALUE_CODE)) {
aConc = aConc.parent;
}
if (aConc.getParentConcept().getIteratorSelector().equals(ENCOUNTER_CODE)) {
QueryOperator parentConcept = aConc.getParentConcept();
if (parentConcept.getIteratorSelector().equals(ENCOUNTER_CODE)) {
if (aConc.parent.getChildConcepts().size() > 1) {
if (globalRequestLevel == RequestedLevel.ANY) {
globalRequestLevel = RequestedLevel.SAMEVISIT;
......@@ -225,7 +228,7 @@ public class Graph_2_I2B2_Mapper extends Graph_2_System_Mapper {
return RequestedLevel.SAMEVISIT;
}
}
if (aConc.getParentConcept().getIteratorSelector().equals(INSTANCE_CODE)) {
if (parentConcept.getIteratorSelector().equals(INSTANCE_CODE)) {
if (aConc.parent.getChildConcepts().size() > 1) {
if ((globalRequestLevel == RequestedLevel.ANY)
|| (globalRequestLevel == RequestedLevel.SAMEVISIT)) {
......@@ -238,53 +241,50 @@ public class Graph_2_I2B2_Mapper extends Graph_2_System_Mapper {
return RequestedLevel.ANY;
}
private void addPanel(Element queryDef, QueryOperator anOr, int panelIndex, boolean negated)
private void addPanel(Element queryDef, List<QueryOperator> anOrClause, int panelIndex)
throws XMLStreamException {
Element panel = addElem(queryDef, "panel");
RequestedLevel requestLevel = getRequestedLevel(anOr);
RequestedLevel requestLevel = getRequestedLevel(anOrClause);
boolean negated = false;
// if (anOp.type == OperatorType.NOT) {
// negated = true;
// anOp = anOp.getParameters().get(0).asOperator();
// }
addPanelHeader(panel, requestLevel, panelIndex, negated);
for (QueryOperator aConc : anOr.getChildConcepts()) {
// TODO: handle multiple constraints in one concept (i.e. value > x and timestamp < y)
addPanelItem(panel, aConc, null);
}
for (QueryOperator anOp : anOr.getOperators()) {
// take the parent because otherwise we have the 'value'-concept
QueryOperator aConcept = anOp.getParameters().get(0).asConcept().parent;
addPanelItem(panel, aConcept, anOp);
for (QueryOperator aConc : anOrClause) {
addPanelItem(panel, aConc);
}
}
private void addPanels(Element queryDef) throws XMLStreamException {
QueryOperator rootFilter = root.getParameters().get(0).asOperator().getParameters().get(1)
.asOperator();
if (rootFilter.type == OperatorType.OR) {
addPanel(queryDef, rootFilter, currentPanelIndex, false);
} else if (rootFilter.type == OperatorType.NOT) {
// there is either a single concept in the NOT
for (QueryOperator aConc : rootFilter.getChildConcepts()) {
QueryOperator tmpOr = new QueryOperator(OperatorType.OR);
tmpOr.addParameter(aConc);
addPanel(queryDef, tmpOr, currentPanelIndex, true);
}
// OR a single OR
for (QueryOperator anOr : rootFilter.getOperators()) {
addPanel(queryDef, anOr, currentPanelIndex, true);
private List<List<QueryOperator>> getOredOps(QueryOperator rootFilter) {
List<List<QueryOperator>> oredOps = new ArrayList<List<QueryOperator>>();
if (rootFilter.type == OperatorType.AND) {
for (QueryOperator anOredClause : rootFilter.getOperators()) {
List<QueryOperator> orList = new ArrayList<QueryOperator>();
orList.add(anOredClause);
oredOps.add(orList);
}
} else if (rootFilter.type == OperatorType.OR) {
oredOps.add(rootFilter.getOperators());
} else if (rootFilter.type == OperatorType.NOT) {
oredOps = getOredOps(rootFilter.getParameters().get(0).asOperator());
throw new RuntimeException("not yet implemented");
} else {
// an non boolean operator
addPanel(queryDef, rootFilter, currentPanelIndex, false);
currentPanelIndex++;
List<QueryOperator> orList = new ArrayList<QueryOperator>();
orList.add(rootFilter);
oredOps.add(orList);
}
return oredOps;
}
// for (Expression anExp : root.getParameters()) {
// QueryOperator aReturnClause = (QueryOperator) anExp;
// for (QueryOperator aConc : aReturnClause.getChildConcepts()) {
// QueryOperator tmpOr = new QueryOperator(OperatorType.OR);
// tmpOr.addParameter(aConc);
// addPanel(queryDef, tmpOr, currentPanelIndex, false);
// currentPanelIndex++;
// }
// }
private void addPanels(Element queryDef) throws XMLStreamException {
QueryOperator rootFilter = root.getParameters().get(0).asOperator().getParameters().get(1)
.asOperator();
List<List<QueryOperator>> andWithOrs = getOredOps(rootFilter);
for (List<QueryOperator> anOrClause : andWithOrs) {
addPanel(queryDef, anOrClause, currentPanelIndex++);
}
}
public static XMLOutputter getXMLOutputter() {
......@@ -305,6 +305,7 @@ public class Graph_2_I2B2_Mapper extends Graph_2_System_Mapper {
timing.addContent(globalRequestLevel.toString());
queryDef.addContent(0, timing);
String result = getXMLOutputter().outputString(request);
result = result.replaceAll("\r\n", "\n").trim();
return result;
}
......
......@@ -18,7 +18,11 @@ import de.uniwue.query.QueryOperator;
public class I2B2_2_Graph_Mapper extends Mapper {
private QueryOperator patient, encounter, currentBooleanOp;
private QueryOperator patient, encounter;
private String[] aliasNames = { "a", "b", "c", "d", "f", "g" };
private int aliasIndex;
public I2B2_2_Graph_Mapper() {
Graph_2_I2B2_Mapper.initializeOpMappings(opMap);
......@@ -34,15 +38,22 @@ public class I2B2_2_Graph_Mapper extends Mapper {
encounter = null;
}
private String prettyPrint(Element anElem) {
return Graph_2_I2B2_Mapper.getXMLOutputter().outputString(anElem);
}
private void parsePanels(Element queryDef) {
List<Element> panels = queryDef.getChildren("panel");
if (panels.size() > 1) {
addOp(OperatorType.AND);
}
for (Element aPanelElem : panels) {
parsePanel(aPanelElem);
}
}
private void parsePanel(Element aPanelElem) {
currentBooleanOp = null;
QueryOperator lastOp = currentOp;
String panelTiming = aPanelElem.getChild("panel_timing").getText();
QueryOperator concept;
if (panelTiming.equals("ANY")) {
......@@ -57,20 +68,21 @@ public class I2B2_2_Graph_Mapper extends Mapper {
}
String invert = aPanelElem.getChildText("invert");
if (invert != null && invert.equals("1")) {
currentBooleanOp = new QueryOperator(currentBooleanOp, OperatorType.NOT);
addOp(OperatorType.NOT);
}
List<Element> itemsList = aPanelElem.getChildren("item");
if (itemsList.size() > 1) {
currentBooleanOp = new QueryOperator(currentBooleanOp, OperatorType.OR);
} else {
currentBooleanOp = null;
addOp(OperatorType.OR);
}
for (Element anItemElem : itemsList) {
parseItem(anItemElem, concept);
}
currentOp = lastOp;
}
private void parseItem(Element anItemElem, QueryOperator concept) {
String prettyPrint = prettyPrint(anItemElem);
QueryOperator lastOp = currentOp;
Element modChild = anItemElem.getChild("constrain_by_modifier");
if (modChild != null) {
// TODO: handle modifier
......@@ -82,7 +94,10 @@ public class I2B2_2_Graph_Mapper extends Mapper {
// TODO: was bedeuten diese Belegungen ?
return;
}
QueryOperator newConcept = new QueryOperator(concept, itemKey);
QueryOperator filter = addOp(OperatorType.EXISTS);
QueryOperator newConcept = new QueryOperator(filter, concept, itemKey, true);
String alias = aliasNames[aliasIndex++];
newConcept.alias = alias;
List<Element> constrainByDateElems = anItemElem.getChildren("constrain_by_date");
for (Element dateConstraint : constrainByDateElems) {
// TODO:
......@@ -92,21 +107,19 @@ public class I2B2_2_Graph_Mapper extends Mapper {
for (Element valueConstraint : constrainByValueElems) {
parseConstrainByValue(valueConstraint, newConcept);
}
if ((constrainByValueElems.size() == 0) && (constrainByDateElems.size() == 0)) {
currentBooleanOp.addParameter(newConcept);
}
currentOp = lastOp;
}
private void parseConstrainByValue(Element valueConstraint, QueryOperator hullConcept) {
QueryOperator valueConcept = new QueryOperator(hullConcept.parent, hullConcept, "value");
private void parseConstrainByValue(Element valueConstraint, QueryOperator constrainedConcept) {
QueryOperator valueConcept = new QueryOperator(constrainedConcept.parent, constrainedConcept, "value", true);
currentOp = valueConcept;
String valueType = valueConstraint.getChildText("value_type");
String valueOperator = valueConstraint.getChildText("value_operator");
OperatorType operatorType = opMap.getOpType(valueOperator);
if (operatorType == null) {
throw new RuntimeException("unsupported operation");
}
QueryOperator constrainOp = new QueryOperator(currentBooleanOp, operatorType);
constrainOp.addParameter(valueConcept);
QueryOperator constrainOp = insertOp(operatorType);
String valueConstraintValue = valueConstraint.getChildText("value_constraint");
if (valueType.equalsIgnoreCase("NUMBER")) {
if (valueOperator.equalsIgnoreCase("BETWEEN")) {
......@@ -143,12 +156,18 @@ public class I2B2_2_Graph_Mapper extends Mapper {
public QueryOperator parse(String queryString) throws JDOMException, IOException {
clear();
patient = new QueryOperator(Graph_2_I2B2_Mapper.PATIENT_CODE);
root.getRootConcepts().add(patient);
patient.alias = "e";
QueryOperator filter = addOp(OperatorType.FILTER);
filter.addParameter(patient);
Document xmlDoc = new SAXBuilder()
.build(new ByteArrayInputStream(queryString.getBytes(StandardCharsets.UTF_8)));
Element rootElement = xmlDoc.getRootElement();
Element queryDef = rootElement.getChild("query_definition");
parsePanels(queryDef);
currentOp = root;
QueryOperator returnOp = addOp(OperatorType.RETURN);
QueryOperator aliasRef = addOp(OperatorType.ALIAS_REF);
aliasRef.addParameter("e");
return root;
}
......
......@@ -2,7 +2,9 @@ package de.uniwue.query.openEHR;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
......@@ -44,7 +46,9 @@ import com.ethercis.aql.parser.AqlParser.StandardPredicateContext;
import com.ethercis.aql.parser.AqlParser.TopExprContext;
import com.ethercis.aql.parser.AqlParser.ValueListItemsContext;
import com.ethercis.aql.parser.AqlParser.WhereContext;
import com.google.common.collect.Lists;
import de.uniwue.query.Expression;
import de.uniwue.query.OperatorType;
import de.uniwue.query.Primitive;
import de.uniwue.query.Primitive.PrimitiveDataType;
......@@ -55,11 +59,6 @@ public class AQL_2_Graph_Mapper extends System_2_Graph_Mapper {
private String currentExternalAlias;
// private QueryOperator getRootFilter() {
// QueryOperator filter = root.getParameters().get(0).asOperator();
// return filter;
// }
public AQL_2_Graph_Mapper() {
super(AqlParser.ruleNames);
Graph_2_AQL_Mapper.initializeOpMappings(opMap);
......@@ -75,44 +74,6 @@ public class AQL_2_Graph_Mapper extends System_2_Graph_Mapper {
currentExternalAlias = null;
}
// /**
// * @param newPathCode
// * @param forceNewInstance
// * When collecting the archetyped elements, elements with the same name have to be
// * instantiated again because they can have a different alias
// * @return
// */
// private QueryOperator step(String newPathCode, boolean forceNewInstance, String possibleAlias,
// OperatorType stepOpType) {
// QueryOperator result = null;
// if (currentPath != null) {
// QueryOperator lastElement = currentPath.getLastElement();
// // look for probably already existing children with that name
// for (QueryOperator aChild : lastElement.getChildConcepts()) {
// if (aChild.getCode().equals(newPathCode)) {
// if (possibleAlias != null) {
// if (aliases.containsKey(possibleAlias)
// && aliases.get(possibleAlias).getLastElement() == aChild) {
// result = aChild;
// }
// } else {
// result = aChild;
// }
// }
// }
// // don't instantiate archetyped elements again when collecting clauses
// if ((result == null) || forceNewInstance) {
// result = new QueryOperator(lastElement.parents.get(0), lastElement, newPathCode,
// stepOpType);
// }
// addPathElem(result);
// } else {
// result = new QueryOperator(currentOp, newPathCode);
// currentPath = new GraphPath(result);
// }
// return result;
// }
private boolean containsErrors(ParseTree aParseTree) {
for (int i = 0; i < aParseTree.getChildCount(); i++) {
ParseTree aChild = aParseTree.getChild(i);
......@@ -141,18 +102,92 @@ public class AQL_2_Graph_Mapper extends System_2_Graph_Mapper {
String prettyPrint = prettyPrint(parseTree);
currentOp = root;
visitQueryExpr(parseTree);
addModelLeafNodesToWhere();
moveClausesToOutmostEncapsulatingClauses();
removeUnnecessaryANDs();
return root;
}
private void addModelLeafNodesToWhere() {
// for (QueryConcept aLeaf : getRoot().getLeafsRecursive()) {
// if (aLeaf.parentOps.size() == 0) {
// QueryOperator anOp = new QueryOperator(OperatorType.EXISTS);
// query.ops.add(anOp);
// anOp.addParameter(aLeaf);
// }
// }
private void moveClausesToOutmostEncapsulatingClauses() {
List<QueryOperator> exists = root.getOpsRecursiveWithType(OperatorType.EXISTS);
// move first the innermost, then proceed to the outer ones
exists = Lists.reverse(exists);
for (QueryOperator anExist : exists) {
if (anExist.getParameters().size() > 1) {
QueryOperator filter = anExist.getParameters().get(1).asOperator();
if (filter.type == OperatorType.AND) {
for (QueryOperator aClause : filter.getOperators()) {
moveOpToCorrectEncapsulatingClause(aClause);
}
} else {
moveOpToCorrectEncapsulatingClause(filter);
}
}
}
}
private QueryOperator getOutmostClauseDefiningAllAliases(Set<String> usedAliases,
QueryOperator currentClause) {
for (QueryOperator aChildClause : currentClause.getOperators()) {
if (usedAliases.contains(aChildClause.alias)) {
Set<String> reducedAliases = new HashSet<String>(usedAliases);
reducedAliases.remove(aChildClause.alias);
if (reducedAliases.isEmpty()) {
// the currentClause is the wrapping filter of the alias defining iterator
return currentClause;
} else {
QueryOperator filterClause = currentClause.getParameters().get(1).asOperator();
return getOutmostClauseDefiningAllAliases(reducedAliases, filterClause);
}
}
QueryOperator resultClause = getOutmostClauseDefiningAllAliases(usedAliases, aChildClause);
if (resultClause != null) {
return resultClause;
}
}
return null;
}
private void moveOpToCorrectEncapsulatingClause(QueryOperator aFilter) {
Set<String> usedAliases = new HashSet<String>();
List<QueryOperator> aliasRefs = aFilter.getOpsRecursiveWithType(OperatorType.ALIAS_REF);
for (QueryOperator anAliasRef : aliasRefs) {
usedAliases.add(anAliasRef.getParameters().get(0).asPrimitive().value);
}
// remove aliases that are defined in myself
for (QueryOperator aChild : aFilter.getOpsRecursive()) {
usedAliases.remove(aChild.alias);
}
QueryOperator targetClause = getOutmostClauseDefiningAllAliases(usedAliases, root);
if (targetClause == null) {
throw new RuntimeException("there always has to be a match");
}
QueryOperator nearestFilter = getNearestFilter(aFilter);
if (nearestFilter != targetClause) {
aFilter.parent.removeParameter(aFilter);
if ((targetClause.getParameters().size() > 1)
&& (targetClause.getParameters().get(1).asOperator().type != OperatorType.AND)) {
currentOp = targetClause.getParameters().get(1).asOperator();
targetClause = insertOp(OperatorType.AND);
}
targetClause.addParameter(aFilter);
}
}
private QueryOperator getNearestFilter(QueryOperator anOp) {
QueryOperator currentOp = anOp.parent;
while (currentOp.type != OperatorType.EXISTS) {
currentOp = currentOp.parent;
}
return currentOp;
}
private void removeUnnecessaryANDs() {
for (QueryOperator anAnd : root.getOpsRecursiveWithType(OperatorType.AND)) {
if (anAnd.getParameters().size() == 1) {
anAnd.parent.addParameter(anAnd.getParameters().get(0));
anAnd.parent.removeParameter(anAnd);
}
}
}
private void visitPredicateOperandContexts(List<PredicateOperandContext> predicateOperand,
......@@ -226,7 +261,6 @@ public class AQL_2_Graph_Mapper extends System_2_Graph_Mapper {
// because the IdentifiedEqualities are mixed up with the boolean operators, this iteration has
// to be performed on the children and a lookahead has to be be done when to insert a boolean
// operator
List<List<IdentifiedEqualityContext>> oredAnds = new ArrayList<List<IdentifiedEqualityContext>>();
List<IdentifiedEqualityContext> currentAnd = new ArrayList<IdentifiedEqualityContext>();
oredAnds.add(currentAnd);
......@@ -293,42 +327,6 @@ public class AQL_2_Graph_Mapper extends System_2_Graph_Mapper {
}
}
// private QueryOperator getOutmostClauseDefiningAllAliases(Set<String> usedAliases,
// QueryOperator currentClause) {
// for (QueryOperator aChildClause : currentClause.getOperators()) {
// if (usedAliases.contains(aChildClause.alias)) {
// Set<String> reducedAliases = new HashSet<String>(usedAliases);
// reducedAliases.remove(aChildClause.alias);
// if (reducedAliases.isEmpty()) {
// // the currentClause is the wrapping filter of the alias defining iterator
// return currentClause;
// } else {
// QueryOperator filterClause = currentClause.getParameters().get(1).asOperator();
// return getOutmostClauseDefiningAllAliases(reducedAliases, filterClause);
// }
// }
// QueryOperator resultClause = getOutmostClauseDefiningAllAliases(usedAliases, aChildClause);
// if (resultClause != null) {
// return resultClause;
// }
// }
// return null;
// }
//
// private void moveOpToCorrectEncapsulatingClause(QueryOperator constrClause) {
// Set<String> usedAliases = new HashSet<String>();
// List<QueryOperator> aliasRefs = constrClause.getOpsRecursiveWithType(OperatorType.ALIAS_REF);
// for (QueryOperator anAliasRef : aliasRefs) {
// usedAliases.add(anAliasRef.getParameters().get(0).asPrimitive().value);
// }
// QueryOperator targetClause = getOutmostClauseDefiningAllAliases(usedAliases, root);
// if (targetClause == null) {
// throw new RuntimeException("there always has to be a match");
// }
// constrClause.parents.get(0).removeParameter(constrClause);
// targetClause.addParameter(constrClause);
// }
private void visitIdentifiedEquality(IdentifiedEqualityContext ctx) {
String prettyPrint = prettyPrint(ctx);
QueryOperator lastOp = currentOp;
......@@ -553,7 +551,8 @@ public class AQL_2_Graph_Mapper extends System_2_Graph_Mapper {
}
TerminalNode and = ctx.AND();
if (and != null) {
// don't create an AND. The boolean connection is created via nesting of the EXISTS
// don't create an AND. The boolean connection is created at the end of the parsing process
// via reshifting of clauses
}
if ((or != null) && (and != null)) {
throw new RuntimeException("there cannot be an OR and an AND in the same containsExpression");
......@@ -562,13 +561,21 @@ public class AQL_2_Graph_Mapper extends System_2_Graph_Mapper {
if (xor != null) {
throw new RuntimeException("not yet implemented");
}
ContainExpressionBoolContext containExpressionBool = ctx.containExpressionBool();
if (containExpressionBool != null) {
visitContainExpressionBool(containExpressionBool);
}
ContainsExpressionContext containsExpression = ctx.containsExpression();
if (containsExpression != null) {
visitContainsExpression(containsExpression);
}
ContainExpressionBoolContext containExpressionBool = ctx.containExpressionBool();
if (containExpressionBool != null) {
visitContainExpressionBool(containExpressionBool);
}
private void reverseParameters(QueryOperator anOp) {
List<Expression> reverse = Lists.reverse(anOp.getParameters());
for (Expression aChild : reverse) {
anOp.removeParameter(aChild);
anOp.addParameter(aChild);
}
}
......@@ -620,10 +627,8 @@ public class AQL_2_Graph_Mapper extends System_2_Graph_Mapper {
String text3 = archetypeid.getText();
String newElemName = text1 + "[" + text3 + "]";
QueryOperator existsOp = addOp(OperatorType.EXISTS);
QueryOperator aliasRef = addOp(OperatorType.ALIAS_REF);
aliasRef.addParameter(lastPathElem.alias);
QueryOperator newConcept = new QueryOperator(aliasRef.parent, aliasRef, newElemName,
OperatorType.FIELD_WITH_TYPE);
QueryOperator newConcept = new QueryOperator(existsOp, lastPathElem, newElemName,
OperatorType.FIELD_WITH_TYPE, true);
newConcept.alias = alias;
lastPathElem = newConcept;
currentOp = existsOp;
......
package de.uniwue.query.openEHR;
import java.util.List;