Skip to content

Commit

Permalink
issue #679 - added FHIRPath Patch spec tests
Browse files Browse the repository at this point in the history
1. Added FHIRPathSpecTest for executing the spec-provided
FHIRPath Patch test cases. I needed to tweak the test file to work
around our strict interpretation of `ele-1`
which makes empty resources invalid.
I also removed a single fhirpath patch operation from the
`Full Resource` testcase...we currently cannot handle replace of
DomainResource.text.div

2. Added logic to throw UnsupportedOperationException for patches
with nested part values and added corresponding skip logic from the test

3. Added skip logic for 2 other test cases, both with `mode=forwards`
* `Delete Nested Primitive #2`: this test expects that the server will
automatically remove a parent elements when the last element from within
one is removed. We don't do that.
* `Reorder List #4`: on this one, I disagree with the expected output

4. Found and fixed an issue with the original implementation;
patch values for code subtypes come is as basic Code types whereas the
setters expect a subtype, so I needed to add logic to convert the Code
to the appropriate subtype before calling any setters.

Finally, I added the FHIR mimetypes to the patchFormat element of our
CapabilityStatement to indicate that we now support FHIRPath patch.

Signed-off-by: Lee Surprenant <[email protected]>
  • Loading branch information
lmsurpre committed Feb 5, 2020
1 parent 841ec44 commit 4b92b56
Show file tree
Hide file tree
Showing 10 changed files with 1,805 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.ibm.fhir.model.resource.Bundle;
import com.ibm.fhir.model.resource.Parameters;
import com.ibm.fhir.model.resource.Resource;
import com.ibm.fhir.model.type.Code;
import com.ibm.fhir.model.type.Element;
import com.ibm.fhir.model.util.ModelSupport;

Expand Down Expand Up @@ -245,6 +246,21 @@ protected void markListDirty() {
listStack.peek().dirty(true);
}

protected Code convertToCodeSubtype(Visitable parent, String elementName, Code value) {
Class<?> targetType = ModelSupport.getElementType(parent.getClass(), elementName);
if (value.getClass() != targetType) {
MethodType mt = MethodType.methodType(targetType, String.class);
try {
MethodHandle methodHandle = MethodHandles.publicLookup().findStatic(targetType, "of", mt);
value = (Code) methodHandle.invoke(((Code)value).getValue());
} catch (Throwable e) {
throw new IllegalArgumentException("Value of type '" + value.getClass() +
"' cannot be used to populate target of type '" + targetType + "'");
}
}
return value;
}

private abstract class Markable {
private boolean dirty = false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ public static FHIRPathPatchOperation parse(Parameter operation) {
foundName = true;
break;
case VALUE:
if (part.getValue() == null) {
throw new UnsupportedOperationException("Nested value patches are not yet supported");
}
value = validatePartAndGetValue(foundValue, part, Element.class);
foundValue = true;
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.Stack;

import com.ibm.fhir.model.resource.Resource;
import com.ibm.fhir.model.type.Code;
import com.ibm.fhir.model.type.Element;
import com.ibm.fhir.model.util.ModelSupport;
import com.ibm.fhir.model.visitor.CopyingVisitor;
Expand All @@ -30,7 +31,8 @@ public AddingVisitor(Visitable parent, String elementName, Visitable value) {
this.visitStack = new Stack<Visitable>();
this.parent = parent;
this.elementNameToAdd = elementName;
this.value = value;
this.value = value instanceof Code ?
convertToCodeSubtype(parent, elementName, (Code)value) : value;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ public static <T extends Visitable> T add(T elementOrResource, String fhirPath,
Visitable parent = node.isResourceNode() ?
node.asResourceNode().resource() : node.asElementNode().element();

AddingVisitor<T> addingVisitor = new AddingVisitor<T>(parent, elementName, value);
AddingVisitor<T> addingVisitor = new AddingVisitor<>(parent, elementName, value);

try {
elementOrResource.accept(addingVisitor);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.Stack;

import com.ibm.fhir.model.resource.Resource;
import com.ibm.fhir.model.type.Code;
import com.ibm.fhir.model.type.Element;
import com.ibm.fhir.model.visitor.CopyingVisitor;
import com.ibm.fhir.model.visitor.Visitable;
Expand All @@ -32,7 +33,8 @@ public InsertingVisitor(Visitable parent, String elementName, int index, Visitab
this.parent = parent;
this.elementName = elementName;
this.index = index;
this.value = value;
this.value = value instanceof Code ?
convertToCodeSubtype(parent, elementName, (Code)value) : value;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.Stack;

import com.ibm.fhir.model.resource.Resource;
import com.ibm.fhir.model.type.Code;
import com.ibm.fhir.model.type.Element;
import com.ibm.fhir.model.util.ModelSupport;
import com.ibm.fhir.model.visitor.CopyingVisitor;
Expand All @@ -32,7 +33,8 @@ public ReplacingVisitor(Visitable parent, String elementName, Visitable oldValue
this.parent = parent;
this.elementNameToReplace = elementName;
this.oldValue = oldValue;
this.newValue = newValue;
this.newValue = newValue instanceof Code ?
convertToCodeSubtype(parent, elementName, (Code)newValue) : newValue;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* (C) Copyright IBM Corp. 2019
* (C) Copyright IBM Corp. 2019, 2020
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -47,7 +47,7 @@

/**
* Executes all the FHIRPath tests shipped with the FHIRPath specification
* @see <a href="http://build.fhir.org/ig/HL7/FHIRPath/branches/master/N1/tests.html">http://build.fhir.org/ig/HL7/FHIRPath/branches/master/N1/tests.html</a>
* @see <a href="http://hl7.org/fhirpath/N1/tests.html">http://hl7.org/fhirpath/N1/tests.html</a>
*/
public class FHIRPathSpecTest implements ITest {
protected final FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator();
Expand Down Expand Up @@ -303,14 +303,14 @@ public static void main(String[] args) throws Exception {
FHIRPathEvaluator.DEBUG = true;
FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator();
Collection<FHIRPathNode> result = evaluator.evaluate(patient, "Patient.active.type().name = 'boolean'");
System.out.println("result: " + result);
System.out.println("result: " + result);
}
try (InputStream in = FHIRPathSpecTest.class.getClassLoader().getResourceAsStream("FHIRPath/input/observation-example.xml")) {
Observation observation = FHIRParser.parser(Format.XML).parse(in);
FHIRPathEvaluator.DEBUG = true;
FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator();
Collection<FHIRPathNode> result = evaluator.evaluate(observation, "(Observation.value as Period).unit");
System.out.println("result: " + result);
System.out.println("result: " + result);
}
}
}
2 changes: 2 additions & 0 deletions fhir-path/src/test/resources/fhir-path-patch-tests.CHANGELOG
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
To workaround global-1 I added a Resource.id to all FHIR Resources in the file (except the "Full Resource" test case which already had one)
I commented out the Patient.text.div replace operation in the test case Full Resource
Loading

0 comments on commit 4b92b56

Please sign in to comment.