use of org.hl7.fhir.r4b.model.Range in project clinical_quality_language by cqframework.
the class DataRequirementsProcessor method toFhirValue.
private DataType toFhirValue(ElmRequirementsContext context, Expression value) {
if (value == null) {
return null;
}
if (value instanceof Interval) {
// TODO: Handle lowclosed/highclosed
return new Period().setStartElement(toFhirDateTimeValue(context, ((Interval) value).getLow())).setEndElement(toFhirDateTimeValue(context, ((Interval) value).getHigh()));
} else if (value instanceof Literal) {
if (context.getTypeResolver().isDateTimeType(value.getResultType())) {
return new DateTimeType(((Literal) value).getValue());
} else if (context.getTypeResolver().isDateType(value.getResultType())) {
return new DateType(((Literal) value).getValue());
} else if (context.getTypeResolver().isIntegerType(value.getResultType())) {
return new IntegerType(((Literal) value).getValue());
} else if (context.getTypeResolver().isDecimalType(value.getResultType())) {
return new DecimalType(((Literal) value).getValue());
} else if (context.getTypeResolver().isStringType(value.getResultType())) {
return new StringType(((Literal) value).getValue());
}
} else if (value instanceof DateTime) {
DateTime dateTime = (DateTime) value;
return new DateTimeType(toDateTimeString(toFhirValue(context, dateTime.getYear()), toFhirValue(context, dateTime.getMonth()), toFhirValue(context, dateTime.getDay()), toFhirValue(context, dateTime.getHour()), toFhirValue(context, dateTime.getMinute()), toFhirValue(context, dateTime.getSecond()), toFhirValue(context, dateTime.getMillisecond()), toFhirValue(context, dateTime.getTimezoneOffset())));
} else if (value instanceof org.hl7.elm.r1.Date) {
org.hl7.elm.r1.Date date = (org.hl7.elm.r1.Date) value;
return new DateType(toDateString(toFhirValue(context, date.getYear()), toFhirValue(context, date.getMonth()), toFhirValue(context, date.getDay())));
} else if (value instanceof Start) {
DataType operand = toFhirValue(context, ((Start) value).getOperand());
if (operand != null) {
Period period = (Period) operand;
return period.getStartElement();
}
} else if (value instanceof End) {
DataType operand = toFhirValue(context, ((End) value).getOperand());
if (operand != null) {
Period period = (Period) operand;
return period.getEndElement();
}
} else if (value instanceof ParameterRef) {
if (context.getTypeResolver().isIntervalType(value.getResultType())) {
Extension e = toExpression(context, (ParameterRef) value);
org.hl7.cql.model.DataType pointType = ((IntervalType) value.getResultType()).getPointType();
if (context.getTypeResolver().isDateTimeType(pointType) || context.getTypeResolver().isDateType(pointType)) {
Period period = new Period();
period.addExtension(e);
return period;
} else if (context.getTypeResolver().isQuantityType(pointType) || context.getTypeResolver().isIntegerType(pointType) || context.getTypeResolver().isDecimalType(pointType)) {
Range range = new Range();
range.addExtension(e);
return range;
} else {
throw new IllegalArgumentException(String.format("toFhirValue not implemented for interval of %s", pointType.toString()));
}
} else // Boolean, Integer, Decimal, String, Quantity, Date, DateTime, Time, Coding, CodeableConcept
if (context.getTypeResolver().isBooleanType(value.getResultType())) {
BooleanType result = new BooleanType();
result.addExtension(toExpression(context, (ParameterRef) value));
return result;
} else if (context.getTypeResolver().isIntegerType(value.getResultType())) {
IntegerType result = new IntegerType();
result.addExtension(toExpression(context, (ParameterRef) value));
return result;
} else if (context.getTypeResolver().isDecimalType(value.getResultType())) {
DecimalType result = new DecimalType();
result.addExtension(toExpression(context, (ParameterRef) value));
return result;
} else if (context.getTypeResolver().isQuantityType(value.getResultType())) {
Quantity result = new Quantity();
result.addExtension(toExpression(context, (ParameterRef) value));
return result;
} else if (context.getTypeResolver().isCodeType(value.getResultType())) {
Coding result = new Coding();
result.addExtension(toExpression(context, (ParameterRef) value));
return result;
} else if (context.getTypeResolver().isConceptType(value.getResultType())) {
CodeableConcept result = new CodeableConcept();
result.addExtension(toExpression(context, (ParameterRef) value));
return result;
} else if (context.getTypeResolver().isDateType(value.getResultType())) {
DateType result = new DateType();
result.addExtension(toExpression(context, (ParameterRef) value));
return result;
} else if (context.getTypeResolver().isDateTimeType(value.getResultType())) {
DateTimeType result = new DateTimeType();
result.addExtension(toExpression(context, (ParameterRef) value));
return result;
} else if (context.getTypeResolver().isTimeType(value.getResultType())) {
TimeType result = new TimeType();
result.addExtension(toExpression(context, (ParameterRef) value));
return result;
} else {
throw new IllegalArgumentException(String.format("toFhirValue not implemented for parameter of type %s", value.getResultType().toString()));
}
}
throw new IllegalArgumentException(String.format("toFhirValue not implemented for %s", value.getClass().getSimpleName()));
}
use of org.hl7.fhir.r4b.model.Range in project clinical_quality_language by cqframework.
the class Cql2ElmVisitor method parseDateTimeLiteral.
private Expression parseDateTimeLiteral(String input) {
/*
DATETIME
: '@'
[0-9][0-9][0-9][0-9] // year
(
(
'-'[0-9][0-9] // month
(
(
'-'[0-9][0-9] // day
('T' TIMEFORMAT?)?
)
| 'T'
)?
)
| 'T'
)?
('Z' | ('+' | '-') [0-9][0-9]':'[0-9][0-9])? // timezone offset
;
*/
Pattern dateTimePattern = Pattern.compile("(\\d{4})(((-(\\d{2}))(((-(\\d{2}))((T)((\\d{2})(\\:(\\d{2})(\\:(\\d{2})(\\.(\\d+))?)?)?)?)?)|(T))?)|(T))?((Z)|(([+-])(\\d{2})(\\:(\\d{2}))))?");
// 1-------234-5--------678-9--------11--11-------1---1-------1---1-------1---1-----------------2------2----22---22-----2-------2---2-----------
// ----------------------------------01--23-------4---5-------6---7-------8---9-----------------0------1----23---45-----6-------7---8-----------
/*
year - group 1
month - group 5
day - group 9
day dateTime indicator - group 11
hour - group 13
minute - group 15
second - group 17
millisecond - group 19
month dateTime indicator - group 20
year dateTime indicator - group 21
utc indicator - group 23
timezone offset polarity - group 25
timezone offset hour - group 26
timezone offset minute - group 28
*/
/*
Pattern dateTimePattern =
Pattern.compile("(\\d{4})(-(\\d{2}))?(-(\\d{2}))?((Z)|(T((\\d{2})(\\:(\\d{2})(\\:(\\d{2})(\\.(\\d+))?)?)?)?((Z)|(([+-])(\\d{2})(\\:?(\\d{2}))?))?))?");
//1-------2-3---------4-5---------67---8-91-------1---1-------1---1-------1---1-------------11---12-----2-------2----2---------------
//----------------------------------------0-------1---2-------3---4-------5---6-------------78---90-----1-------2----3---------------
*/
Matcher matcher = dateTimePattern.matcher(input);
if (matcher.matches()) {
try {
GregorianCalendar calendar = (GregorianCalendar) GregorianCalendar.getInstance();
DateTime result = of.createDateTime();
int year = Integer.parseInt(matcher.group(1));
int month = -1;
int day = -1;
int hour = -1;
int minute = -1;
int second = -1;
int millisecond = -1;
result.setYear(libraryBuilder.createLiteral(year));
if (matcher.group(5) != null) {
month = Integer.parseInt(matcher.group(5));
if (month < 0 || month > 12) {
throw new IllegalArgumentException(String.format("Invalid month in date/time literal (%s).", input));
}
result.setMonth(libraryBuilder.createLiteral(month));
}
if (matcher.group(9) != null) {
day = Integer.parseInt(matcher.group(9));
int maxDay = 31;
switch(month) {
case 2:
maxDay = calendar.isLeapYear(year) ? 29 : 28;
break;
case 4:
case 6:
case 9:
case 11:
maxDay = 30;
break;
default:
break;
}
if (day < 0 || day > maxDay) {
throw new IllegalArgumentException(String.format("Invalid day in date/time literal (%s).", input));
}
result.setDay(libraryBuilder.createLiteral(day));
}
if (matcher.group(13) != null) {
hour = Integer.parseInt(matcher.group(13));
if (hour < 0 || hour > 24) {
throw new IllegalArgumentException(String.format("Invalid hour in date/time literal (%s).", input));
}
result.setHour(libraryBuilder.createLiteral(hour));
}
if (matcher.group(15) != null) {
minute = Integer.parseInt(matcher.group(15));
if (minute < 0 || minute >= 60 || (hour == 24 && minute > 0)) {
throw new IllegalArgumentException(String.format("Invalid minute in date/time literal (%s).", input));
}
result.setMinute(libraryBuilder.createLiteral(minute));
}
if (matcher.group(17) != null) {
second = Integer.parseInt(matcher.group(17));
if (second < 0 || second >= 60 || (hour == 24 && second > 0)) {
throw new IllegalArgumentException(String.format("Invalid second in date/time literal (%s).", input));
}
result.setSecond(libraryBuilder.createLiteral(second));
}
if (matcher.group(19) != null) {
millisecond = Integer.parseInt(matcher.group(19));
if (millisecond < 0 || (hour == 24 && millisecond > 0)) {
throw new IllegalArgumentException(String.format("Invalid millisecond in date/time literal (%s).", input));
}
result.setMillisecond(libraryBuilder.createLiteral(millisecond));
}
if (matcher.group(23) != null && matcher.group(23).equals("Z")) {
result.setTimezoneOffset(libraryBuilder.createLiteral(0.0));
}
if (matcher.group(25) != null) {
int offsetPolarity = matcher.group(25).equals("+") ? 1 : -1;
if (matcher.group(28) != null) {
int hourOffset = Integer.parseInt(matcher.group(26));
if (hourOffset < 0 || hourOffset > 14) {
throw new IllegalArgumentException(String.format("Timezone hour offset is out of range in date/time literal (%s).", input));
}
int minuteOffset = Integer.parseInt(matcher.group(28));
if (minuteOffset < 0 || minuteOffset >= 60 || (hourOffset == 14 && minuteOffset > 0)) {
throw new IllegalArgumentException(String.format("Timezone minute offset is out of range in date/time literal (%s).", input));
}
result.setTimezoneOffset(libraryBuilder.createLiteral((double) (hourOffset + (minuteOffset / 60)) * offsetPolarity));
} else {
if (matcher.group(26) != null) {
int hourOffset = Integer.parseInt(matcher.group(26));
if (hourOffset < 0 || hourOffset > 14) {
throw new IllegalArgumentException(String.format("Timezone hour offset is out of range in date/time literal (%s).", input));
}
result.setTimezoneOffset(libraryBuilder.createLiteral((double) (hourOffset * offsetPolarity)));
}
}
}
if (result.getHour() == null && matcher.group(11) == null && matcher.group(20) == null && matcher.group(21) == null) {
org.hl7.elm.r1.Date date = of.createDate();
date.setYear(result.getYear());
date.setMonth(result.getMonth());
date.setDay(result.getDay());
date.setResultType(libraryBuilder.resolveTypeName("System", "Date"));
return date;
}
result.setResultType(libraryBuilder.resolveTypeName("System", "DateTime"));
return result;
} catch (RuntimeException e) {
throw new IllegalArgumentException(String.format("Invalid date-time input (%s). Use ISO 8601 date time representation (yyyy-MM-ddThh:mm:ss.fff(Z|(+/-hh:mm)).", input), e);
}
} else {
throw new IllegalArgumentException(String.format("Invalid date-time input (%s). Use ISO 8601 date time representation (yyyy-MM-ddThh:mm:ss.fff(Z|+/-hh:mm)).", input));
}
}
use of org.hl7.fhir.r4b.model.Range in project beneficiary-fhir-data by CMSgov.
the class PatientResourceProvider method searchByLogicalId.
/**
* Adds support for the FHIR "search" operation for {@link Patient}s, allowing users to search by
* {@link Patient#getId()}.
*
* <p>The {@link Search} annotation indicates that this method supports the search operation.
* There may be many different methods annotated with this {@link Search} annotation, to support
* many different search criteria.
*
* @param logicalId a {@link TokenParam} (with no system, per the spec) for the {@link
* Patient#getId()} to try and find a matching {@link Patient} for
* @param startIndex an {@link OptionalParam} for the startIndex (or offset) used to determine
* pagination
* @param lastUpdated an {@link OptionalParam} to filter the results based on the passed date
* range
* @param requestDetails a {@link RequestDetails} containing the details of the request URL, used
* to parse out pagination values
* @return Returns a {@link List} of {@link Patient}s, which may contain multiple matching
* resources, or may also be empty.
*/
@Search
@Trace
public Bundle searchByLogicalId(@RequiredParam(name = Patient.SP_RES_ID) @Description(shortDefinition = "The patient identifier to search for") TokenParam logicalId, @OptionalParam(name = "startIndex") @Description(shortDefinition = "The offset used for result pagination") String startIndex, @OptionalParam(name = "_lastUpdated") @Description(shortDefinition = "Include resources last updated in the given range") DateRangeParam lastUpdated, RequestDetails requestDetails) {
if (logicalId.getQueryParameterQualifier() != null)
throw new InvalidRequestException("Unsupported query parameter qualifier: " + logicalId.getQueryParameterQualifier());
if (logicalId.getSystem() != null && !logicalId.getSystem().isEmpty())
throw new InvalidRequestException("Unsupported query parameter system: " + logicalId.getSystem());
if (logicalId.getValueNotNull().isEmpty())
throw new InvalidRequestException("Unsupported query parameter value: " + logicalId.getValue());
List<IBaseResource> patients;
if (loadedFilterManager.isResultSetEmpty(logicalId.getValue(), lastUpdated)) {
patients = Collections.emptyList();
} else {
try {
patients = Optional.of(read(new IdType(logicalId.getValue()), requestDetails)).filter(p -> QueryUtils.isInRange(p.getMeta().getLastUpdated().toInstant(), lastUpdated)).map(p -> Collections.singletonList((IBaseResource) p)).orElse(Collections.emptyList());
} catch (ResourceNotFoundException e) {
patients = Collections.emptyList();
}
}
/*
* Publish the operation name. Note: This is a bit later than we'd normally do this, as we need
* to override the operation name that was published by the possible call to read(...), above.
*/
RequestHeaders requestHeader = RequestHeaders.getHeaderWrapper(requestDetails);
Operation operation = new Operation(Operation.Endpoint.V1_PATIENT);
operation.setOption("by", "id");
// track all api hdrs
requestHeader.getNVPairs().forEach((n, v) -> operation.setOption(n, v.toString()));
operation.setOption("_lastUpdated", Boolean.toString(lastUpdated != null && !lastUpdated.isEmpty()));
operation.publishOperationName();
OffsetLinkBuilder paging = new OffsetLinkBuilder(requestDetails, "/Patient?");
Bundle bundle = TransformerUtils.createBundle(paging, patients, loadedFilterManager.getTransactionTime());
return bundle;
}
use of org.hl7.fhir.r4b.model.Range in project beneficiary-fhir-data by CMSgov.
the class CoverageResourceProviderIT method searchWithLastUpdated.
/**
* Verifies that {@link
* gov.cms.bfd.server.war.stu3.providers.CoverageResourceProvider#searchByBeneficiary} works as
* expected for a search with a lastUpdated value.
*/
@Test
public void searchWithLastUpdated() {
List<Object> loadedRecords = ServerTestUtils.get().loadData(Arrays.asList(StaticRifResourceGroup.SAMPLE_A.getResources()));
IGenericClient fhirClient = ServerTestUtils.get().createFhirClient();
Beneficiary beneficiary = loadedRecords.stream().filter(r -> r instanceof Beneficiary).map(r -> (Beneficiary) r).findFirst().get();
Bundle searchResults = fhirClient.search().forResource(Coverage.class).where(Coverage.BENEFICIARY.hasId(TransformerUtils.buildPatientId(beneficiary))).returnBundle(Bundle.class).execute();
LOGGER.info("Bundle information: database {}, first {}", searchResults.getMeta().getLastUpdated(), searchResults.getEntry().get(0).getResource().getMeta().getLastUpdated());
Date nowDate = new Date();
Date secondsAgoDate = Date.from(Instant.now().minusSeconds(100));
DateRangeParam inBoundsRange = new DateRangeParam().setLowerBoundInclusive(secondsAgoDate).setUpperBoundExclusive(nowDate);
LOGGER.info("Query Date Range {}", inBoundsRange);
Bundle searchInBoundsResults = fhirClient.search().forResource(Coverage.class).where(Coverage.BENEFICIARY.hasId(TransformerUtils.buildPatientId(beneficiary))).lastUpdated(inBoundsRange).returnBundle(Bundle.class).execute();
assertNotNull(searchInBoundsResults);
assertEquals(MedicareSegment.values().length, searchInBoundsResults.getTotal());
Date hourAgoDate = Date.from(Instant.now().minusSeconds(3600));
DateRangeParam outOfBoundsRange = new DateRangeParam(hourAgoDate, secondsAgoDate);
Bundle searchOutOfBoundsResult = fhirClient.search().forResource(Coverage.class).where(Coverage.BENEFICIARY.hasId(TransformerUtils.buildPatientId(beneficiary))).lastUpdated(outOfBoundsRange).returnBundle(Bundle.class).execute();
assertNotNull(searchOutOfBoundsResult);
assertEquals(0, searchOutOfBoundsResult.getTotal());
}
use of org.hl7.fhir.r4b.model.Range in project beneficiary-fhir-data by CMSgov.
the class AbstractR4ResourceProvider method findByPatient.
@Search
@Trace
public Bundle findByPatient(@RequiredParam(name = "mbi") @Description(shortDefinition = "The patient identifier to search for") ReferenceParam mbi, @OptionalParam(name = "type") @Description(shortDefinition = "A list of claim types to include") TokenAndListParam types, @OptionalParam(name = "isHashed") @Description(shortDefinition = "A boolean indicating whether or not the MBI is hashed") String hashed, @OptionalParam(name = "excludeSAMHSA") @Description(shortDefinition = "If true, exclude all SAMHSA-related resources") String samhsa, @OptionalParam(name = "_lastUpdated") @Description(shortDefinition = "Include resources last updated in the given range") DateRangeParam lastUpdated, @OptionalParam(name = "service-date") @Description(shortDefinition = "Include resources that completed in the given range") DateRangeParam serviceDate, RequestDetails requestDetails) {
if (mbi != null && !StringUtils.isBlank(mbi.getIdPart())) {
String mbiString = mbi.getIdPart();
Bundle bundleResource;
boolean isHashed = !Boolean.FALSE.toString().equalsIgnoreCase(hashed);
boolean excludeSamhsa = Boolean.TRUE.toString().equalsIgnoreCase(samhsa);
if (isHashed) {
TransformerUtilsV2.logMbiHashToMdc(mbiString);
}
if (types != null) {
bundleResource = createBundleFor(parseClaimTypes(types), mbiString, isHashed, excludeSamhsa, lastUpdated, serviceDate);
} else {
bundleResource = createBundleFor(getResourceTypes(), mbiString, isHashed, excludeSamhsa, lastUpdated, serviceDate);
}
return bundleResource;
} else {
throw new IllegalArgumentException("mbi can't be null/blank");
}
}
Aggregations