package ca.uhn.fhir.jpa.dao; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.equalToIgnoringCase; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Map; import javax.persistence.EntityManager; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.transaction.PlatformTransactionManager; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.config.TestDstu1Config; import ca.uhn.fhir.jpa.entity.TagTypeEnum; import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc; import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc; import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.BundleEntry; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.dstu.composite.IdentifierDt; import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; import ca.uhn.fhir.model.dstu.resource.Location; import ca.uhn.fhir.model.dstu.resource.Observation; import ca.uhn.fhir.model.dstu.resource.Patient; import ca.uhn.fhir.model.dstu2.composite.MetaDt; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.server.IBundleProvider; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.util.TestUtil; public class FhirSystemDaoDstu1Test extends BaseJpaTest { private static AnnotationConfigApplicationContext ourCtx; private static EntityManager ourEntityManager; private static FhirContext ourFhirContext; private static IFhirResourceDao<Location> ourLocationDao; private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoDstu1Test.class); private static IFhirResourceDao<Observation> ourObservationDao; private static IFhirResourceDao<Patient> ourPatientDao; private static IFhirSystemDao<List<IResource>, MetaDt> ourSystemDao; private static PlatformTransactionManager ourTxManager; private static ISearchParamPresenceSvc ourSearchParamPresenceSvc; private static ISearchCoordinatorSvc ourSearchCoordinatorSvc; @Before public void before() { super.purgeDatabase(ourEntityManager, ourTxManager, ourSearchParamPresenceSvc, ourSearchCoordinatorSvc); } @Override protected FhirContext getContext() { return ourFhirContext; } @Test public void testGetResourceCounts() { Observation obs = new Observation(); obs.getName().addCoding().setSystem("urn:system").setCode("testGetResourceCountsO01"); ourObservationDao.create(obs, mySrd); Map<String, Long> oldCounts = ourSystemDao.getResourceCounts(); Patient patient = new Patient(); patient.addIdentifier().setSystem("urn:system").setValue("testGetResourceCountsP01"); patient.addName().addFamily("Tester").addGiven("Joe"); ourPatientDao.create(patient, mySrd); Map<String, Long> newCounts = ourSystemDao.getResourceCounts(); if (oldCounts.containsKey("Patient")) { assertEquals(oldCounts.get("Patient") + 1, (long) newCounts.get("Patient")); } else { assertEquals(1L, (long) newCounts.get("Patient")); } assertEquals((long) oldCounts.get("Observation"), (long) newCounts.get("Observation")); } @Test public void testHistory() throws Exception { Date start = new Date(); Thread.sleep(10); Patient patient = new Patient(); patient.addIdentifier().setSystem("urn:system").setValue("testHistory"); patient.addName().addFamily("Tester").addGiven("Joe"); IIdType pid = ourPatientDao.create(patient, mySrd).getId().toVersionless(); Thread.sleep(10); patient.addName().addFamily("A"); patient.setId(pid); IIdType newpid = ourPatientDao.update(patient, mySrd).getId(); Thread.sleep(10); patient.addName().addFamily("B"); patient.setId(pid); IIdType newpid2 = ourPatientDao.update(patient, mySrd).getId(); Thread.sleep(10); patient.addName().addFamily("C"); patient.setId(pid); IIdType newpid3 = ourPatientDao.update(patient, mySrd).getId(); IBundleProvider values = ourSystemDao.history(start, null, mySrd); assertEquals(4, values.size().intValue()); List<IBaseResource> res = values.getResources(0, 4); assertEquals(newpid3, res.get(0).getIdElement()); assertEquals(newpid2, res.get(1).getIdElement()); assertEquals(newpid, res.get(2).getIdElement()); assertEquals(pid.toUnqualifiedVersionless(), res.get(3).getIdElement().toUnqualifiedVersionless()); Location loc = new Location(); loc.getAddress().addLine("AAA"); IIdType lid = ourLocationDao.create(loc, mySrd).getId(); Location loc2 = new Location(); loc2.getAddress().addLine("AAA"); ourLocationDao.create(loc2, mySrd).getId(); Thread.sleep(2000); values = ourLocationDao.history(start, null, mySrd); assertEquals(2, values.size().intValue()); values = ourLocationDao.history(lid.toUnqualifiedVersionless(), start, null, mySrd); assertEquals(1, values.size().intValue()); } @Test public void testPersistWithSimpleLink() { Patient patient = new Patient(); patient.setId(new IdDt("Patient/testPersistWithSimpleLinkP01")); patient.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP01"); patient.addName().addFamily("Tester").addGiven("Joe"); Observation obs = new Observation(); obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01"); obs.setSubject(new ResourceReferenceDt("Patient/testPersistWithSimpleLinkP01")); ourSystemDao.transaction(mySrd, Arrays.asList((IResource) patient, obs)); String patientId = (patient.getId().getIdPart()); String obsId = (obs.getId().getIdPart()); // assertThat(patientId, greaterThan(0L)); // assertEquals(patientVersion, 1L); // assertThat(obsId, greaterThan(patientId)); // assertEquals(obsVersion, 1L); // Try to search IBundleProvider obsResults = ourObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_NAME, new IdentifierDt("urn:system", "testPersistWithSimpleLinkO01"))); assertEquals(1, obsResults.size().intValue()); IBundleProvider patResults = ourPatientDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Patient.SP_IDENTIFIER, new IdentifierDt("urn:system", "testPersistWithSimpleLinkP01"))); assertEquals(1, obsResults.size().intValue()); IIdType foundPatientId = patResults.getResources(0, 1).get(0).getIdElement(); ResourceReferenceDt subject = obs.getSubject(); assertEquals(foundPatientId.getIdPart(), subject.getReference().getIdPart()); // Update patient = (Patient) patResults.getResources(0, 1).get(0); obs = (Observation) obsResults.getResources(0, 1).get(0); patient.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP02"); obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO02"); ourSystemDao.transaction(mySrd, Arrays.asList((IResource) patient, obs)); String patientId2 = (patient.getId().getIdPart()); String patientVersion2 = (patient.getId().getVersionIdPart()); String obsId2 = (obs.getId().getIdPart()); String obsVersion2 = (obs.getId().getVersionIdPart()); assertEquals(patientId, patientId2); assertEquals(patientVersion2, "2"); assertEquals(obsId, obsId2); assertEquals(obsVersion2, "2"); } @Test public void testPersistWithUnknownId() { Observation obs = new Observation(); obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01"); obs.setSubject(new ResourceReferenceDt("Patient/999998888888")); try { ourSystemDao.transaction(mySrd, Arrays.asList((IResource) obs)); } catch (InvalidRequestException e) { assertThat(e.getMessage(), containsString("Resource Patient/999998888888 not found, specified in path: Observation.subject")); } obs = new Observation(); obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01"); obs.setSubject(new ResourceReferenceDt("Patient/1.2.3.4")); try { ourSystemDao.transaction(mySrd, Arrays.asList((IResource) obs)); } catch (InvalidRequestException e) { assertThat(e.getMessage(), containsString("Resource Patient/1.2.3.4 not found, specified in path: Observation.subject")); } } @Test public void testTagOperationss() throws Exception { TagList preSystemTl = ourSystemDao.getAllTags(mySrd); TagList tl1 = new TagList(); tl1.addTag("testGetAllTagsScheme1", "testGetAllTagsTerm1", "testGetAllTagsLabel1"); Patient p1 = new Patient(); p1.addIdentifier().setSystem("foo").setValue("testGetAllTags01"); ResourceMetadataKeyEnum.TAG_LIST.put(p1, tl1); ourPatientDao.create(p1, mySrd); TagList tl2 = new TagList(); tl2.addTag("testGetAllTagsScheme2", "testGetAllTagsTerm2", "testGetAllTagsLabel2"); Observation o1 = new Observation(); o1.getName().setText("testGetAllTags02"); ResourceMetadataKeyEnum.TAG_LIST.put(o1, tl2); IIdType o1id = ourObservationDao.create(o1, mySrd).getId(); assertTrue(o1id.getVersionIdPart() != null); TagList postSystemTl = ourSystemDao.getAllTags(mySrd); assertEquals(preSystemTl.size() + 2, postSystemTl.size()); assertEquals("testGetAllTagsLabel1", postSystemTl.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1").getLabel()); TagList tags = ourPatientDao.getAllResourceTags(mySrd); assertEquals("testGetAllTagsLabel1", tags.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1").getLabel()); assertNull(tags.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2")); TagList tags2 = ourObservationDao.getTags(o1id, mySrd); assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1")); assertEquals("testGetAllTagsLabel2", tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2").getLabel()); o1.setId(o1id); IIdType o1id2 = ourObservationDao.update(o1, mySrd).getId(); assertTrue(o1id2.getVersionIdPart() != null); tags2 = ourObservationDao.getTags(o1id, mySrd); assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1")); assertEquals("testGetAllTagsLabel2", tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2").getLabel()); tags2 = ourObservationDao.getTags(o1id2, mySrd); assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1")); assertNotNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2")); /* * Remove a tag from a version */ ourObservationDao.removeTag(o1id2, TagTypeEnum.TAG, "testGetAllTagsScheme2", "testGetAllTagsTerm2", mySrd); tags2 = ourObservationDao.getTags(o1id2, mySrd); assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1")); assertNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2")); tags2 = ourObservationDao.getTags(o1id, mySrd); assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1")); assertNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2")); /* * Add a tag */ ourObservationDao.addTag(o1id2, TagTypeEnum.TAG, "testGetAllTagsScheme3", "testGetAllTagsTerm3", "testGetAllTagsLabel3"); tags2 = ourObservationDao.getTags(o1id2, mySrd); assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1")); assertNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2")); assertNotNull(tags2.getTag("testGetAllTagsScheme3", "testGetAllTagsTerm3")); assertEquals("testGetAllTagsLabel3", tags2.getTag("testGetAllTagsScheme3", "testGetAllTagsTerm3").getLabel()); tags2 = ourObservationDao.getTags(o1id, mySrd); assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1")); assertNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2")); } @Test(expected = InvalidRequestException.class) public void testTransactionFailsWithDuplicateIds() { Patient patient1 = new Patient(); patient1.setId(new IdDt("Patient/testTransactionFailsWithDusplicateIds")); patient1.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP01"); Patient patient2 = new Patient(); patient2.setId(new IdDt("Patient/testTransactionFailsWithDusplicateIds")); patient2.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP02"); ourSystemDao.transaction(mySrd, Arrays.asList((IResource) patient1, patient2)); } @Test public void testTransactionFromBundle() throws Exception { InputStream bundleRes = FhirSystemDaoDstu1Test.class.getResourceAsStream("/bundle-dstu1.xml"); Bundle bundle = ourFhirContext.newXmlParser().parseBundle(new InputStreamReader(bundleRes)); List<IResource> res = bundle.toListOfResources(); ourSystemDao.transaction(mySrd, res); Patient p1 = (Patient) res.get(0); String id = p1.getId().getValue(); ourLog.info("ID: {}", id); assertThat(id, not(equalToIgnoringCase("74635"))); assertThat(id, not(equalToIgnoringCase(""))); } /** * Issue #55. Note that this is the incorrect way to do this but we'll leave it since people may depend on it. */ @Test public void testTransactionWithCidIds() throws Exception { List<IResource> res = new ArrayList<IResource>(); Patient p1 = new Patient(); p1.setId("cid:patient1"); p1.addIdentifier().setSystem("system").setValue("testTransactionWithCidIds01"); res.add(p1); Observation o1 = new Observation(); o1.setId("cid:observation1"); o1.getIdentifier().setSystem("system").setValue("testTransactionWithCidIds02"); o1.setSubject(new ResourceReferenceDt("Patient/cid:patient1")); res.add(o1); Observation o2 = new Observation(); o2.setId("cid:observation2"); o2.getIdentifier().setSystem("system").setValue("testTransactionWithCidIds03"); o2.setSubject(new ResourceReferenceDt("Patient/cid:patient1")); res.add(o2); ourSystemDao.transaction(mySrd, res); assertTrue(p1.getId().getValue(), p1.getId().getIdPart().matches("^[0-9]+$")); assertTrue(o1.getId().getValue(), o1.getId().getIdPart().matches("^[0-9]+$")); assertTrue(o2.getId().getValue(), o2.getId().getIdPart().matches("^[0-9]+$")); assertThat(o1.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart())); assertThat(o2.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart())); } @Test public void testTransactionWithCidIds2() throws Exception { String resource = "/dstu1_bundle.xml"; String bundleStr = loadClasspath(resource); Bundle bundle = ourFhirContext.newXmlParser().parseBundle(bundleStr); List<IResource> res = new ArrayList<IResource>(); for (BundleEntry next : bundle.getEntries()) { res.add(next.getResource()); } List<IResource> response = ourSystemDao.transaction(mySrd, res); String encodeResourceToString = ourFhirContext.newXmlParser().setPrettyPrint(true).encodeResourceToString(response.get(0)); ourLog.info(encodeResourceToString); assertThat(encodeResourceToString, not(containsString("smsp"))); } /** * This is the correct way to do this, not {@link #testTransactionWithCidIds()} */ @Test public void testTransactionWithCidIdsUnqualified() throws Exception { List<IResource> res = new ArrayList<IResource>(); Patient p1 = new Patient(); p1.setId("cid:patient1"); p1.addIdentifier().setSystem("system").setValue("testTransactionWithCidIdsUnqualified01"); res.add(p1); Observation o1 = new Observation(); o1.setId("cid:observation1"); o1.getIdentifier().setSystem("system").setValue("testTransactionWithCidIdsUnqualified02"); o1.setSubject(new ResourceReferenceDt("cid:patient1")); res.add(o1); Observation o2 = new Observation(); o2.setId("cid:observation2"); o2.getIdentifier().setSystem("system").setValue("testTransactionWithCidIdsUnqualified03"); o2.setSubject(new ResourceReferenceDt("cid:patient1")); res.add(o2); ourSystemDao.transaction(mySrd, res); assertTrue(p1.getId().getValue(), p1.getId().getIdPart().matches("^[0-9]+$")); assertTrue(o1.getId().getValue(), o1.getId().getIdPart().matches("^[0-9]+$")); assertTrue(o2.getId().getValue(), o2.getId().getIdPart().matches("^[0-9]+$")); assertThat(o1.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart())); assertThat(o2.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart())); } @Test public void testTransactionWithDelete() throws Exception { /* * Create 3 */ List<IResource> res; res = new ArrayList<IResource>(); Patient p1 = new Patient(); p1.addIdentifier().setSystem("urn:system").setValue("testTransactionWithDelete"); res.add(p1); Patient p2 = new Patient(); p2.addIdentifier().setSystem("urn:system").setValue("testTransactionWithDelete"); res.add(p2); Patient p3 = new Patient(); p3.addIdentifier().setSystem("urn:system").setValue("testTransactionWithDelete"); res.add(p3); ourSystemDao.transaction(mySrd, res); /* * Verify */ IBundleProvider results = ourPatientDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Patient.SP_IDENTIFIER, new TokenParam("urn:system", "testTransactionWithDelete"))); assertEquals(3, results.size().intValue()); /* * Now delete 2 */ res = new ArrayList<IResource>(); List<IBaseResource> existing = results.getResources(0, 3); p1 = new Patient(); p1.setId(existing.get(0).getIdElement()); ResourceMetadataKeyEnum.DELETED_AT.put(p1, InstantDt.withCurrentTime()); res.add(p1); p2 = new Patient(); p2.setId(existing.get(1).getIdElement()); ResourceMetadataKeyEnum.DELETED_AT.put(p2, InstantDt.withCurrentTime()); res.add(p2); ourSystemDao.transaction(mySrd, res); /* * Verify */ IBundleProvider results2 = ourPatientDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Patient.SP_IDENTIFIER, new TokenParam("urn:system", "testTransactionWithDelete"))); assertEquals(1, results2.size().intValue()); List<IBaseResource> existing2 = results2.getResources(0, 1); assertEquals(existing2.get(0).getIdElement(), existing.get(2).getIdElement()); } @AfterClass public static void afterClassClearContext() { ourCtx.close(); TestUtil.clearAllStaticFieldsForUnitTest(); } @SuppressWarnings("unchecked") @BeforeClass public static void beforeClass() { ourCtx = new AnnotationConfigApplicationContext(TestDstu1Config.class); ourFhirContext = ourCtx.getBean("myFhirContextDstu1", FhirContext.class); ourPatientDao = ourCtx.getBean("myPatientDaoDstu1", IFhirResourceDao.class); ourObservationDao = ourCtx.getBean("myObservationDaoDstu1", IFhirResourceDao.class); ourLocationDao = ourCtx.getBean("myLocationDaoDstu1", IFhirResourceDao.class); ourSystemDao = ourCtx.getBean("mySystemDaoDstu1", IFhirSystemDao.class); ourEntityManager = ourCtx.getBean(EntityManager.class); ourTxManager = ourCtx.getBean(PlatformTransactionManager.class); ourSearchParamPresenceSvc = ourCtx.getBean(ISearchParamPresenceSvc.class); ourSearchCoordinatorSvc = ourCtx.getBean(ISearchCoordinatorSvc.class); } }