Skip to content

Commit

Permalink
Merge pull request #567 from openEHR/566_value_handler_dv_scale
Browse files Browse the repository at this point in the history
UpdateValueHandler: Take into account DvScale
  • Loading branch information
VeraPrinsen authored Feb 9, 2024
2 parents 5a83fa7 + 8fb58de commit 2008781
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 165 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@
import com.google.common.base.Strings;
import com.nedap.archie.ArchieLanguageConfiguration;
import com.nedap.archie.aom.*;
import com.nedap.archie.aom.primitives.CTerminologyCode;
import com.nedap.archie.aom.terminology.ArchetypeTerm;
import com.nedap.archie.aom.terminology.ArchetypeTerminology;
import com.nedap.archie.aom.utils.AOMUtils;
import com.nedap.archie.base.Interval;
import com.nedap.archie.paths.PathSegment;
import com.nedap.archie.query.APathQuery;
import com.nedap.archie.query.RMObjectWithPath;
import com.nedap.archie.query.RMPathQuery;
import com.nedap.archie.rm.archetyped.Archetyped;
import com.nedap.archie.rm.archetyped.Locatable;
import com.nedap.archie.rm.datatypes.CodePhrase;
import com.nedap.archie.rm.datavalues.DvCodedText;
import com.nedap.archie.rm.datavalues.quantity.DvOrdered;
import com.nedap.archie.rm.datavalues.quantity.DvOrdinal;
import com.nedap.archie.rm.datavalues.quantity.DvScale;
import com.nedap.archie.rm.support.identification.TerminologyId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -45,7 +45,7 @@ private static Map<String, Object> fixCodePhrase(Object rmObject, Archetype arch
if (pathOfParent.endsWith("value/defining_code") || pathOfParent.endsWith("null_flavour/defining_code")) {
return fixDvCodedText(rmObject, archetype, pathOfParent);
} else if (pathOfParent.endsWith("symbol/defining_code")) {
return fixDvOrdinal(rmObject, archetype, pathOfParent);
return fixDvOrdinalOrDvScale(rmObject, archetype, pathOfParent);
} else {
}
} catch (Exception e) {
Expand All @@ -55,12 +55,12 @@ private static Map<String, Object> fixCodePhrase(Object rmObject, Archetype arch
return new HashMap<>();
}

private static Map<String, Object> fixDvOrdinal(Object rmObject, Archetype archetype, String pathOfParent) throws XPathExpressionException {
private static Map<String, Object> fixDvOrdinalOrDvScale(Object rmObject, Archetype archetype, String pathOfParent) throws XPathExpressionException {
Map<String, Object> result = new HashMap<>();

RMPathQuery rmPathQuery = new RMPathQuery(pathOfParent.replace("/symbol/defining_code", ""));
DvOrdinal ordinal = rmPathQuery.find(ArchieRMInfoLookup.getInstance(), rmObject);
Long value = null;
DvOrdered ordered = rmPathQuery.find(ArchieRMInfoLookup.getInstance(), rmObject);
Number value;
CAttribute symbolAttribute = archetype.itemAtPath(pathOfParent.replace("/symbol/defining_code", "/symbol"));//TODO: remove all numeric indices from path!
if (symbolAttribute != null) {
CAttributeTuple socParent = (CAttributeTuple) symbolAttribute.getSocParent();
Expand All @@ -69,25 +69,30 @@ private static Map<String, Object> fixDvOrdinal(Object rmObject, Archetype arche
int symbolIndex = socParent.getMemberIndex("symbol");
if (valueIndex != -1 && symbolIndex != -1) {
for (CPrimitiveTuple tuple : socParent.getTuples()) {
if (tuple.getMembers().get(symbolIndex).getConstraint().get(0).equals(ordinal.getSymbol().getDefiningCode().getCodeString())) {
List<Interval<Long>> valueConstraint = (List<Interval<Long>>) tuple.getMembers().get(valueIndex).getConstraint();
if ((ordered instanceof DvOrdinal && tuple.getMembers().get(symbolIndex).getConstraint().get(0).equals(((DvOrdinal) ordered).getSymbol().getDefiningCode().getCodeString())) ||
ordered instanceof DvScale && tuple.getMembers().get(symbolIndex).getConstraint().get(0).equals(((DvScale) ordered).getSymbol().getDefiningCode().getCodeString())) {
List<Interval<Number>> valueConstraint = (List<Interval<Number>>) tuple.getMembers().get(valueIndex).getConstraint();
if(valueConstraint.size() == 1) {
Interval<Long> interval = valueConstraint.get(0);
Interval<Number> interval = valueConstraint.get(0);
if(interval.getLower().equals(interval.getUpper()) && !interval.isLowerUnbounded() && !interval.isUpperUnbounded()) {
value = interval.getLower();
ordinal.setValue(value);
if (ordered instanceof DvOrdinal) {
((DvOrdinal) ordered).setValue((Long) value);
} else {
((DvScale) ordered).setValue((Double) value);
}
String pathToValue = pathOfParent.replace("/symbol/defining_code", "/value");
result.put(pathToValue, value);
}

}
}
}

}
}
}
if(ordinal.getSymbol() != null && ordinal.getSymbol().getDefiningCode() != null) {

if ((ordered instanceof DvOrdinal && (((DvOrdinal) ordered).getSymbol() != null && ((DvOrdinal) ordered).getSymbol().getDefiningCode() != null)) ||
(ordered instanceof DvScale && (((DvScale) ordered).getSymbol() != null && ((DvScale) ordered).getSymbol().getDefiningCode() != null))) {
//also fix the DvCodedText inside the DvOrdinal
result.putAll(fixDvCodedText(rmObject, archetype, pathOfParent));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@

import com.nedap.archie.ArchieLanguageConfiguration;
import com.nedap.archie.adlparser.ADLParser;
import com.nedap.archie.adlparser.modelconstraints.RMConstraintImposer;
import com.nedap.archie.aom.Archetype;
import com.nedap.archie.creation.RMObjectCreator;
import com.nedap.archie.rm.archetyped.Locatable;
import com.nedap.archie.rm.archetyped.Pathable;
import com.nedap.archie.rm.datastructures.Cluster;
import com.nedap.archie.rm.datastructures.Element;
import com.nedap.archie.rm.datastructures.ItemTree;
import com.nedap.archie.rm.datavalues.DvBoolean;
import com.nedap.archie.rm.datavalues.DvText;
import com.nedap.archie.rminfo.ArchieRMInfoLookup;
import com.nedap.archie.testutil.TestUtil;
import com.nedap.archie.xml.JAXBUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
Expand Down Expand Up @@ -60,52 +57,73 @@ public void fixableMatches() throws Exception {
ItemTree itemTree = (ItemTree) root.itemAtPath("/data[id2]/events[id3]/data[id4]");

// Add a second cluster with the boolean set to true
Cluster cluster2 = new Cluster("id81", new DvText("Cluster"), new ArrayList<>());
Cluster cluster2 = new Cluster("id19", new DvText("Cluster"), new ArrayList<>());
DvBoolean dvBoolean = new DvBoolean();
dvBoolean.setValue(true);
cluster2.addItem(new Element("id82", new DvText("First element"), dvBoolean));
cluster2.addItem(new Element("id20", new DvText("First element"), dvBoolean));
itemTree.addItem(cluster2);

EvaluationResult evaluate = ruleEvaluation.evaluate(root, archetype.getRules().getRules());
assertEquals("There are eleven values that must be set", 11, evaluate.getSetPathValues().size());
assertEquals("There are eleven values that must be set", 16, evaluate.getSetPathValues().size());

//assert that paths must be set to specific values
// Assert that paths must be set to specific values
// DvText
assertEquals("test string", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id5]/value/value").getValue());
assertEquals("at1", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id6]/value/defining_code/code_string").getValue());
assertEquals("local", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id6]/value/defining_code/terminology_id/value").getValue());
assertEquals("Option 1", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id6]/value/value").getValue());
assertEquals("at6", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id7]/value/symbol/defining_code/code_string").getValue());
assertEquals("local", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id7]/value/symbol/defining_code/terminology_id/value").getValue());
assertEquals(0l, evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id7]/value/value").getValue());
assertEquals("at1", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id8]/null_flavour/defining_code/code_string").getValue());
assertEquals("local", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id8]/null_flavour/defining_code/terminology_id/value").getValue());
assertEquals("Option 1", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id8]/null_flavour/value").getValue());
assertEquals("The boolean is true", evaluate.getSetPathValues().get("/data[id2]/events[id3, 1]/data[id4]/items[id81, 6]/items[id84]/value/value").getValue());

//now assert that the RM Object cloned by rule evaluation has been modified with the new values for further evaluation
// DvCodedText
assertEquals("at10", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id7]/value/defining_code/code_string").getValue());
assertEquals("local", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id7]/value/defining_code/terminology_id/value").getValue());
assertEquals("Option 1", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id7]/value/value").getValue());
// DvOrdinal
assertEquals("at11", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id13]/value/symbol/defining_code/code_string").getValue());
assertEquals("local", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id13]/value/symbol/defining_code/terminology_id/value").getValue());
assertEquals(1l, evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id13]/value/value").getValue());
assertEquals("Option 2", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id13]/value/symbol/value").getValue());
// DvScale
assertEquals("at12", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id15]/value/symbol/defining_code/code_string").getValue());
assertEquals("local", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id15]/value/symbol/defining_code/terminology_id/value").getValue());
assertEquals(2.5, evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id15]/value/value").getValue());
assertEquals("Option 3", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id15]/value/symbol/value").getValue());
// DvCodedText with null flavour
assertEquals("at10", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id17]/null_flavour/defining_code/code_string").getValue());
assertEquals("local", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id17]/null_flavour/defining_code/terminology_id/value").getValue());
assertEquals("Option 1", evaluate.getSetPathValues().get("/data[id2]/events[id3]/data[id4]/items[id17]/null_flavour/value").getValue());
// DvText in Cluster
assertEquals("The boolean is true", evaluate.getSetPathValues().get("/data[id2]/events[id3, 1]/data[id4]/items[id19, 7]/items[id22]/value/value").getValue());

// Now assert that the RM Object cloned by rule evaluation has been modified with the new values for further evaluation
// DvText
assertEquals("test string", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id5]/value/value"));
assertEquals("at1", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id6]/value/defining_code/code_string"));
assertEquals("local", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id6]/value/defining_code/terminology_id/value"));
assertEquals("Option 1", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id6]/value/value"));
assertEquals("at6", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id7]/value/symbol/defining_code/code_string"));
assertEquals("local", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id7]/value/symbol/defining_code/terminology_id/value"));
assertEquals(0l, ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id7]/value/value"));
assertEquals("at1", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id8]/null_flavour/defining_code/code_string"));
assertEquals("local", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id8]/null_flavour/defining_code/terminology_id/value"));
assertEquals("Option 1", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id8]/null_flavour/value"));
assertEquals("The boolean is true", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3, 1]/data[id4]/items[id81, 6]/items[id84]/value/value"));

//and of course the DV_ORDINAL and DV_CODED_TEXT should be constructed correctly, with the correct numeric respectively a textual value
assertEquals(0l, ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id7]/value/value"));
assertEquals("Option 1", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id6]/value/value"));
assertEquals("Option 1", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id8]/null_flavour/value"));

// DvCodedText
assertEquals("at10", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id7]/value/defining_code/code_string"));
assertEquals("local", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id7]/value/defining_code/terminology_id/value"));
assertEquals("Option 1", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id7]/value/value"));
// DvOrdinal
assertEquals("at11", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id13]/value/symbol/defining_code/code_string"));
assertEquals("local", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id13]/value/symbol/defining_code/terminology_id/value"));
assertEquals(1l, ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id13]/value/value"));
// DvScale
assertEquals("at12", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id15]/value/symbol/defining_code/code_string"));
assertEquals("local", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id15]/value/symbol/defining_code/terminology_id/value"));
assertEquals(2.5, ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id15]/value/value"));
// DvCodedText with null flavour
assertEquals("at10", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id17]/null_flavour/defining_code/code_string"));
assertEquals("local", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id17]/null_flavour/defining_code/terminology_id/value"));
assertEquals("Option 1", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id17]/null_flavour/value"));
// DvText in Cluster
assertEquals("The boolean is true", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3, 1]/data[id4]/items[id19, 7]/items[id22]/value/value"));

// And of course the DV_CODED_TEXT, DV_ORDINAL and DV_SCALE should be constructed correctly, with the correct numeric respectively a textual value
assertEquals("Option 1", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id7]/value/value"));
assertEquals("Option 2", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id13]/value/symbol/value"));
assertEquals(1l, ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id13]/value/value"));
assertEquals("Option 3", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id15]/value/symbol/value"));
assertEquals(2.5, ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id15]/value/value"));
assertEquals("Option 1", ruleEvaluation.getRMRoot().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id17]/null_flavour/value"));

evaluate = ruleEvaluation.evaluate(ruleEvaluation.getRMRoot(), archetype.getRules().getRules());
for(AssertionResult result:evaluate.getAssertionResults()) {
assertTrue(result.getResult());
}

}

@Test
Expand Down
Loading

0 comments on commit 2008781

Please sign in to comment.