use of org.hl7.fhir.dstu2016may.model.Range in project beneficiary-fhir-data by CMSgov.
the class R4PatientResourceProvider method searchByIdentifier.
/**
* Adds support for the FHIR "search" operation for {@link Patient}s, allowing users to search by
* {@link Patient#getIdentifier()}. Specifically, the following criteria are supported:
*
* <p>Searches that don't match one of the above forms are not supported.
*
* <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 identifier an {@link Identifier} {@link TokenParam} for the {@link
* Patient#getIdentifier()} 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 searchByIdentifier(@RequiredParam(name = Patient.SP_IDENTIFIER) @Description(shortDefinition = "The patient identifier to search for") TokenParam identifier, @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 (identifier.getQueryParameterQualifier() != null) {
throw new InvalidRequestException("Unsupported query parameter qualifier: " + identifier.getQueryParameterQualifier());
}
if (!SUPPORTED_HASH_IDENTIFIER_SYSTEMS.contains(identifier.getSystem()))
throw new InvalidRequestException("Unsupported identifier system: " + identifier.getSystem());
RequestHeaders requestHeader = RequestHeaders.getHeaderWrapper(requestDetails);
Operation operation = new Operation(Operation.Endpoint.V2_PATIENT);
operation.setOption("by", "identifier");
requestHeader.getNVPairs().forEach((n, v) -> operation.setOption(n, v.toString()));
operation.setOption("_lastUpdated", Boolean.toString(lastUpdated != null && !lastUpdated.isEmpty()));
operation.publishOperationName();
List<IBaseResource> patients;
try {
Patient patient;
switch(identifier.getSystem()) {
case TransformerConstants.CODING_BBAPI_BENE_MBI_HASH:
patient = queryDatabaseByMbiHash(identifier.getValue(), requestHeader);
break;
case TransformerConstants.CODING_BBAPI_BENE_HICN_HASH:
case TransformerConstants.CODING_BBAPI_BENE_HICN_HASH_OLD:
patient = queryDatabaseByHicnHash(identifier.getValue(), requestHeader);
break;
default:
throw new InvalidRequestException("Unsupported identifier system: " + identifier.getSystem());
}
patients = QueryUtils.isInRange(patient.getMeta().getLastUpdated().toInstant(), lastUpdated) ? Collections.singletonList(patient) : Collections.emptyList();
} catch (NoResultException e) {
patients = new LinkedList<>();
}
OffsetLinkBuilder paging = new OffsetLinkBuilder(requestDetails, "/Patient?");
return TransformerUtilsV2.createBundle(paging, patients, loadedFilterManager.getTransactionTime());
}
use of org.hl7.fhir.dstu2016may.model.Range in project beneficiary-fhir-data by CMSgov.
the class R4PatientResourceProvider 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.V2_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 = TransformerUtilsV2.createBundle(paging, patients, loadedFilterManager.getTransactionTime());
return bundle;
}
use of org.hl7.fhir.dstu2016may.model.Range in project beneficiary-fhir-data by CMSgov.
the class ExplanationOfBenefitResourceProviderIT method searchEobWithLastUpdatedAndPagination.
/**
* Verifies that {@link ExplanationOfBenefitResourceProvider#findByPatient} works as with a
* lastUpdated parameter after yesterday.
*
* @throws FHIRException (indicates test failure)
*/
@Test
public void searchEobWithLastUpdatedAndPagination() throws FHIRException {
Beneficiary beneficiary = loadSampleA();
IGenericClient fhirClient = ServerTestUtils.get().createFhirClient();
// Search with lastUpdated range between yesterday and now
int expectedCount = 3;
Date yesterday = Date.from(Instant.now().minus(1, ChronoUnit.DAYS));
Date now = new Date();
DateRangeParam afterYesterday = new DateRangeParam(yesterday, now);
Bundle searchResultsAfter = fhirClient.search().forResource(ExplanationOfBenefit.class).where(ExplanationOfBenefit.PATIENT.hasId(TransformerUtils.buildPatientId(beneficiary))).lastUpdated(afterYesterday).count(expectedCount).returnBundle(Bundle.class).execute();
assertEquals(expectedCount, searchResultsAfter.getEntry().size(), "Expected number resources return to be equal to count");
// Check self url
String selfLink = searchResultsAfter.getLink(IBaseBundle.LINK_SELF).getUrl();
assertTrue(selfLink.contains("lastUpdated"));
// Check next bundle
String nextLink = searchResultsAfter.getLink(IBaseBundle.LINK_NEXT).getUrl();
assertTrue(nextLink.contains("lastUpdated"));
Bundle nextResults = fhirClient.search().byUrl(nextLink).returnBundle(Bundle.class).execute();
assertEquals(expectedCount, nextResults.getEntry().size(), "Expected number resources return to be equal to count");
}
use of org.hl7.fhir.dstu2016may.model.Range in project beneficiary-fhir-data by CMSgov.
the class R4CoverageResourceProviderIT 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().createFhirClientV2();
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(TransformerUtilsV2.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(TransformerUtilsV2.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(TransformerUtilsV2.buildPatientId(beneficiary))).lastUpdated(outOfBoundsRange).returnBundle(Bundle.class).execute();
assertNotNull(searchOutOfBoundsResult);
assertEquals(0, searchOutOfBoundsResult.getTotal());
}
use of org.hl7.fhir.dstu2016may.model.Range in project kindling by HL7.
the class FhirTurtleGenerator method processTypes.
private void processTypes(String baseResourceName, FHIRResource baseResource, ElementDefn td, String predicateBase, boolean innerIsBackbone) throws Exception {
for (ElementDefn ed : td.getElements()) {
String predicateName = predicateBase + "." + (ed.getName().endsWith("[x]") ? ed.getName().substring(0, ed.getName().length() - 3) : ed.getName());
FHIRResource predicateResource;
if (ed.getName().endsWith("[x]")) {
predicateResource = fact.fhir_objectProperty(predicateName);
// Choice entry
if (ed.typeCode().equals("*")) {
// Wild card -- any element works (probably should be more restrictive but...)
Resource targetResource = RDFNamespace.FHIR.resourceRef("Element");
baseResource.restriction(fact.fhir_cardinality_restriction(predicateResource.resource, targetResource, ed.getMinCardinality(), ed.getMaxCardinality()));
predicateResource.domain(baseResource);
predicateResource.range(targetResource);
} else {
// Create a restriction on the union of possible types
List<Resource> typeOpts = new ArrayList<Resource>();
for (TypeRef tr : ed.getTypes()) {
// TODO: Figure out how to get the type reference code
String trName = tr.getName();
if (trName.equals("SimpleQuantity"))
trName = "Quantity";
String qualifiedPredicateName = predicateName + Utilities.capitalize(trName);
Resource targetRes = fact.fhir_class(tr.getName()).resource;
FHIRResource qualifiedPredicate = fact.fhir_objectProperty(qualifiedPredicateName, predicateResource.resource).domain(baseResource).range(targetRes);
typeOpts.add(fact.fhir_cardinality_restriction(qualifiedPredicate.resource, targetRes, ed.getMinCardinality(), ed.getMaxCardinality()));
}
baseResource.restriction(fact.fhir_union(typeOpts));
}
} else {
FHIRResource baseDef;
if (ed.getTypes().isEmpty()) {
predicateResource = fact.fhir_objectProperty(predicateName);
String targetClassName = mapComponentName(baseResourceName, ed.getDeclaredTypeName());
baseDef = fact.fhir_class(targetClassName, innerIsBackbone ? "BackboneElement" : "Element").addDefinition(ed.getDefinition());
processTypes(targetClassName, baseDef, ed, predicateName, innerIsBackbone);
} else {
TypeRef targetType = ed.getTypes().get(0);
String targetName = targetType.getName();
if (targetName.startsWith("@")) {
// Link to earlier definition
ElementDefn targetRef = getElementForPath(targetName.substring(1));
String targetRefName = targetRef.getName();
String targetClassName = baseResourceName + Character.toUpperCase(targetRefName.charAt(0)) + targetRefName.substring(1);
baseDef = fact.fhir_class(targetClassName, innerIsBackbone ? "BackboneElement" : "Element").addDefinition(ed.getDefinition()).addTitle(ed.getShortDefn());
if (!processing.contains(targetRefName)) {
processing.add(targetRefName);
processTypes(targetClassName, baseDef, targetRef, predicateName, innerIsBackbone);
processing.remove(targetRefName);
}
} else {
// A placeholder entry. The rest of the information will be supplied elsewhere
baseDef = fact.fhir_class(targetName);
}
// XHTML the exception, in that the html doesn't derive from Primitive
if (targetName.equals("xhtml"))
predicateResource = fact.fhir_dataProperty(predicateName);
else
predicateResource = fact.fhir_objectProperty(predicateName);
}
predicateResource.addTitle(ed.getShortDefn()).addDefinition(ed.getDefinition()).domain(baseResource);
baseResource.restriction(fact.fhir_cardinality_restriction(predicateResource.resource, baseDef.resource, ed.getMinCardinality(), ed.getMaxCardinality()));
predicateResource.range(baseDef.resource);
if (!Utilities.noString(ed.getW5()))
predicateResource.addObjectProperty(RDFS.subPropertyOf, RDFNamespace.W5.resourceRef(ed.getW5()));
}
}
}
Aggregations