use of gov.cms.bfd.model.rif.BeneficiaryHistory in project beneficiary-fhir-data by CMSgov.
the class ExplanationOfBenefitResourceProviderIT method searchForEobsByExistingPatientWithEvenPaging.
/**
* Verifies that {@link ExplanationOfBenefitResourceProvider#findByPatient} works as expected for
* a {@link Patient} that does exist in the DB, with paging. This test uses a count of 2 to verify
* our code will not run into an IndexOutOfBoundsException on odd bundle sizes.
*
* @throws FHIRException (indicates test failure)
*/
@Test
public void searchForEobsByExistingPatientWithEvenPaging() throws FHIRException {
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();
List<IBaseResource> combinedResults = new ArrayList<>();
Bundle searchResults = fhirClient.search().forResource(ExplanationOfBenefit.class).where(ExplanationOfBenefit.PATIENT.hasId(TransformerUtils.buildPatientId(beneficiary))).count(2).returnBundle(Bundle.class).execute();
searchResults.getEntry().forEach(e -> combinedResults.add(e.getResource()));
assertNotNull(searchResults);
assertEquals(2, searchResults.getEntry().size());
/*
* Verify the bundle contains a key for total and that the value matches the
* number of entries in the bundle.
*/
assertEquals(loadedRecords.stream().filter(r -> !(r instanceof Beneficiary)).filter(r -> !(r instanceof BeneficiaryHistory)).filter(r -> !(r instanceof MedicareBeneficiaryIdHistory)).count(), searchResults.getTotal());
/*
* Verify links to the first and last page exist.
*/
assertNotNull(searchResults.getLink(Constants.LINK_LAST));
assertNotNull(searchResults.getLink(Constants.LINK_FIRST));
/*
* Verify that accessing all next links, eventually leading to the last page,
* will not encounter an IndexOutOfBoundsException.
*/
while (searchResults.getLink(Constants.LINK_NEXT) != null) {
searchResults = fhirClient.loadPage().next(searchResults).execute();
assertNotNull(searchResults);
assertTrue(searchResults.hasEntry());
/*
* Each page after the first should have a first, previous, and last links.
*/
assertNotNull(searchResults.getLink(Constants.LINK_FIRST));
assertNotNull(searchResults.getLink(Constants.LINK_PREVIOUS));
assertNotNull(searchResults.getLink(Constants.LINK_LAST));
searchResults.getEntry().forEach(e -> combinedResults.add(e.getResource()));
}
/*
* Verify that the combined results are the same size as
* "all of the claim records in the sample."
*/
assertEquals(loadedRecords.stream().filter(r -> !(r instanceof Beneficiary)).filter(r -> !(r instanceof BeneficiaryHistory)).filter(r -> !(r instanceof MedicareBeneficiaryIdHistory)).count(), combinedResults.size());
/*
* Verify that each of the expected claims (one for every claim type) is present
* and looks correct.
*/
CarrierClaim carrierClaim = loadedRecords.stream().filter(r -> r instanceof CarrierClaim).map(r -> (CarrierClaim) r).findFirst().get();
assertEquals(1, filterToClaimTypeFromList(combinedResults, ClaimType.CARRIER).size());
CarrierClaimTransformerTest.assertMatches(carrierClaim, filterToClaimTypeFromList(combinedResults, ClaimType.CARRIER).get(0), Optional.empty());
DMEClaim dmeClaim = loadedRecords.stream().filter(r -> r instanceof DMEClaim).map(r -> (DMEClaim) r).findFirst().get();
DMEClaimTransformerTest.assertMatches(dmeClaim, filterToClaimTypeFromList(combinedResults, ClaimType.DME).get(0), Optional.empty());
HHAClaim hhaClaim = loadedRecords.stream().filter(r -> r instanceof HHAClaim).map(r -> (HHAClaim) r).findFirst().get();
HHAClaimTransformerTest.assertMatches(hhaClaim, filterToClaimTypeFromList(combinedResults, ClaimType.HHA).get(0));
HospiceClaim hospiceClaim = loadedRecords.stream().filter(r -> r instanceof HospiceClaim).map(r -> (HospiceClaim) r).findFirst().get();
HospiceClaimTransformerTest.assertMatches(hospiceClaim, filterToClaimTypeFromList(combinedResults, ClaimType.HOSPICE).get(0));
InpatientClaim inpatientClaim = loadedRecords.stream().filter(r -> r instanceof InpatientClaim).map(r -> (InpatientClaim) r).findFirst().get();
InpatientClaimTransformerTest.assertMatches(inpatientClaim, filterToClaimTypeFromList(combinedResults, ClaimType.INPATIENT).get(0));
OutpatientClaim outpatientClaim = loadedRecords.stream().filter(r -> r instanceof OutpatientClaim).map(r -> (OutpatientClaim) r).findFirst().get();
OutpatientClaimTransformerTest.assertMatches(outpatientClaim, filterToClaimTypeFromList(combinedResults, ClaimType.OUTPATIENT).get(0));
PartDEvent partDEvent = loadedRecords.stream().filter(r -> r instanceof PartDEvent).map(r -> (PartDEvent) r).findFirst().get();
PartDEventTransformerTest.assertMatches(partDEvent, filterToClaimTypeFromList(combinedResults, ClaimType.PDE).get(0));
SNFClaim snfClaim = loadedRecords.stream().filter(r -> r instanceof SNFClaim).map(r -> (SNFClaim) r).findFirst().get();
SNFClaimTransformerTest.assertMatches(snfClaim, filterToClaimTypeFromList(combinedResults, ClaimType.SNF).get(0));
}
use of gov.cms.bfd.model.rif.BeneficiaryHistory in project beneficiary-fhir-data by CMSgov.
the class ExplanationOfBenefitResourceProviderIT method searchForEobsByExistingPatient.
/**
* Verifies that {@link ExplanationOfBenefitResourceProvider#findByPatient} works as expected for
* a {@link Patient} that does exist in the DB.
*
* @throws FHIRException (indicates test failure)
*/
@Test
public void searchForEobsByExistingPatient() throws FHIRException {
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(ExplanationOfBenefit.class).where(ExplanationOfBenefit.PATIENT.hasId(TransformerUtils.buildPatientId(beneficiary))).returnBundle(Bundle.class).execute();
assertNotNull(searchResults);
/*
* Verify the bundle contains a key for total and that the value matches the
* number of entries in the bundle
*/
assertEquals(loadedRecords.stream().filter(r -> !(r instanceof Beneficiary)).filter(r -> !(r instanceof BeneficiaryHistory)).filter(r -> !(r instanceof MedicareBeneficiaryIdHistory)).count(), searchResults.getTotal());
/*
* Verify that no paging links exist in the bundle.
*/
assertNull(searchResults.getLink(Constants.LINK_NEXT));
assertNull(searchResults.getLink(Constants.LINK_PREVIOUS));
assertNull(searchResults.getLink(Constants.LINK_FIRST));
assertNull(searchResults.getLink(Constants.LINK_LAST));
/*
* Verify that each of the expected claims (one for every claim type) is present
* and looks correct.
*/
CarrierClaim carrierClaim = loadedRecords.stream().filter(r -> r instanceof CarrierClaim).map(r -> (CarrierClaim) r).findFirst().get();
assertEquals(1, filterToClaimType(searchResults, ClaimType.CARRIER).size());
CarrierClaimTransformerTest.assertMatches(carrierClaim, filterToClaimType(searchResults, ClaimType.CARRIER).get(0), Optional.empty());
DMEClaim dmeClaim = loadedRecords.stream().filter(r -> r instanceof DMEClaim).map(r -> (DMEClaim) r).findFirst().get();
DMEClaimTransformerTest.assertMatches(dmeClaim, filterToClaimType(searchResults, ClaimType.DME).get(0), Optional.empty());
HHAClaim hhaClaim = loadedRecords.stream().filter(r -> r instanceof HHAClaim).map(r -> (HHAClaim) r).findFirst().get();
HHAClaimTransformerTest.assertMatches(hhaClaim, filterToClaimType(searchResults, ClaimType.HHA).get(0));
HospiceClaim hospiceClaim = loadedRecords.stream().filter(r -> r instanceof HospiceClaim).map(r -> (HospiceClaim) r).findFirst().get();
HospiceClaimTransformerTest.assertMatches(hospiceClaim, filterToClaimType(searchResults, ClaimType.HOSPICE).get(0));
InpatientClaim inpatientClaim = loadedRecords.stream().filter(r -> r instanceof InpatientClaim).map(r -> (InpatientClaim) r).findFirst().get();
InpatientClaimTransformerTest.assertMatches(inpatientClaim, filterToClaimType(searchResults, ClaimType.INPATIENT).get(0));
OutpatientClaim outpatientClaim = loadedRecords.stream().filter(r -> r instanceof OutpatientClaim).map(r -> (OutpatientClaim) r).findFirst().get();
OutpatientClaimTransformerTest.assertMatches(outpatientClaim, filterToClaimType(searchResults, ClaimType.OUTPATIENT).get(0));
PartDEvent partDEvent = loadedRecords.stream().filter(r -> r instanceof PartDEvent).map(r -> (PartDEvent) r).findFirst().get();
PartDEventTransformerTest.assertMatches(partDEvent, filterToClaimType(searchResults, ClaimType.PDE).get(0));
SNFClaim snfClaim = loadedRecords.stream().filter(r -> r instanceof SNFClaim).map(r -> (SNFClaim) r).findFirst().get();
SNFClaimTransformerTest.assertMatches(snfClaim, filterToClaimType(searchResults, ClaimType.SNF).get(0));
}
use of gov.cms.bfd.model.rif.BeneficiaryHistory in project beneficiary-fhir-data by CMSgov.
the class RifLoaderIT method loadSampleU.
/**
* Runs {@link RifLoader} against the {@link StaticRifResourceGroup#SAMPLE_U} data.
*/
@Test
@Disabled
public void loadSampleU() {
loadSample(Arrays.asList(StaticRifResourceGroup.SAMPLE_A.getResources()));
loadSample(Arrays.asList(StaticRifResourceGroup.SAMPLE_U.getResources()));
verifyRecordPrimaryKeysPresent(Arrays.asList(StaticRifResourceGroup.SAMPLE_U.getResources()));
// Ensure no records were skipped
validateBeneficiaryAndSkippedCountsInDatabase(1, 0);
/*
* Verify that the updates worked as expected by manually checking some fields.
*/
EntityManagerFactory entityManagerFactory = PipelineTestUtils.get().getPipelineApplicationState().getEntityManagerFactory();
EntityManager entityManager = null;
try {
entityManager = entityManagerFactory.createEntityManager();
CriteriaQuery<BeneficiaryHistory> beneficiaryHistoryCriteria = entityManager.getCriteriaBuilder().createQuery(BeneficiaryHistory.class);
List<BeneficiaryHistory> beneficiaryHistoryEntries = entityManager.createQuery(beneficiaryHistoryCriteria.select(beneficiaryHistoryCriteria.from(BeneficiaryHistory.class))).getResultList();
for (BeneficiaryHistory beneHistory : beneficiaryHistoryEntries) {
assertEquals("567834", beneHistory.getBeneficiaryId());
// A recent lastUpdated timestamp
assertTrue(beneHistory.getLastUpdated().isPresent(), "Expected a lastUpdated field");
beneHistory.getLastUpdated().ifPresent(lastUpdated -> {
assertTrue(lastUpdated.isAfter(Instant.now().minus(10, ChronoUnit.MINUTES)), "Expected a recent lastUpdated timestamp");
});
}
assertEquals(4, beneficiaryHistoryEntries.size());
Beneficiary beneficiaryFromDb = entityManager.find(Beneficiary.class, "567834");
// Last Name inserted with value of "Johnson"
assertEquals("Johnson", beneficiaryFromDb.getNameSurname());
// Following fields were NOT changed in update record
assertEquals("John", beneficiaryFromDb.getNameGiven());
assertEquals(new Character('A'), beneficiaryFromDb.getNameMiddleInitial().get());
assertEquals(Optional.of("SSSS"), beneficiaryFromDb.getMedicareBeneficiaryId(), "Beneficiary has MBI");
assertEquals(Optional.of("401441595efcc68bc5b26f4e88bd9fa550004e068d69ff75761ab946ec553a02"), beneficiaryFromDb.getMbiHash(), "Beneficiary has mbiHash");
// A recent lastUpdated timestamp
assertTrue(beneficiaryFromDb.getLastUpdated().isPresent(), "Expected a lastUpdated field");
beneficiaryFromDb.getLastUpdated().ifPresent(lastUpdated -> {
assertTrue(lastUpdated.isAfter(Instant.now().minus(1, ChronoUnit.MINUTES)), "Expected a recent lastUpdated timestamp");
});
CarrierClaim carrierRecordFromDb = entityManager.find(CarrierClaim.class, "9991831999");
assertEquals('N', carrierRecordFromDb.getFinalAction());
// DateThrough inserted with value 10-27-1999
assertEquals(LocalDate.of(2000, Month.OCTOBER, 27), carrierRecordFromDb.getDateThrough());
assertEquals(1, carrierRecordFromDb.getLines().size());
// A recent lastUpdated timestamp
assertTrue(carrierRecordFromDb.getLastUpdated().isPresent(), "Expected a lastUpdated field");
carrierRecordFromDb.getLastUpdated().ifPresent(lastUpdated -> {
assertTrue(lastUpdated.isAfter(Instant.now().minus(1, ChronoUnit.MINUTES)), "Expected a recent lastUpdated timestamp");
});
CarrierClaimLine carrierLineRecordFromDb = carrierRecordFromDb.getLines().get(0);
// CliaLabNumber inserted with value BB889999AA
assertEquals("GG443333HH", carrierLineRecordFromDb.getCliaLabNumber().get());
} finally {
if (entityManager != null)
entityManager.close();
}
}
use of gov.cms.bfd.model.rif.BeneficiaryHistory in project beneficiary-fhir-data by CMSgov.
the class RifLoaderIT method assertAreInDatabase.
/**
* Verifies that the specified RIF records are actually in the database.
*
* @param options the {@link LoadAppOptions} to use
* @param entityManagerFactory the {@link EntityManagerFactory} to use
* @param records the RIF records to verify
*/
private static void assertAreInDatabase(LoadAppOptions options, EntityManagerFactory entityManagerFactory, Stream<Object> records) {
EntityManager entityManager = null;
try {
entityManager = entityManagerFactory.createEntityManager();
for (Object record : records.collect(Collectors.toList())) {
/*
* We need to handle BeneficiaryHistory separately, as it has a generated ID.
*/
if (record instanceof BeneficiaryHistory) {
BeneficiaryHistory beneficiaryHistoryToFind = (BeneficiaryHistory) record;
beneficiaryHistoryToFind.setHicn(RifLoader.computeHicnHash(new IdHasher(options.getIdHasherConfig()), beneficiaryHistoryToFind.getHicn()));
beneficiaryHistoryToFind.setMbiHash(beneficiaryHistoryToFind.getMedicareBeneficiaryId().isPresent() ? Optional.of(RifLoader.computeMbiHash(new IdHasher(options.getIdHasherConfig()), beneficiaryHistoryToFind.getMedicareBeneficiaryId().get())) : Optional.empty());
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<BeneficiaryHistory> query = criteriaBuilder.createQuery(BeneficiaryHistory.class);
Root<BeneficiaryHistory> from = query.from(BeneficiaryHistory.class);
query.select(from).where(criteriaBuilder.equal(from.get(BeneficiaryHistory_.beneficiaryId), beneficiaryHistoryToFind.getBeneficiaryId()), criteriaBuilder.equal(from.get(BeneficiaryHistory_.birthDate), beneficiaryHistoryToFind.getBirthDate()), criteriaBuilder.equal(from.get(BeneficiaryHistory_.sex), beneficiaryHistoryToFind.getSex()), criteriaBuilder.equal(from.get(BeneficiaryHistory_.hicn), beneficiaryHistoryToFind.getHicn()), criteriaBuilder.equal(from.get(BeneficiaryHistory_.mbiHash), beneficiaryHistoryToFind.getMbiHash().orElse(null)));
List<BeneficiaryHistory> beneficiaryHistoryFound = entityManager.createQuery(query).getResultList();
assertNotNull(beneficiaryHistoryFound);
assertFalse(beneficiaryHistoryFound.isEmpty());
} else {
Object recordId = entityManagerFactory.getPersistenceUnitUtil().getIdentifier(record);
Object recordFromDb = entityManager.find(record.getClass(), recordId);
assertNotNull(recordFromDb);
}
}
} finally {
if (entityManager != null)
entityManager.close();
}
}
use of gov.cms.bfd.model.rif.BeneficiaryHistory in project beneficiary-fhir-data by CMSgov.
the class R4PatientResourceProvider method queryDatabaseByHash.
/**
* @param hash the {@link Beneficiary} hash value to match
* @param hashType a string to represent the hash type (used for logging purposes)
* @param requestHeader the {@link #RequestHeaders} where resource request headers are
* encapsulated
* @param beneficiaryHashField the JPA location of the beneficiary hash field
* @param beneficiaryHistoryHashField the JPA location of the beneficiary history hash field
* @return a FHIR {@link Patient} for the CCW {@link Beneficiary} that matches the specified
* {@link Beneficiary} hash value
* @throws NoResultException A {@link NoResultException} will be thrown if no matching {@link
* Beneficiary} can be found
*/
@Trace
private Patient queryDatabaseByHash(String hash, String hashType, SingularAttribute<Beneficiary, String> beneficiaryHashField, SingularAttribute<BeneficiaryHistory, String> beneficiaryHistoryHashField, RequestHeaders requestHeader) {
if (hash == null || hash.trim().isEmpty()) {
throw new IllegalArgumentException();
}
/*
* Beneficiaries' MBIs can change over time and those past MBIs may land in
* BeneficiaryHistory records. Accordingly, we need to search for matching MBIs in both the
* Beneficiary and the BeneficiaryHistory records.
*
* There's no sane way to do this in a single query with JPA 2.1, it appears: JPA doesn't
* support UNIONs and it doesn't support subqueries in FROM clauses. That said, the ideal query
* would look like this:
*
* SELECT * FROM ( SELECT DISTINCT "beneficiaryId" FROM "Beneficiaries" WHERE "hicn" =
* :'hicn_hash' UNION SELECT DISTINCT "beneficiaryId" FROM "BeneficiariesHistory" WHERE "hicn" =
* :'hicn_hash') AS matching_benes INNER JOIN "Beneficiaries" ON matching_benes."beneficiaryId"
* = "Beneficiaries"."beneficiaryId" LEFT JOIN "BeneficiariesHistory" ON
* "Beneficiaries"."beneficiaryId" = "BeneficiariesHistory"."beneficiaryId" LEFT JOIN
* "MedicareBeneficiaryIdHistory" ON "Beneficiaries"."beneficiaryId" =
* "MedicareBeneficiaryIdHistory"."beneficiaryId";
*
* ... with the returned columns and JOINs being dynamic, depending on IncludeIdentifiers.
*
* In lieu of that, we run two queries: one to find MBI matches in BeneficiariesHistory,
* and a second to find BENE_ID or MBI matches in Beneficiaries (with all of their data, so
* we're ready to return the result). This is bad and dumb but I can't find a better working
* alternative.
*
* (I'll just note that I did also try JPA/Hibernate native SQL queries but couldn't get the
* joins or fetch groups to work with them.)
*
* If we want to fix this, we need to move identifiers out entirely to separate tables:
* i.e., BeneficiaryMbis. We could then safely query these tables and join them
* back to Beneficiaries (and hopefully the optimizer will play nice, too).
*/
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
// First, find all matching hashes from BeneficiariesHistory.
CriteriaQuery<String> beneHistoryMatches = builder.createQuery(String.class);
Root<BeneficiaryHistory> beneHistoryMatchesRoot = beneHistoryMatches.from(BeneficiaryHistory.class);
beneHistoryMatches.select(beneHistoryMatchesRoot.get(BeneficiaryHistory_.beneficiaryId)).where(builder.equal(beneHistoryMatchesRoot.get(beneficiaryHistoryHashField), hash));
List<String> matchingIdsFromBeneHistory = null;
Long fromHistoryQueryNanoSeconds = null;
Timer.Context beneHistoryMatchesTimer = metricRegistry.timer(MetricRegistry.name(getClass().getSimpleName(), "query", "bene_by_" + hashType, hashType + "s_from_beneficiarieshistory")).time();
try {
matchingIdsFromBeneHistory = entityManager.createQuery(beneHistoryMatches).getResultList();
} finally {
fromHistoryQueryNanoSeconds = beneHistoryMatchesTimer.stop();
TransformerUtilsV2.recordQueryInMdc("bene_by_" + hashType + "." + hashType + "s_from_beneficiarieshistory", fromHistoryQueryNanoSeconds, matchingIdsFromBeneHistory == null ? 0 : matchingIdsFromBeneHistory.size());
}
// Then, find all Beneficiary records that match the hash or those BENE_IDs.
CriteriaQuery<Beneficiary> beneMatches = builder.createQuery(Beneficiary.class);
Root<Beneficiary> beneMatchesRoot = beneMatches.from(Beneficiary.class);
beneMatchesRoot.fetch(Beneficiary_.skippedRifRecords, JoinType.LEFT);
// BFD379: in original V2, if check is commented out
if (requestHeader.isMBIinIncludeIdentifiers()) {
beneMatchesRoot.fetch(Beneficiary_.medicareBeneficiaryIdHistories, JoinType.LEFT);
}
beneMatches.select(beneMatchesRoot);
Predicate beneHashMatches = builder.equal(beneMatchesRoot.get(beneficiaryHashField), hash);
if (matchingIdsFromBeneHistory != null && !matchingIdsFromBeneHistory.isEmpty()) {
Predicate beneHistoryHashMatches = beneMatchesRoot.get(Beneficiary_.beneficiaryId).in(matchingIdsFromBeneHistory);
beneMatches.where(builder.or(beneHashMatches, beneHistoryHashMatches));
} else {
beneMatches.where(beneHashMatches);
}
List<Beneficiary> matchingBenes = Collections.emptyList();
Long benesByHashOrIdQueryNanoSeconds = null;
Timer.Context timerQuery = metricRegistry.timer(MetricRegistry.name(getClass().getSimpleName(), "query", "bene_by_" + hashType, "bene_by_" + hashType + "_or_id")).time();
try {
matchingBenes = entityManager.createQuery(beneMatches).getResultList();
} finally {
benesByHashOrIdQueryNanoSeconds = timerQuery.stop();
TransformerUtilsV2.recordQueryInMdc(String.format("bene_by_" + hashType + ".bene_by_" + hashType + "_or_id.include_%s", String.join("_", (List<String>) requestHeader.getValue(HEADER_NAME_INCLUDE_IDENTIFIERS))), benesByHashOrIdQueryNanoSeconds, matchingBenes.size());
}
// Then, if we found more than one distinct BENE_ID, or none, throw an error.
long distinctBeneIds = matchingBenes.stream().map(Beneficiary::getBeneficiaryId).filter(Objects::nonNull).distinct().count();
Beneficiary beneficiary = null;
if (distinctBeneIds <= 0) {
throw new NoResultException();
} else if (distinctBeneIds > 1) {
MDC.put("database_query.by_hash.collision.distinct_bene_ids", Long.toString(distinctBeneIds));
throw new ResourceNotFoundException("By hash query found more than one distinct BENE_ID: " + Long.toString(distinctBeneIds));
} else if (distinctBeneIds == 1) {
beneficiary = matchingBenes.get(0);
}
// Null out the unhashed HICNs; in v2 we are ignoring HICNs
beneficiary.setHicnUnhashed(Optional.empty());
Patient patient = BeneficiaryTransformerV2.transform(metricRegistry, beneficiary, requestHeader);
return patient;
}
Aggregations