This commit is contained in:
jamesagnew 2018-03-03 17:50:29 -05:00
parent ecf570ced9
commit b2ceb87a70
5 changed files with 868 additions and 724 deletions

View File

@ -1,27 +1,59 @@
package org.hl7.fhir.r4.utils; package org.hl7.fhir.r4.utils;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum; import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.util.ElementUtil;
import org.fhir.ucum.Decimal;
import org.fhir.ucum.UcumException;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.PathEngineException;
import org.hl7.fhir.r4.conformance.ProfileUtilities; import org.hl7.fhir.r4.conformance.ProfileUtilities;
import org.hl7.fhir.r4.context.IWorkerContext; import org.hl7.fhir.r4.context.IWorkerContext;
import org.hl7.fhir.r4.model.*; import org.hl7.fhir.r4.elementmodel.Element;
import org.hl7.fhir.r4.elementmodel.ObjectConverter;
import org.hl7.fhir.r4.model.Base;
import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.DateTimeType;
import org.hl7.fhir.r4.model.DateType;
import org.hl7.fhir.r4.model.DecimalType;
import org.hl7.fhir.r4.model.ElementDefinition;
import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent; import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r4.model.ExpressionNode.*; import org.hl7.fhir.r4.model.ExpressionNode;
import org.hl7.fhir.r4.model.ExpressionNode.CollectionStatus;
import org.hl7.fhir.r4.model.ExpressionNode.Function;
import org.hl7.fhir.r4.model.ExpressionNode.Kind;
import org.hl7.fhir.r4.model.ExpressionNode.Operation;
import org.hl7.fhir.r4.model.ExpressionNode.SourceLocation;
import org.hl7.fhir.r4.model.IntegerType;
import org.hl7.fhir.r4.model.Property;
import org.hl7.fhir.r4.model.Resource;
import org.hl7.fhir.r4.model.StringType;
import org.hl7.fhir.r4.model.StructureDefinition;
import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind; import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule; import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule;
//import org.hl7.fhir.r4.model.TemporalPrecisionEnum;
import org.hl7.fhir.r4.model.TimeType;
import org.hl7.fhir.r4.model.TypeDetails;
import org.hl7.fhir.r4.model.ValueSet;
import org.hl7.fhir.r4.model.TypeDetails.ProfiledType; import org.hl7.fhir.r4.model.TypeDetails.ProfiledType;
import org.hl7.fhir.r4.utils.FHIRLexer.FHIRLexerException; import org.hl7.fhir.r4.utils.FHIRLexer.FHIRLexerException;
import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext.FunctionDetails; import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext.FunctionDetails;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.PathEngineException;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.fhir.ucum.Decimal;
import org.fhir.ucum.UcumException;
import java.math.BigDecimal; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import java.util.*; import ca.uhn.fhir.util.ElementUtil;
import static org.apache.commons.lang3.StringUtils.length;
/** /**
* *
@ -282,6 +314,21 @@ public class FHIRPathEngine {
return check(appContext, resourceType, context, parse(expr)); return check(appContext, resourceType, context, parse(expr));
} }
private int compareDateTimeElements(Base theL, Base theR) {
String dateLeftString = theL.primitiveValue();
if (length(dateLeftString) > 10) {
DateTimeType dateLeft = new DateTimeType(dateLeftString);
dateLeft.setTimeZoneZulu(true);
dateLeftString = dateLeft.getValueAsString();
}
String dateRightString = theR.primitiveValue();
if (length(dateRightString) > 10) {
DateTimeType dateRight = new DateTimeType(dateRightString);
dateRight.setTimeZoneZulu(true);
dateRightString = dateRight.getValueAsString();
}
return dateLeftString.compareTo(dateRightString);
}
/** /**
* evaluate a path and return the matching elements * evaluate a path and return the matching elements
@ -1191,6 +1238,8 @@ public class FHIRPathEngine {
result.addType("decimal"); result.addType("decimal");
return result; return result;
case Concatenate: case Concatenate:
result = new TypeDetails(CollectionStatus.SINGLETON, "");
return result;
case Plus: case Plus:
result = new TypeDetails(CollectionStatus.SINGLETON); result = new TypeDetails(CollectionStatus.SINGLETON);
if (left.hasType(worker, "integer") && right.hasType(worker, "integer")) if (left.hasType(worker, "integer") && right.hasType(worker, "integer"))
@ -1267,7 +1316,7 @@ public class FHIRPathEngine {
if (left.hasType("integer", "decimal", "unsignedInt", "positiveInt") && right.hasType("integer", "decimal", "unsignedInt", "positiveInt")) if (left.hasType("integer", "decimal", "unsignedInt", "positiveInt") && right.hasType("integer", "decimal", "unsignedInt", "positiveInt"))
return Utilities.equivalentNumber(left.primitiveValue(), right.primitiveValue()); return Utilities.equivalentNumber(left.primitiveValue(), right.primitiveValue());
if (left.hasType("date", "dateTime", "time", "instant") && right.hasType("date", "dateTime", "time", "instant")) if (left.hasType("date", "dateTime", "time", "instant") && right.hasType("date", "dateTime", "time", "instant"))
return Utilities.equivalentNumber(left.primitiveValue(), right.primitiveValue()); return compareDateTimeElements(left, right) == 0;
if (left.hasType("string", "id", "code", "uri") && right.hasType("string", "id", "code", "uri")) if (left.hasType("string", "id", "code", "uri") && right.hasType("string", "id", "code", "uri"))
return Utilities.equivalent(convertToString(left), convertToString(right)); return Utilities.equivalent(convertToString(left), convertToString(right));
@ -1324,8 +1373,8 @@ public class FHIRPathEngine {
return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) < 0); return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) < 0);
else if ((l.hasType("integer") || l.hasType("decimal")) && (r.hasType("integer") || r.hasType("decimal"))) else if ((l.hasType("integer") || l.hasType("decimal")) && (r.hasType("integer") || r.hasType("decimal")))
return makeBoolean(new Double(l.primitiveValue()) < new Double(r.primitiveValue())); return makeBoolean(new Double(l.primitiveValue()) < new Double(r.primitiveValue()));
else if ((l.hasType("date", "dateTime", "instant")) && (r.hasType("date", "dateTime", "instant"))) else if ((l.hasType("date", "dateTime", "instant")) && (r.hasType("date", "dateTime", "instant")))
return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) < 0); return makeBoolean(compareDateTimeElements(l, r) < 0);
else if ((l.hasType("time")) && (r.hasType("time"))) else if ((l.hasType("time")) && (r.hasType("time")))
return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) < 0); return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) < 0);
} else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) {
@ -1348,8 +1397,8 @@ public class FHIRPathEngine {
return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) > 0); return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) > 0);
else if ((l.hasType("integer", "decimal", "unsignedInt", "positiveInt")) && (r.hasType("integer", "decimal", "unsignedInt", "positiveInt"))) else if ((l.hasType("integer", "decimal", "unsignedInt", "positiveInt")) && (r.hasType("integer", "decimal", "unsignedInt", "positiveInt")))
return makeBoolean(new Double(l.primitiveValue()) > new Double(r.primitiveValue())); return makeBoolean(new Double(l.primitiveValue()) > new Double(r.primitiveValue()));
else if ((l.hasType("date", "dateTime", "instant")) && (r.hasType("date", "dateTime", "instant"))) else if ((l.hasType("date", "dateTime", "instant")) && (r.hasType("date", "dateTime", "instant")))
return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) > 0); return makeBoolean(compareDateTimeElements(l, r) > 0);
else if ((l.hasType("time")) && (r.hasType("time"))) else if ((l.hasType("time")) && (r.hasType("time")))
return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) > 0); return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) > 0);
} else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) {
@ -1372,8 +1421,8 @@ public class FHIRPathEngine {
return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) <= 0); return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) <= 0);
else if ((l.hasType("integer", "decimal", "unsignedInt", "positiveInt")) && (r.hasType("integer", "decimal", "unsignedInt", "positiveInt"))) else if ((l.hasType("integer", "decimal", "unsignedInt", "positiveInt")) && (r.hasType("integer", "decimal", "unsignedInt", "positiveInt")))
return makeBoolean(new Double(l.primitiveValue()) <= new Double(r.primitiveValue())); return makeBoolean(new Double(l.primitiveValue()) <= new Double(r.primitiveValue()));
else if ((l.hasType("date", "dateTime", "instant")) && (r.hasType("date", "dateTime", "instant"))) else if ((l.hasType("date", "dateTime", "instant")) && (r.hasType("date", "dateTime", "instant")))
return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) <= 0); return makeBoolean(compareDateTimeElements(l, r) <= 0);
else if ((l.hasType("time")) && (r.hasType("time"))) else if ((l.hasType("time")) && (r.hasType("time")))
return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) <= 0); return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) <= 0);
} else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) {
@ -1398,8 +1447,8 @@ public class FHIRPathEngine {
return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) >= 0); return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) >= 0);
else if ((l.hasType("integer", "decimal", "unsignedInt", "positiveInt")) && (r.hasType("integer", "decimal", "unsignedInt", "positiveInt"))) else if ((l.hasType("integer", "decimal", "unsignedInt", "positiveInt")) && (r.hasType("integer", "decimal", "unsignedInt", "positiveInt")))
return makeBoolean(new Double(l.primitiveValue()) >= new Double(r.primitiveValue())); return makeBoolean(new Double(l.primitiveValue()) >= new Double(r.primitiveValue()));
else if ((l.hasType("date", "dateTime", "instant")) && (r.hasType("date", "dateTime", "instant"))) else if ((l.hasType("date", "dateTime", "instant")) && (r.hasType("date", "dateTime", "instant")))
return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) >= 0); return makeBoolean(compareDateTimeElements(l, r) >= 0);
else if ((l.hasType("time")) && (r.hasType("time"))) else if ((l.hasType("time")) && (r.hasType("time")))
return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) >= 0); return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) >= 0);
} else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) {
@ -2209,8 +2258,34 @@ public class FHIRPathEngine {
} }
private List<Base> funcReplace(ExecutionContext context, List<Base> focus, ExpressionNode exp) { private List<Base> funcReplace(ExecutionContext context, List<Base> focus, ExpressionNode exp) throws FHIRException, PathEngineException {
throw new Error("not Implemented yet"); List<Base> result = new ArrayList<Base>();
if (focus.size() == 1) {
String f = convertToString(focus.get(0));
if (!Utilities.noString(f)) {
if (exp.getParameters().size() != 2) {
String t = convertToString(execute(context, focus, exp.getParameters().get(0), true));
String r = convertToString(execute(context, focus, exp.getParameters().get(1), true));
String n = f.replace(t, r);
result.add(new StringType(n));
}
else {
throw new PathEngineException(String.format("funcReplace() : checking for 2 arguments (pattern, substitution) but found %d items", exp.getParameters().size()));
}
}
else {
throw new PathEngineException(String.format("funcReplace() : checking for 1 string item but found empty item"));
}
}
else {
throw new PathEngineException(String.format("funcReplace() : checking for 1 string item but found %d items", focus.size()));
}
return result;
} }

View File

@ -1,6 +1,9 @@
package org.hl7.fhir.dstu3.hapi.validation; package org.hl7.fhir.dstu3.hapi.validation;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu2.composite.PeriodDt;
import ca.uhn.fhir.model.dstu2.valueset.ProcedureStatusEnum;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ResultSeverityEnum; import ca.uhn.fhir.validation.ResultSeverityEnum;
@ -64,6 +67,34 @@ public class FhirInstanceValidatorDstu3Test {
myValidConcepts.add(theSystem + "___" + theCode); myValidConcepts.add(theSystem + "___" + theCode);
} }
/**
* See #873
*/
@Test
public void testCompareTimesWithDifferentTimezones() {
Procedure procedure = new Procedure();
procedure.setStatus(Procedure.ProcedureStatus.COMPLETED);
procedure.getSubject().setReference("Patient/1");
procedure.getCode().setText("Some proc");
Period period = new Period();
period.setStartElement(new DateTimeType("2000-01-01T00:00:01+05:00"));
period.setEndElement(new DateTimeType("2000-01-01T00:00:00+04:00"));
assertThat(period.getStart().getTime(), lessThan(period.getEnd().getTime()));
procedure.setPerformed(period);
FhirValidator val = ourCtx.newValidator();
val.registerValidatorModule(new FhirInstanceValidator(myDefaultValidationSupport));
ValidationResult result = val.validateWithResult(procedure);
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome());
ourLog.info(encoded);
assertTrue(result.isSuccessful());
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Before @Before
public void before() { public void before() {

View File

@ -1,9 +1,13 @@
package org.hl7.fhir.instance.hapi.validation; package org.hl7.fhir.instance.hapi.validation;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu2.composite.PeriodDt;
import ca.uhn.fhir.model.dstu2.resource.Parameters; import ca.uhn.fhir.model.dstu2.resource.Parameters;
import ca.uhn.fhir.model.dstu2.resource.Patient; import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.resource.Procedure;
import ca.uhn.fhir.model.dstu2.valueset.ProcedureStatusEnum;
import ca.uhn.fhir.model.primitive.DateDt; import ca.uhn.fhir.model.primitive.DateDt;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;
@ -23,6 +27,7 @@ import org.junit.Test;
import java.io.IOException; import java.io.IOException;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.lessThan;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@ -49,34 +54,6 @@ public class FhirInstanceValidatorTest {
assertTrue(result.isSuccessful()); assertTrue(result.isSuccessful());
} }
/*
* {
"resourceType": "Observation",
"meta": {
"profile": [
"http://example.com/foo/bar/testValidateResourceContainingProfileDeclarationJson"
]
},
"identifier": [
{
"system": "http://acme",
"value": "12345"
}
],
"status": "final",
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "12345"
}
]
},
"encounter": {
"reference": "http://foo.com/Encounter/9"
}
}
*/
@Test @Test
public void testObservation() { public void testObservation() {
Observation o = new Observation(); Observation o = new Observation();
@ -97,6 +74,34 @@ public class FhirInstanceValidatorTest {
assertTrue(result.isSuccessful()); assertTrue(result.isSuccessful());
} }
/**
* See #873
*/
@Test
public void testCompareTimesWithDifferentTimezones() {
Procedure procedure = new Procedure();
procedure.setStatus(ProcedureStatusEnum.COMPLETED);
procedure.getSubject().setReference("Patient/1");
procedure.getCode().setText("Some proc");
PeriodDt period = new PeriodDt();
period.setStart(new DateTimeDt("2000-01-01T00:00:01+05:00"));
period.setEnd(new DateTimeDt("2000-01-01T00:00:00+04:00"));
assertThat(period.getStart().getTime(), lessThan(period.getEnd().getTime()));
procedure.setPerformed(period);
FhirValidator val = ourCtxDstu2.newValidator();
val.registerValidatorModule(ourValidator);
ValidationResult result = val.validateWithResult(procedure);
String encoded = ourCtxDstu2.newJsonParser().setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome());
ourLog.info(encoded);
assertTrue(result.isSuccessful());
}
@Test @Test
public void testParametersHl7OrgDstu2() { public void testParametersHl7OrgDstu2() {
org.hl7.fhir.instance.model.Patient patient = new org.hl7.fhir.instance.model.Patient(); org.hl7.fhir.instance.model.Patient patient = new org.hl7.fhir.instance.model.Patient();