Merge branch 'master' of github.com:jamesagnew/hapi-fhir
This commit is contained in:
commit
ea49692106
|
@ -20,21 +20,20 @@ package ca.uhn.fhir.model.primitive;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import ca.uhn.fhir.model.api.BasePrimitive;
|
||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.apache.commons.lang3.time.FastDateFormat;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.apache.commons.lang3.time.FastDateFormat;
|
||||
|
||||
import ca.uhn.fhir.model.api.BasePrimitive;
|
||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
||||
static final long NANOS_PER_MILLIS = 1000000L;
|
||||
|
@ -42,7 +41,8 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
|
||||
private static final FastDateFormat ourHumanDateFormat = FastDateFormat.getDateInstance(FastDateFormat.MEDIUM);
|
||||
private static final FastDateFormat ourHumanDateTimeFormat = FastDateFormat.getDateTimeInstance(FastDateFormat.MEDIUM, FastDateFormat.MEDIUM);
|
||||
|
||||
private static final FastDateFormat ourXmlDateTimeFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss");
|
||||
public static final String NOW_DATE_CONSTANT = "%now";
|
||||
private String myFractionalSeconds;
|
||||
private TemporalPrecisionEnum myPrecision = null;
|
||||
private TimeZone myTimeZone;
|
||||
|
@ -635,8 +635,13 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
@Override
|
||||
public void setValueAsString(String theValue) throws DataFormatException {
|
||||
clearTimeZone();
|
||||
|
||||
if (NOW_DATE_CONSTANT.equalsIgnoreCase(theValue)) {
|
||||
super.setValueAsString(ourXmlDateTimeFormat.format(new Date()));
|
||||
} else {
|
||||
super.setValueAsString(theValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the year, e.g. 2015
|
||||
|
|
|
@ -47,7 +47,7 @@ public abstract class BaseParamWithPrefix<T extends BaseParam> extends BaseParam
|
|||
break;
|
||||
} else {
|
||||
char nextChar = theString.charAt(offset);
|
||||
if (nextChar == '-' || Character.isDigit(nextChar)) {
|
||||
if (nextChar == '-' || nextChar == '%' || Character.isDigit(nextChar)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -313,7 +313,7 @@ public class ConsentInterceptorResourceProviderR4Test extends BaseResourceProvid
|
|||
patient.setActive(true);
|
||||
|
||||
// Reject output
|
||||
consentService.setTarget(new ConsentSvcRejectSeeingAnything());
|
||||
consentService.setTarget(new ConsentSvcRejectCanSeeAnything());
|
||||
HttpPost post = new HttpPost(ourServerBase + "/Patient");
|
||||
post.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RETURN + '=' + Constants.HEADER_PREFER_RETURN_REPRESENTATION);
|
||||
post.setEntity(toEntity(patient));
|
||||
|
@ -356,7 +356,7 @@ public class ConsentInterceptorResourceProviderR4Test extends BaseResourceProvid
|
|||
ourRestServer.getInterceptorService().registerInterceptor(myConsentInterceptor);
|
||||
|
||||
// Reject output
|
||||
consentService.setTarget(new ConsentSvcRejectSeeingAnything());
|
||||
consentService.setTarget(new ConsentSvcRejectCanSeeAnything());
|
||||
patient = new Patient();
|
||||
patient.setId(id);
|
||||
patient.setActive(true);
|
||||
|
@ -394,6 +394,32 @@ public class ConsentInterceptorResourceProviderR4Test extends BaseResourceProvid
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRejectWillSeeResource() throws IOException {
|
||||
create50Observations();
|
||||
|
||||
ConsentSvcRejectWillSeeEvenNumbered consentService = new ConsentSvcRejectWillSeeEvenNumbered();
|
||||
myConsentInterceptor = new ConsentInterceptor(consentService, IConsentContextServices.NULL_IMPL);
|
||||
ourRestServer.getInterceptorService().registerInterceptor(myConsentInterceptor);
|
||||
|
||||
// Search for all
|
||||
String url = ourServerBase + "/Observation?_pretty=true&_count=10";
|
||||
ourLog.info("HTTP GET {}", url);
|
||||
HttpGet get = new HttpGet(url);
|
||||
get.addHeader(Constants.HEADER_ACCEPT, Constants.CT_JSON);
|
||||
try (CloseableHttpResponse status = ourHttpClient.execute(get)) {
|
||||
String responseString = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
|
||||
ourLog.info("Response: {}", responseString);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
Bundle result = myFhirCtx.newJsonParser().parseResource(Bundle.class, responseString);
|
||||
List<IBaseResource> resources = BundleUtil.toListOfResources(myFhirCtx, result);
|
||||
List<String> returnedIdValues = toUnqualifiedVersionlessIdValues(resources);
|
||||
assertEquals(myObservationIdsOddOnly.subList(0, 5), returnedIdValues);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGraphQL_Proceed() throws IOException {
|
||||
createPatientAndOrg();
|
||||
|
@ -727,7 +753,7 @@ public class ConsentInterceptorResourceProviderR4Test extends BaseResourceProvid
|
|||
|
||||
}
|
||||
|
||||
private static class ConsentSvcRejectSeeingAnything implements IConsentService {
|
||||
private static class ConsentSvcRejectCanSeeAnything implements IConsentService {
|
||||
|
||||
@Override
|
||||
public ConsentOutcome startOperation(RequestDetails theRequestDetails, IConsentContextServices theContextServices) {
|
||||
|
@ -756,4 +782,43 @@ public class ConsentInterceptorResourceProviderR4Test extends BaseResourceProvid
|
|||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static class ConsentSvcRejectWillSeeEvenNumbered implements IConsentService {
|
||||
|
||||
@Override
|
||||
public ConsentOutcome startOperation(RequestDetails theRequestDetails, IConsentContextServices theContextServices) {
|
||||
return ConsentOutcome.PROCEED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConsentOutcome canSeeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) {
|
||||
return ConsentOutcome.PROCEED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConsentOutcome willSeeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) {
|
||||
if (theResource.getIdElement().isIdPartValidLong()) {
|
||||
Long resIdLong = theResource.getIdElement().getIdPartAsLong();
|
||||
if (resIdLong % 2 == 0) {
|
||||
return new ConsentOutcome(ConsentOperationStatusEnum.REJECT);
|
||||
}
|
||||
}
|
||||
return new ConsentOutcome(ConsentOperationStatusEnum.PROCEED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completeOperationSuccess(RequestDetails theRequestDetails, IConsentContextServices theContextServices) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completeOperationFailure(RequestDetails theRequestDetails, BaseServerResponseException theException, IConsentContextServices theContextServices) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,11 @@ import ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl;
|
|||
import ca.uhn.fhir.jpa.util.TestUtil;
|
||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r5.model.Bundle;
|
||||
import org.hl7.fhir.r5.model.DateTimeType;
|
||||
import org.hl7.fhir.r5.model.Observation;
|
||||
import org.hl7.fhir.r5.model.Patient;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
|
@ -84,6 +88,20 @@ public class ResourceProviderR5Test extends BaseResourceProviderR5Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateNowSyntax() {
|
||||
Observation observation = new Observation();
|
||||
observation.setEffective(new DateTimeType("1965-08-09"));
|
||||
IIdType oid = myObservationDao.create(observation).getId().toUnqualified();
|
||||
String nowParam = UrlUtil.escapeUrlParam("%now");
|
||||
Bundle output = ourClient
|
||||
.search()
|
||||
.byUrl("Observation?date=lt" + nowParam)
|
||||
.returnBundle(Bundle.class)
|
||||
.execute();
|
||||
List<IIdType> ids = output.getEntry().stream().map(t -> t.getResource().getIdElement().toUnqualified()).collect(Collectors.toList());
|
||||
assertThat(ids, containsInAnyOrder(oid));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
|
|
|
@ -107,6 +107,16 @@
|
|||
<artifactId>logback-classic</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
|
|
@ -23,7 +23,6 @@ package ca.uhn.fhir.jpa.searchparam.matcher;
|
|||
public class InMemoryMatchResult {
|
||||
public static final String PARSE_FAIL = "Failed to translate parse query string";
|
||||
public static final String STANDARD_PARAMETER = "Standard parameters not supported";
|
||||
public static final String PREFIX = "Prefixes not supported";
|
||||
public static final String CHAIN = "Chained references are not supported";
|
||||
public static final String PARAM = "Param not supported";
|
||||
|
||||
|
|
|
@ -29,7 +29,9 @@ import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParams;
|
|||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||
import ca.uhn.fhir.rest.param.BaseParamWithPrefix;
|
||||
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
|
||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
@ -42,7 +44,6 @@ import org.springframework.stereotype.Service;
|
|||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Service
|
||||
public class InMemoryResourceMatcher {
|
||||
|
@ -57,11 +58,10 @@ public class InMemoryResourceMatcher {
|
|||
/**
|
||||
* This method is called in two different scenarios. With a null theResource, it determines whether database matching might be required.
|
||||
* Otherwise, it tries to perform the match in-memory, returning UNSUPPORTED if it's not possible.
|
||||
*
|
||||
* <p>
|
||||
* Note that there will be cases where it returns UNSUPPORTED with a null resource, but when a non-null resource it returns supported and no match.
|
||||
* This is because an earlier parameter may be matchable in-memory in which case processing stops and we never get to the parameter
|
||||
* that would have required a database call.
|
||||
*
|
||||
*/
|
||||
|
||||
public InMemoryMatchResult match(String theCriteria, IBaseResource theResource, ResourceIndexedSearchParams theSearchParams) {
|
||||
|
@ -102,14 +102,18 @@ public class InMemoryResourceMatcher {
|
|||
if (hasQualifiers(theAndOrParams)) {
|
||||
return InMemoryMatchResult.unsupportedFromParameterAndReason(theParamName, InMemoryMatchResult.STANDARD_PARAMETER);
|
||||
}
|
||||
if (hasPrefixes(theAndOrParams)) {
|
||||
|
||||
return InMemoryMatchResult.unsupportedFromParameterAndReason(theParamName, InMemoryMatchResult.PREFIX);
|
||||
|
||||
}
|
||||
if (hasChain(theAndOrParams)) {
|
||||
return InMemoryMatchResult.unsupportedFromParameterAndReason(theParamName, InMemoryMatchResult.CHAIN);
|
||||
}
|
||||
|
||||
String resourceName = theResourceDefinition.getName();
|
||||
RuntimeSearchParam paramDef = mySearchParamRegistry.getActiveSearchParam(resourceName, theParamName);
|
||||
InMemoryMatchResult checkUnsupportedResult = checkUnsupportedPrefixes(theParamName, paramDef, theAndOrParams);
|
||||
if (!checkUnsupportedResult.supported()) {
|
||||
return checkUnsupportedResult;
|
||||
}
|
||||
|
||||
switch (theParamName) {
|
||||
case IAnyResource.SP_RES_ID:
|
||||
|
||||
|
@ -125,8 +129,7 @@ public class InMemoryResourceMatcher {
|
|||
|
||||
default:
|
||||
|
||||
String resourceName = theResourceDefinition.getName();
|
||||
RuntimeSearchParam paramDef = mySearchParamRegistry.getActiveSearchParam(resourceName, theParamName);
|
||||
|
||||
return matchResourceParam(theParamName, theAndOrParams, theSearchParams, resourceName, paramDef);
|
||||
}
|
||||
}
|
||||
|
@ -137,6 +140,7 @@ public class InMemoryResourceMatcher {
|
|||
}
|
||||
return theAndOrParams.stream().allMatch(nextAnd -> matchIdsOr(nextAnd, theResource));
|
||||
}
|
||||
|
||||
private boolean matchIdsOr(List<IQueryParameterType> theOrParams, IBaseResource theResource) {
|
||||
if (theResource == null) {
|
||||
return true;
|
||||
|
@ -190,9 +194,41 @@ public class InMemoryResourceMatcher {
|
|||
return theAndOrParams.stream().flatMap(List::stream).anyMatch(param -> param.getQueryParameterQualifier() != null);
|
||||
}
|
||||
|
||||
private boolean hasPrefixes(List<List<IQueryParameterType>> theAndOrParams) {
|
||||
Predicate<IQueryParameterType> hasPrefixPredicate = param -> param instanceof BaseParamWithPrefix &&
|
||||
((BaseParamWithPrefix) param).getPrefix() != null;
|
||||
return theAndOrParams.stream().flatMap(List::stream).anyMatch(hasPrefixPredicate);
|
||||
private InMemoryMatchResult checkUnsupportedPrefixes(String theParamName, RuntimeSearchParam theParamDef, List<List<IQueryParameterType>> theAndOrParams) {
|
||||
if (theParamDef != null) {
|
||||
for (List<IQueryParameterType> theAndOrParam : theAndOrParams) {
|
||||
for (IQueryParameterType param : theAndOrParam) {
|
||||
if (param instanceof BaseParamWithPrefix) {
|
||||
ParamPrefixEnum prefix = ((BaseParamWithPrefix) param).getPrefix();
|
||||
RestSearchParameterTypeEnum paramType = theParamDef.getParamType();
|
||||
if (!supportedPrefix(prefix, paramType)) {
|
||||
return InMemoryMatchResult.unsupportedFromParameterAndReason(theParamName, String.format("The prefix %s is not supported for param type %s", prefix, paramType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return InMemoryMatchResult.successfulMatch();
|
||||
}
|
||||
|
||||
private boolean supportedPrefix(ParamPrefixEnum theParam, RestSearchParameterTypeEnum theParamType) {
|
||||
if (theParam == null || theParamType == null) {
|
||||
return true;
|
||||
}
|
||||
switch (theParamType) {
|
||||
case DATE:
|
||||
switch (theParam) {
|
||||
case GREATERTHAN:
|
||||
case GREATERTHAN_OR_EQUALS:
|
||||
case LESSTHAN:
|
||||
case LESSTHAN_OR_EQUALS:
|
||||
case EQUAL:
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
package ca.uhn.fhir.jpa.searchparam.matcher;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParams;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.model.primitive.BaseDateTimeDt;
|
||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
|
||||
import org.hl7.fhir.r5.model.BaseDateTimeType;
|
||||
import org.hl7.fhir.r5.model.DateTimeType;
|
||||
import org.hl7.fhir.r5.model.Observation;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
public class InMemoryResourceMatcherR5Test {
|
||||
public static final String OBSERVATION_DATE = "1970-10-17";
|
||||
private static final String EARLY_DATE = "1965-08-09";
|
||||
private static final String LATE_DATE = "2000-06-29";
|
||||
|
||||
@Autowired
|
||||
private
|
||||
InMemoryResourceMatcher myInMemoryResourceMatcher;
|
||||
|
||||
@MockBean
|
||||
ISearchParamRegistry mySearchParamRegistry;
|
||||
private Observation myObservation;
|
||||
private ResourceIndexedSearchParams mySearchParams;
|
||||
|
||||
@Configuration
|
||||
public static class SpringConfig {
|
||||
@Bean
|
||||
InMemoryResourceMatcher inMemoryResourceMatcher() {
|
||||
return new InMemoryResourceMatcher();
|
||||
}
|
||||
|
||||
@Bean
|
||||
MatchUrlService matchUrlService() {
|
||||
return new MatchUrlService();
|
||||
}
|
||||
|
||||
@Bean
|
||||
FhirContext fhirContext() {
|
||||
return FhirContext.forR5();
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
RuntimeSearchParam searchParams = new RuntimeSearchParam(null, null, null, null, "Observation.effective", RestSearchParameterTypeEnum.DATE, null, null, null, RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE);
|
||||
when(mySearchParamRegistry.getSearchParamByName(any(), any())).thenReturn(searchParams);
|
||||
when(mySearchParamRegistry.getActiveSearchParam("Observation", "date")).thenReturn(searchParams);
|
||||
myObservation = new Observation();
|
||||
myObservation.setEffective(new DateTimeType(OBSERVATION_DATE));
|
||||
mySearchParams = extractDateSearchParam(myObservation);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDateUnsupportedOps() {
|
||||
testDateUnsupportedOp(ParamPrefixEnum.APPROXIMATE);
|
||||
testDateUnsupportedOp(ParamPrefixEnum.STARTS_AFTER);
|
||||
testDateUnsupportedOp(ParamPrefixEnum.ENDS_BEFORE);
|
||||
testDateUnsupportedOp(ParamPrefixEnum.NOT_EQUAL);
|
||||
}
|
||||
|
||||
private void testDateUnsupportedOp(ParamPrefixEnum theOperator) {
|
||||
InMemoryMatchResult result = myInMemoryResourceMatcher.match("date=" + theOperator.getValue() + OBSERVATION_DATE, myObservation, mySearchParams);
|
||||
assertFalse(result.supported());
|
||||
assertEquals("Parameter: <date> Reason: The prefix " + theOperator + " is not supported for param type DATE", result.getUnsupportedReason());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateSupportedOps() {
|
||||
testDateSupportedOp(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, true, true, false);
|
||||
testDateSupportedOp(ParamPrefixEnum.GREATERTHAN, true, false, false);
|
||||
testDateSupportedOp(ParamPrefixEnum.EQUAL, false, true, false);
|
||||
testDateSupportedOp(ParamPrefixEnum.LESSTHAN_OR_EQUALS, false, true, true);
|
||||
testDateSupportedOp(ParamPrefixEnum.LESSTHAN, false, false, true);
|
||||
}
|
||||
|
||||
private void testDateSupportedOp(ParamPrefixEnum theOperator, boolean theEarly, boolean theSame, boolean theLater) {
|
||||
String equation = "date=" + theOperator.getValue();
|
||||
{
|
||||
InMemoryMatchResult result = myInMemoryResourceMatcher.match(equation + EARLY_DATE, myObservation, mySearchParams);
|
||||
assertTrue(result.getUnsupportedReason(), result.supported());
|
||||
assertEquals(result.matched(), theEarly);
|
||||
}
|
||||
{
|
||||
InMemoryMatchResult result = myInMemoryResourceMatcher.match(equation + OBSERVATION_DATE, myObservation, mySearchParams);
|
||||
assertTrue(result.getUnsupportedReason(), result.supported());
|
||||
assertEquals(result.matched(), theSame);
|
||||
}
|
||||
{
|
||||
InMemoryMatchResult result = myInMemoryResourceMatcher.match(equation + LATE_DATE, myObservation, mySearchParams);
|
||||
assertTrue(result.getUnsupportedReason(), result.supported());
|
||||
assertEquals(result.matched(), theLater);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNowPast() {
|
||||
InMemoryMatchResult result = myInMemoryResourceMatcher.match("date=lt" + BaseDateTimeDt.NOW_DATE_CONSTANT, myObservation, mySearchParams);
|
||||
assertTrue(result.getUnsupportedReason(), result.supported());
|
||||
assertTrue(result.matched());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNowNextWeek() {
|
||||
Observation futureObservation = new Observation();
|
||||
Instant nextWeek = Instant.now().plus(Duration.ofDays(7));
|
||||
futureObservation.setEffective(new DateTimeType(Date.from(nextWeek)));
|
||||
ResourceIndexedSearchParams searchParams = extractDateSearchParam(futureObservation);
|
||||
|
||||
InMemoryMatchResult result = myInMemoryResourceMatcher.match("date=gt" + BaseDateTimeDt.NOW_DATE_CONSTANT, futureObservation, searchParams);
|
||||
assertTrue(result.getUnsupportedReason(), result.supported());
|
||||
assertTrue(result.matched());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNowNextMinute() {
|
||||
Observation futureObservation = new Observation();
|
||||
Instant nextMinute = Instant.now().plus(Duration.ofMinutes(1));
|
||||
futureObservation.setEffective(new DateTimeType(Date.from(nextMinute)));
|
||||
ResourceIndexedSearchParams searchParams = extractDateSearchParam(futureObservation);
|
||||
|
||||
InMemoryMatchResult result = myInMemoryResourceMatcher.match("date=gt" + BaseDateTimeDt.NOW_DATE_CONSTANT, futureObservation, searchParams);
|
||||
assertTrue(result.getUnsupportedReason(), result.supported());
|
||||
assertTrue(result.matched());
|
||||
}
|
||||
|
||||
private ResourceIndexedSearchParams extractDateSearchParam(Observation theObservation) {
|
||||
ResourceIndexedSearchParams retval = new ResourceIndexedSearchParams();
|
||||
BaseDateTimeType dateValue = (BaseDateTimeType) theObservation.getEffective();
|
||||
ResourceIndexedSearchParamDate dateParam = new ResourceIndexedSearchParamDate("date", dateValue.getValue(), dateValue.getValue(), dateValue.getValueAsString());
|
||||
retval.myDateParams.add(dateParam);
|
||||
return retval;
|
||||
}
|
||||
|
||||
}
|
|
@ -549,7 +549,7 @@ public class InMemorySubscriptionMatcherR3Test extends BaseSubscriptionDstu3Test
|
|||
CommunicationRequest cr = new CommunicationRequest();
|
||||
cr.getRequester().getAgent().setReference("Organization/O1276");
|
||||
cr.setOccurrence(new DateTimeType("2019-02-08T00:01:00-05:00"));
|
||||
assertUnsupported(cr, criteria);
|
||||
assertMatched(cr, criteria);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -178,7 +178,7 @@ public class ConsentInterceptor {
|
|||
alreadySeenResources.put(newOperationOutcome, true);
|
||||
} else {
|
||||
String resourceId = nextResource.getIdElement().getValue();
|
||||
theRequestDetails.getFhirContext().newTerser().clear(nextResource);
|
||||
thePreResourceShowDetails.setResource(i, null);
|
||||
nextResource.setId(resourceId);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -5,7 +5,6 @@ import ca.uhn.fhir.rest.api.Constants;
|
|||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.validation.IValidationContext;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
import com.github.benmanes.caffeine.cache.CacheLoader;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
package org.hl7.fhir.instance.hapi.validation;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.context.RuntimePrimitiveDatatypeDefinition;
|
||||
import ca.uhn.fhir.context.*;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.validation.IValidationContext;
|
||||
|
@ -14,11 +8,7 @@ import ca.uhn.fhir.validation.IValidatorModule;
|
|||
import com.github.benmanes.caffeine.cache.CacheLoader;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.*;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
|
@ -27,16 +17,10 @@ import org.fhir.ucum.UcumService;
|
|||
import org.hl7.fhir.convertors.NullVersionConverterAdvisor50;
|
||||
import org.hl7.fhir.convertors.VersionConvertorAdvisor50;
|
||||
import org.hl7.fhir.convertors.VersionConvertor_10_50;
|
||||
import org.hl7.fhir.convertors.VersionConvertor_10_50;
|
||||
import org.hl7.fhir.dstu2.model.*;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.dstu2.model.CodeableConcept;
|
||||
import org.hl7.fhir.dstu2.model.Coding;
|
||||
import org.hl7.fhir.dstu2.model.Questionnaire;
|
||||
import org.hl7.fhir.dstu2.model.Resource;
|
||||
import org.hl7.fhir.dstu2.model.StructureDefinition;
|
||||
import org.hl7.fhir.dstu2.model.ValueSet;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.formats.IParser;
|
||||
import org.hl7.fhir.r5.formats.ParserType;
|
||||
|
@ -58,20 +42,17 @@ import org.w3c.dom.Element;
|
|||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
public class FhirInstanceValidator extends BaseValidatorBridge implements IValidatorModule {
|
||||
|
||||
|
|
|
@ -30,9 +30,6 @@ import org.hl7.fhir.utilities.TerminologyServiceOptions;
|
|||
import org.hl7.fhir.utilities.TranslationServices;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
|
|
@ -121,6 +121,18 @@
|
|||
The GraphQL provider did not wrap the respone in a "data" element as described in the FHIR
|
||||
specification. This has been corrected.
|
||||
</action>
|
||||
<action type="add">
|
||||
Added support for comparing resource dates to the current time via a new variable %now. E.g.
|
||||
Procedure?date=gt%now would match future procedures.
|
||||
</action>
|
||||
<action type="add">
|
||||
Add support for in-memory matching on date comparisons ge,gt,eq,lt,le.
|
||||
</action>
|
||||
<action type="fix">
|
||||
When using the Consent Service and denying a resource via the "Will See Resource" method, the resource ID
|
||||
and version were still returned to the user. This has been corrected so that no details about
|
||||
the resource are leaked.
|
||||
</action>
|
||||
</release>
|
||||
<release version="4.0.1" date="2019-09-03" description="Igloo (Point Release)">
|
||||
<action type="fix">
|
||||
|
|
Loading…
Reference in New Issue