Merge branch 'master' into improve_jpa_indexes

This commit is contained in:
jamesagnew 2018-06-24 15:15:31 -04:00
commit 9a880361b6
17 changed files with 5909 additions and 5523 deletions

View File

@ -1610,8 +1610,19 @@ public class SearchBuilder implements ISearchBuilder {
//-- preload all tags with tag definition if any
Map<Long, Collection<ResourceTag>> tagMap = getResourceTagMap(resultList);
//-- pre-load all forcedId
Map<Long, ForcedId> forcedIdMap = getForcedIdMap(pids);
ForcedId forcedId = null;
Long resourceId = null;
for (ResourceTable next : resultList) {
Class<? extends IBaseResource> resourceType = context.getResourceDefinition(next.getResourceType()).getImplementingClass();
resourceId = next.getId();
forcedId = forcedIdMap.get(resourceId);
if (forcedId != null)
next.setForcedId(forcedId);
IBaseResource resource = theDao.toResource(resourceType, next, historyMap.get(next.getId()), tagMap.get(next.getId()), theForHistoryOperation);
if (resource == null) {
ourLog.warn("Unable to find resource {}/{}/_history/{} in database", next.getResourceType(), next.getIdDt().getIdPart(), next.getVersion());
@ -1697,6 +1708,23 @@ public class SearchBuilder implements ISearchBuilder {
return tagMap;
}
//-- load all forcedId in to the map
private Map<Long, ForcedId> getForcedIdMap(Collection<Long> pids) {
Map<Long, ForcedId> forceIdMap = new HashMap<Long, ForcedId>();
if (pids.size() == 0)
return forceIdMap;
Collection<ForcedId> forceIdList = myForcedIdDao.findByResourcePids(pids);
for (ForcedId forcedId : forceIdList) {
forceIdMap.put(forcedId.getResourcePid(), forcedId);
}
return forceIdMap;
}
@Override
public void loadResourcesByPid(Collection<Long> theIncludePids, List<IBaseResource> theResourceListToPopulate, Set<Long> theRevIncludedPids, boolean theForHistoryOperation,
EntityManager entityManager, FhirContext context, IDao theDao) {

View File

@ -1,5 +1,6 @@
package ca.uhn.fhir.jpa.dao.data;
import java.util.Collection;
import java.util.List;
/*
@ -38,5 +39,7 @@ public interface IForcedIdDao extends JpaRepository<ForcedId, Long> {
@Query("SELECT f FROM ForcedId f WHERE f.myResourcePid = :resource_pid")
public ForcedId findByResourcePid(@Param("resource_pid") Long theResourcePid);
@Query("SELECT f FROM ForcedId f WHERE f.myResourcePid in (:pids)")
Collection<ForcedId> findByResourcePids(@Param("pids") Collection<Long> pids);
}

View File

@ -42,7 +42,7 @@ public abstract class BaseHasResource {
@OptimisticLock(excluded = true)
private FhirVersionEnum myFhirVersion;
@OneToOne(optional = true, fetch = FetchType.EAGER, cascade = {}, orphanRemoval = false)
@OneToOne(optional = true, fetch = FetchType.LAZY, cascade = {}, orphanRemoval = false)
@JoinColumn(name = "FORCED_ID_PID")
@OptimisticLock(excluded = true)
private ForcedId myForcedId;

View File

@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.entity;
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

View File

@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term;
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

View File

@ -64,7 +64,6 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
}
}
@Test
public void testCreateInvalidParamNoPath() {
SearchParameter fooSp = new SearchParameter();
@ -858,6 +857,49 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
}
@Test
public void testSearchParameterDescendsIntoContainedResource() {
SearchParameter sp = new SearchParameter();
sp.addBase("Observation");
sp.setCode("specimencollectedtime");
sp.setType(Enumerations.SearchParamType.DATE);
sp.setTitle("Observation Specimen Collected Time");
sp.setExpression("Observation.specimen.resolve().receivedTime");
sp.setXpathUsage(SearchParameter.XPathUsageType.NORMAL);
sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(sp));
mySearchParameterDao.create(sp);
mySearchParamRegsitry.forceRefresh();
Specimen specimen = new Specimen();
specimen.setId("#FOO");
specimen.setReceivedTimeElement(new DateTimeType("2011-01-01"));
Observation o = new Observation();
o.setId("O1");
o.getContained().add(specimen);
o.setStatus(Observation.ObservationStatus.FINAL);
o.setSpecimen(new Reference("#FOO"));
myObservationDao.update(o);
specimen = new Specimen();
specimen.setId("#FOO");
specimen.setReceivedTimeElement(new DateTimeType("2011-01-03"));
o = new Observation();
o.setId("O2");
o.getContained().add(specimen);
o.setStatus(Observation.ObservationStatus.FINAL);
o.setSpecimen(new Reference("#FOO"));
myObservationDao.update(o);
SearchParameterMap params = new SearchParameterMap();
params.add("specimencollectedtime", new DateParam("2011-01-01"));
IBundleProvider outcome = myObservationDao.search(params);
List<String> ids = toUnqualifiedVersionlessIdValues(outcome);
ourLog.info("IDS: " + ids);
assertThat(ids, contains("Observation/O1"));
}
@Test
public void testSearchWithCustomParam() {

View File

@ -128,7 +128,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
}
@Test
public void testCreateSearchParameterOnSearchParameterDoesntCauseEndlessReindexLoop() throws InterruptedException {
public void testCreateSearchParameterOnSearchParameterDoesntCauseEndlessReindexLoop() {
SearchParameter fooSp = new SearchParameter();
fooSp.setCode("foo");
fooSp.addBase("SearchParameter");
@ -175,6 +175,48 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
assertThat(ids, contains(pid.getValue()));
}
@Test
public void testSearchParameterDescendsIntoContainedResource() {
SearchParameter sp = new SearchParameter();
sp.addBase("Observation");
sp.setCode("specimencollectedtime");
sp.setType(Enumerations.SearchParamType.DATE);
sp.setTitle("Observation Specimen Collected Time");
sp.setExpression("Observation.specimen.resolve().receivedTime");
sp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
sp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
mySearchParameterDao.create(sp);
mySearchParamRegsitry.forceRefresh();
Specimen specimen = new Specimen();
specimen.setId("#FOO");
specimen.setReceivedTimeElement(new DateTimeType("2011-01-01"));
Observation o = new Observation();
o.setId("O1");
o.getContained().add(specimen);
o.setStatus(Observation.ObservationStatus.FINAL);
o.setSpecimen(new Reference("#FOO"));
myObservationDao.update(o);
specimen = new Specimen();
specimen.setId("#FOO");
specimen.setReceivedTimeElement(new DateTimeType("2011-01-03"));
o = new Observation();
o.setId("O2");
o.getContained().add(specimen);
o.setStatus(Observation.ObservationStatus.FINAL);
o.setSpecimen(new Reference("#FOO"));
myObservationDao.update(o);
SearchParameterMap params = new SearchParameterMap();
params.add("specimencollectedtime", new DateParam("2011-01-01"));
IBundleProvider outcome = myObservationDao.search(params);
List<String> ids = toUnqualifiedVersionlessIdValues(outcome);
ourLog.info("IDS: " + ids);
assertThat(ids, contains("Observation/O1"));
}
@Test
public void testExtensionWithNoValueIndexesWithoutFailure() {
SearchParameter eyeColourSp = new SearchParameter();

View File

@ -9,9 +9,9 @@ package ca.uhn.fhir.rest.server;
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.rest.server.interceptor.auth;
/*-
* #%L
* HAPI FHIR - Server Framework
* %%
* Copyright (C) 2014 - 2018 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.Collection;
/**

View File

@ -9,9 +9,9 @@ package ca.uhn.fhir.rest.server.interceptor.auth;
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

View File

@ -36,9 +36,9 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

View File

@ -1,45 +1,59 @@
package org.hl7.fhir.dstu3.utils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.List;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.dstu3.hapi.validation.DefaultProfileValidationSupport;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.util.TestUtil;
import org.hl7.fhir.dstu3.hapi.ctx.HapiWorkerContext;
import org.hl7.fhir.dstu3.hapi.validation.DefaultProfileValidationSupport;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.exceptions.FHIRException;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.util.TestUtil;
import java.util.List;
import static org.junit.Assert.*;
public class FhirPathEngineTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirPathEngineTest.class);
private static FhirContext ourCtx = FhirContext.forDstu3();
private static FHIRPathEngine ourEngine;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirPathEngineTest.class);
@Test
public void testAs() throws Exception {
Observation obs = new Observation();
obs.setValue(new StringType("FOO"));
List<Base> value = ourEngine.evaluate(obs, "Observation.value.as(String)");
assertEquals(1, value.size());
assertEquals("FOO", ((StringType)value.get(0)).getValue());
assertEquals("FOO", ((StringType) value.get(0)).getValue());
}
@Test
public void testCrossResourceBoundaries() throws FHIRException {
Specimen specimen = new Specimen();
specimen.setId("#FOO");
specimen.setReceivedTimeElement(new DateTimeType("2011-01-01"));
Observation o = new Observation();
o.getContained().add(specimen);
o.setId("O1");
o.setStatus(Observation.ObservationStatus.FINAL);
o.setSpecimen(new Reference("#FOO"));
List<Base> value = ourEngine.evaluate(o, "Observation.specimen.resolve().receivedTime");
assertEquals(1, value.size());
assertEquals("2011-01-01", ((DateTimeType) value.get(0)).getValueAsString());
}
@Test
public void testExistsWithNoValue() throws FHIRException {
Patient patient = new Patient();
patient.setDeceased(new BooleanType());
List<Base> eval = ourEngine.evaluate(patient, "Patient.deceased.exists()");
ourLog.info(eval.toString());
assertFalse(((BooleanType)eval.get(0)).getValue());
assertFalse(((BooleanType) eval.get(0)).getValue());
}
@Test
@ -48,7 +62,7 @@ public class FhirPathEngineTest {
patient.setDeceased(new BooleanType(false));
List<Base> eval = ourEngine.evaluate(patient, "Patient.deceased.exists()");
ourLog.info(eval.toString());
assertTrue(((BooleanType)eval.get(0)).getValue());
assertTrue(((BooleanType) eval.get(0)).getValue());
}
@AfterClass

View File

@ -3,14 +3,12 @@ package org.hl7.fhir.r4.utils;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.util.TestUtil;
import org.hl7.fhir.dstu3.utils.FhirPathEngineTest;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport;
import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.utils.FHIRPathEngine;
import org.hl7.fhir.exceptions.FHIRException;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import java.util.List;
@ -23,6 +21,23 @@ public class FhirPathEngineR4Test {
private static FHIRPathEngine ourEngine;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirPathEngineTest.class);
@Test
public void testCrossResourceBoundaries() throws FHIRException {
Specimen specimen = new Specimen();
specimen.setId("#FOO");
specimen.setReceivedTimeElement(new DateTimeType("2011-01-01"));
Observation o = new Observation();
o.getContained().add(specimen);
o.setId("O1");
o.setStatus(Observation.ObservationStatus.FINAL);
o.setSpecimen(new Reference("#FOO"));
List<Base> value = ourEngine.evaluate(o, "Observation.specimen.resolve().receivedTime");
assertEquals(1, value.size());
assertEquals("2011-01-01", ((DateTimeType) value.get(0)).getValueAsString());
}
@Test
public void testAs() throws Exception {
Observation obs = new Observation();

View File

@ -459,6 +459,11 @@
<id>Romanow88</id>
<name>Roman Doboni</name>
</developer>
<developer>
<id>franktao2008</id>
<name>Frank Tao</name>
<organization>Smile CDR</organization>
</developer>
</developers>
<licenses>

View File

@ -76,6 +76,19 @@
scheme introduced in LOINC 2.64. Thanks to Rob Hausam for the
pull request!
</action>
<action type="add">
In the JPA server, it is now possible for a custom search parameter
to use the
<![CDATA[<code>resolve()</code>]]> function in its path to descend into
contained resources and index fields within them.
</action>
<action type="fix" issue="1010">
Resource loading logic for the JPA server has been optimized to
reduce the number of database round trips required when loading
search results where many of the entries have a "forced ID" (an alphanumeric
client-assigned reosurce ID). Thanks to Frank Tao for the pull
request!
</action>
</release>
<release version="3.4.0" date="2018-05-28">
<action type="add">