Skip to content
This repository has been archived by the owner on Dec 21, 2022. It is now read-only.

#508,#552: Added support for profile validation in the retrieve #616

Merged
merged 2 commits into from
Sep 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ script:
before_cache:
- rm -rf $HOME/.m2/repository/org/opencds/cqf/cql
after_success:
- test $TRAVIS_BRANCH = "master" && test $TRAVIS_PULL_REQUEST = "false" && ./scripts/deploy.sh
- test ($TRAVIS_BRANCH = "master" || $TRAVIS_BRANCH = "v15") && test $TRAVIS_PULL_REQUEST = "false" && ./scripts/deploy.sh
deploy:
provider: releases
api_key:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,16 @@ protected Object resolveProperty(Object target, String path) {
return null;
}

// If the instance is a primitive (including (or even especially an enumeration), and it has no value, return null
if (child instanceof RuntimeChildPrimitiveDatatypeDefinition) {
IBase value = values.get(0);
if (value instanceof IPrimitiveType) {
if (!((IPrimitiveType<?>)value).hasValue()) {
return null;
}
}
}

if (child instanceof RuntimeChildChoiceDefinition && !child.getElementName().equalsIgnoreCase(path)) {
if (!values.get(0).getClass().getSimpleName()
.equalsIgnoreCase(child.getChildByName(path).getImplementingClass().getSimpleName())) {
Expand Down Expand Up @@ -630,6 +640,10 @@ public TemporalPrecisionEnum toTemporalPrecisionEnum(Precision precision) {
*/

public Object toJavaPrimitive(Object result, Object source) {
if (source instanceof IPrimitiveType<?> && !((IPrimitiveType<?>)source).hasValue()) {
return null;
}

String simpleName = source.getClass().getSimpleName();
switch (simpleName) {
case "InstantType":
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package org.opencds.cqf.cql.engine.fhir.retrieve;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.opencds.cqf.cql.engine.fhir.exception.UnknownElement;

import ca.uhn.fhir.rest.client.api.IGenericClient;
Expand All @@ -14,19 +16,25 @@ public class FhirBundleCursor implements Iterable<Object> {

public FhirBundleCursor(IGenericClient fhirClient, IBaseBundle results)
{
this(fhirClient, results, null);
this(fhirClient, results, null, null);
}

public FhirBundleCursor(IGenericClient fhirClient, IBaseBundle results, String dataType) { this(fhirClient, results, null, null); }

// This constructor filters the bundle based on dataType
public FhirBundleCursor(IGenericClient fhirClient, IBaseBundle results, String dataType) {
// If templateId is provided, this is a trusted cursor, meaning that it will only return results
// for resources that declare they conform to the given profile
public FhirBundleCursor(IGenericClient fhirClient, IBaseBundle results, String dataType, String templateId) {
this.fhirClient = fhirClient;
this.results = results;
this.dataType = dataType;
this.templateId = templateId;
}

private IGenericClient fhirClient;
private IBaseBundle results;
private String dataType;
private String templateId;


/**
Expand All @@ -35,15 +43,21 @@ public FhirBundleCursor(IGenericClient fhirClient, IBaseBundle results, String d
* @return an Iterator.
*/
public Iterator<Object> iterator() {
return new FhirBundleIterator(fhirClient, results, dataType);
return new FhirBundleIterator(fhirClient, results, dataType, templateId);
}

private class FhirBundleIterator implements Iterator<Object> {
public FhirBundleIterator(IGenericClient fhirClient, IBaseBundle results, String dataType) {
public FhirBundleIterator(IGenericClient fhirClient, IBaseBundle results, String dataType, String templateId) {
this.fhirClient = fhirClient;
this.results = results;
this.current = -1;
this.dataType = dataType;
this.templateId = templateId;

// Do not test templateId for base resource "profiles"
if (this.templateId != null && this.templateId.startsWith(String.format("http://hl7.org/fhir/StructureDefinition/%s", dataType))) {
this.templateId = null;
}

if (dataType != null) {
this.dataTypeClass = this.fhirClient.getFhirContext().getResourceDefinition(this.dataType).getImplementingClass();
Expand All @@ -56,6 +70,7 @@ public FhirBundleIterator(IGenericClient fhirClient, IBaseBundle results, String
private IBaseBundle results;
private int current;
private String dataType;
private String templateId;
private Class<? extends IBaseResource> dataTypeClass;
private List<? extends IBaseResource> currentEntry;

Expand All @@ -74,13 +89,33 @@ public boolean hasNext() {
private List<? extends IBaseResource> getEntry() {
if (this.dataTypeClass != null)
{
return BundleUtil.toListOfResourcesOfType(this.fhirClient.getFhirContext(), this.results, this.dataTypeClass);
List<? extends IBaseResource> entries = BundleUtil.toListOfResourcesOfType(this.fhirClient.getFhirContext(), this.results, this.dataTypeClass);
if (templateId != null) {
return getTrustedEntries(entries, templateId);
}
else {
return entries;
}
}
else {
return BundleUtil.toListOfResources(this.fhirClient.getFhirContext(), this.results);
}
}

private List<? extends IBaseResource> getTrustedEntries(List<? extends IBaseResource> entries, String templateId) {
List<IBaseResource> trustedEntries = new ArrayList<IBaseResource>();
for (IBaseResource entry : entries) {
if (entry.getMeta() != null && entry.getMeta().getProfile() != null) {
for (IPrimitiveType<?> profile : entry.getMeta().getProfile()) {
if (profile.hasValue() && profile.getValueAsString().equals(templateId)) {
trustedEntries.add(entry);
}
}
}
}
return trustedEntries;
}

private String getLink() {
return BundleUtil.getLinkUrlOfType(this.fhirClient.getFhirContext(), this.results, IBaseBundle.LINK_NEXT);
}
Expand All @@ -105,6 +140,7 @@ public Object next() {
}

// TODO: It would be possible to get here if the next link was present, but the returned page had 0 entries...
// NOTE: This is especially true if the page has only data that is not conformant to the given profile
throw new UnknownElement("The iteration has no more elements.");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@
import static org.testng.Assert.assertTrue;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;


import org.cqframework.cql.cql2elm.ModelManager;
import org.cqframework.cql.cql2elm.model.Model;
import org.hl7.elm.r1.VersionedIdentifier;
import org.hl7.elm_modelinfo.r1.ClassInfo;
import org.hl7.elm_modelinfo.r1.TypeInfo;
import org.hl7.fhir.dstu2.model.EnumFactory;
import org.hl7.fhir.dstu2.model.Enumeration;

import org.hl7.fhir.dstu2.model.*;
import org.hl7.fhir.dstu2.model.Enumerations.AdministrativeGender;
import org.hl7.fhir.dstu2.model.Enumerations.AgeUnits;
import org.hl7.fhir.dstu2.model.Enumerations.BindingStrength;
Expand All @@ -29,7 +31,6 @@
import org.hl7.fhir.dstu2.model.Enumerations.ResourceType;
import org.hl7.fhir.dstu2.model.Enumerations.SearchParamType;
import org.hl7.fhir.dstu2.model.Enumerations.SpecialValues;
import org.hl7.fhir.dstu2.model.Patient;
import org.opencds.cqf.cql.engine.fhir.exception.UnknownType;
import org.opencds.cqf.cql.engine.model.ModelResolver;
import org.testng.annotations.Test;
Expand Down Expand Up @@ -232,4 +233,28 @@ public void resolveMissingPropertyReturnsNull() {
Object result = resolver.resolvePath(p, "not-a-path");
assertNull(result);
}


//@Test
public void resolveNullEnumerationReturnsNull() {
FhirModelResolver<Base,?,?,SimpleQuantity,?,?,?,?> resolver = new Dstu2FhirModelResolver();

Quantity q = new Quantity();
q.setValue(new BigDecimal("10.0"));
q.setUnit("1");
SimpleQuantity sq = resolver.castToSimpleQuantity(q);

Object result = resolver.resolvePath(sq, "comparator");
assertNull(result);
}

//@Test
public void resolveNullPrimitiveReturnsNull() {
FhirModelResolver<Base,BaseDateTimeType,?,?,?,?,?,?> resolver = new Dstu2FhirModelResolver();

DateTimeType dt = new DateTimeType();

Object result = resolver.resolvePath(dt, "value");
assertNull(result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

Expand All @@ -12,7 +13,7 @@
import org.hl7.elm.r1.VersionedIdentifier;
import org.hl7.elm_modelinfo.r1.ClassInfo;
import org.hl7.elm_modelinfo.r1.TypeInfo;
import org.hl7.fhir.dstu3.model.Enumeration;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.Enumerations.AbstractType;
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
import org.hl7.fhir.dstu3.model.Enumerations.AgeUnits;
Expand All @@ -30,7 +31,6 @@
import org.hl7.fhir.dstu3.model.Enumerations.ResourceType;
import org.hl7.fhir.dstu3.model.Enumerations.SearchParamType;
import org.hl7.fhir.dstu3.model.Enumerations.SpecialValues;
import org.hl7.fhir.dstu3.model.Patient;
import org.opencds.cqf.cql.engine.fhir.exception.UnknownType;
import org.opencds.cqf.cql.engine.model.ModelResolver;
import org.testng.annotations.Test;
Expand Down Expand Up @@ -262,4 +262,27 @@ public void resolveMissingPropertyReturnsNull() {
Object result = resolver.resolvePath(p, "not-a-path");
assertNull(result);
}

@Test
public void resolveNullEnumerationReturnsNull() {
FhirModelResolver<Base,?,?,SimpleQuantity,?,?,?,?> resolver = new Dstu3FhirModelResolver();

Quantity q = new Quantity();
q.setValue(new BigDecimal("10.0"));
q.setUnit("1");
SimpleQuantity sq = resolver.castToSimpleQuantity(q);

Object result = resolver.resolvePath(sq, "comparator");
assertNull(result);
}

@Test
public void resolveNullPrimitiveReturnsNull() {
FhirModelResolver<Base,BaseDateTimeType,?,?,?,?,?,?> resolver = new Dstu3FhirModelResolver();

DateTimeType dt = new DateTimeType();

Object result = resolver.resolvePath(dt, "value");
assertNull(result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
Expand All @@ -16,8 +17,7 @@
import org.hl7.elm.r1.VersionedIdentifier;
import org.hl7.elm_modelinfo.r1.ClassInfo;
import org.hl7.elm_modelinfo.r1.TypeInfo;
import org.hl7.fhir.r4.model.DateTimeType;
import org.hl7.fhir.r4.model.Enumeration;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.Enumerations.AbstractType;
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
import org.hl7.fhir.r4.model.Enumerations.AgeUnits;
Expand All @@ -40,9 +40,6 @@
import org.hl7.fhir.r4.model.Enumerations.ResourceType;
import org.hl7.fhir.r4.model.Enumerations.SearchParamType;
import org.hl7.fhir.r4.model.Enumerations.SpecialValues;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.VisionPrescription;
import org.opencds.cqf.cql.engine.fhir.exception.UnknownType;
import org.opencds.cqf.cql.engine.model.ModelResolver;
import org.testng.annotations.Test;
Expand Down Expand Up @@ -164,7 +161,7 @@ public void modelInfoSpecialCaseTests() {
public void modelInfo400Tests() {
ModelResolver resolver = new R4FhirModelResolver();
ModelManager mm = new ModelManager();
Model m = mm.resolveModel(new VersionedIdentifier().withId("FHIR").withVersion("4.0.0"));
Model m = mm.resolveModel(new VersionedIdentifier().withId("FHIR").withVersion("4.0.1"));

List<TypeInfo> typeInfos = m.getModelInfo().getTypeInfo();

Expand Down Expand Up @@ -378,4 +375,27 @@ public void resolveDateTimeProviderReturnsDate() {
assertNotNull(result);
assertThat(result, is(dateTimeType));
}

@Test
public void resolveNullEnumerationReturnsNull() {
FhirModelResolver<Base,?,?,SimpleQuantity,?,?,?,?> resolver = new R4FhirModelResolver();

Quantity q = new Quantity();
q.setValue(new BigDecimal("10.0"));
q.setUnit("1");
SimpleQuantity sq = resolver.castToSimpleQuantity(q);

Object result = resolver.resolvePath(sq, "comparator");
assertNull(result);
}

@Test
public void resolveNullPrimitiveReturnsNull() {
FhirModelResolver<Base,BaseDateTimeType,?,?,?,?,?,?> resolver = new R4FhirModelResolver();

DateTimeType dt = new DateTimeType();

Object result = resolver.resolvePath(dt, "value");
assertNull(result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ private Field getProperty(Class<?> clazz, String path) {
Field field = clazz.getDeclaredField(path);
return field;
} catch (NoSuchFieldException e) {
if (clazz.getSuperclass() != null) {
Field field = getProperty(clazz.getSuperclass(), path);
return field;
}
throw new IllegalArgumentException(String.format("Could not determine field for path %s of type %s", path, clazz.getSimpleName()));
}
}
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<jackson.version>2.13.2</jackson.version>
<jackson-databind.version>2.13.2.1</jackson-databind.version>
<cqframework.version>1.5.11</cqframework.version>
<cqframework.version>1.5.12-SNAPSHOT</cqframework.version>
<hapi.version>5.6.3</hapi.version>
<slf4j.version>1.7.29</slf4j.version>
</properties>
Expand Down
4 changes: 2 additions & 2 deletions scripts/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
set -euxo pipefail
bash -n "$0"

if [[ "$TRAVIS_BRANCH" != "master" && -z "$TRAVIS_TAG" ]]
if [[ "$TRAVIS_BRANCH" != "master" && "$TRAVIS_BRANCH" != "v15" && -z "$TRAVIS_TAG" ]]
then
echo "Not on the master branch or a git tag. Skipping deploy."
echo "Not on the master or v15 branches or a git tag. Skipping deploy."
exit 0
fi

Expand Down