Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.param.CompositeParam;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.InternalCodingDt;
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
Expand Down Expand Up @@ -442,11 +441,13 @@ public void populateDateSearchParams(
throw new InternalErrorException("resolved search parameter definition is null");
}

// a date range is a search && condition - so we'll use a composite
// a date range is a search AND condition — each put() on the Multimap
// adds a separate AND clause (one for >= start, one for <= end)
DateParam gte = new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, start);
DateParam lte = new DateParam(ParamPrefixEnum.LESSTHAN_OR_EQUALS, end);

searchParams.put(sp.getName(), List.of(new CompositeParam<>(gte, lte)));
searchParams.put(sp.getName(), makeMutableSingleElementList(gte));
searchParams.put(sp.getName(), makeMutableSingleElementList(lte));
} else if (StringUtils.isNotBlank(dateLowPath)) {
List<IQueryParameterType> dateRangeParam = new ArrayList<>();
DateParam dateParam = new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, start);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,47 @@ default boolean isMatchDate(DateParam param, IBase pathResult) {
throw new UnsupportedOperationException(
"Expected date, found " + pathResult.getClass().getSimpleName());
}
} else if (pathResult instanceof ICompositeType type) {
// For Period/Timing paths, a single DateParam represents one side of an overlap check.
// This allows repositories that AND repeated date params to evaluate each bound safely.
dateRange = getDateRange(type);
DateParam lowerBound = dateRange.getLowerBound();
DateParam upperBound = dateRange.getUpperBound();

Date resourceStart = lowerBound == null ? null : lowerBound.getValue();
Date resourceEnd = upperBound == null ? null : upperBound.getValue();

if (param.getValue() == null) {
return false;
}

switch (param.getPrefix()) {
case GREATERTHAN:
case GREATERTHAN_OR_EQUALS:
return resourceEnd != null && isDateMatch(param, resourceEnd);
case LESSTHAN:
case LESSTHAN_OR_EQUALS:
return resourceStart != null && isDateMatch(param, resourceStart);
case EQUAL:
if (resourceStart == null || resourceEnd == null) {
return false;
}

Date compareDate = param.getValue();
return !compareDate.before(resourceStart) && !compareDate.after(resourceEnd);
case NOT_EQUAL:
if (resourceStart == null || resourceEnd == null) {
return true;
}

Date notEqualCompare = param.getValue();
return notEqualCompare.before(resourceStart) || notEqualCompare.after(resourceEnd);
default:
String msg = String.format(
"Unsupported DateTime comparison operation %s",
param.getPrefix().getValue());
throw new UnsupportedOperationException(msg);
}
} else {
throw new UnsupportedOperationException(
"Expected element of type date, dateTime, instant, Timing or Period, found "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,38 @@ void before() {
resourceMatcher = new ResourceMatcherR4();
}

@Test
void matches_locationPeriodWithSingleDateParam_doesNotThrowAndRespectsBounds() {
var encounter = new Encounter();
encounter
.addLocation()
.setPeriod(new Period()
.setStart(createDate("2000-01-01 00:00:00"))
.setEnd(createDate("2000-12-31 23:59:59")));

assertTrue(resourceMatcher.matches(
"location-period",
List.of(new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, createDate("2000-01-01"))),
encounter));
assertTrue(resourceMatcher.matches(
"location-period",
List.of(new DateParam(ParamPrefixEnum.LESSTHAN_OR_EQUALS, createDate("2000-12-31"))),
encounter));

assertEquals(
false,
resourceMatcher.matches(
"location-period",
List.of(new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, createDate("2001-01-01"))),
encounter));
assertEquals(
false,
resourceMatcher.matches(
"location-period",
List.of(new DateParam(ParamPrefixEnum.LESSTHAN_OR_EQUALS, createDate("1999-12-31"))),
encounter));
}

// NB: the list of parameters are always OR'd
// internal compositeparams are always AND'd
static List<Arguments> coverageParameters() {
Expand Down