Merge branch 'master' into improve_jpa_indexes
This commit is contained in:
commit
9a880361b6
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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() {
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
5
pom.xml
5
pom.xml
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
Loading…
Reference in New Issue