Jr 20211021 chained references 3 (#3107)
* Create index entries for outbound references of contained resources * build query for chained reference * fix case where the contained reference is an explicit id rather than a continued chain * fix contained index to use path names not search param names * make qualified search work * cleanup and changelog * recurse while creating indexes on contained resources * double link both contained * longer contained subchains * adding some failing test cases to illustrate the limitations of qualified searches * clean up merge cruft * changelog * create recursive resource links * add test coverage for a more complicated case * changelog * remove unnecessary check for _contained flag * fix broken tests
This commit is contained in:
parent
b267fdb752
commit
20f31e4854
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 3106
|
||||||
|
jira: SMILE-3151
|
||||||
|
title: "Further enhances the features added by issue 3100 to allow chained searches across any combination of discrete and contained references."
|
|
@ -1139,13 +1139,7 @@ public class QueryStack {
|
||||||
break;
|
break;
|
||||||
case REFERENCE:
|
case REFERENCE:
|
||||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||||
if (theSearchContainedMode.equals(SearchContainedModeEnum.TRUE)) {
|
if (isEligibleForContainedResourceSearch(nextAnd)) {
|
||||||
// TODO: The _contained parameter is not intended to control search chain interpretation like this.
|
|
||||||
// See SMILE-2898 for details.
|
|
||||||
// For now, leave the incorrect implementation alone, just in case someone is relying on it,
|
|
||||||
// until the complete fix is available.
|
|
||||||
andPredicates.add(createPredicateReferenceForContainedResource(null, theResourceName, theParamName, new ArrayList<>(), nextParamDef, nextAnd, null, theRequest, theRequestPartitionId));
|
|
||||||
} else if (isEligibleForContainedResourceSearch(nextAnd)) {
|
|
||||||
andPredicates.add(toOrPredicate(
|
andPredicates.add(toOrPredicate(
|
||||||
createPredicateReference(theSourceJoinColumn, theResourceName, theParamName, new ArrayList<>(), nextAnd, null, theRequest, theRequestPartitionId),
|
createPredicateReference(theSourceJoinColumn, theResourceName, theParamName, new ArrayList<>(), nextAnd, null, theRequest, theRequestPartitionId),
|
||||||
createPredicateReferenceForContainedResource(theSourceJoinColumn, theResourceName, theParamName, new ArrayList<>(), nextParamDef, nextAnd, null, theRequest, theRequestPartitionId)
|
createPredicateReferenceForContainedResource(theSourceJoinColumn, theResourceName, theParamName, new ArrayList<>(), nextParamDef, nextAnd, null, theRequest, theRequestPartitionId)
|
||||||
|
|
|
@ -61,6 +61,7 @@ import ca.uhn.fhir.rest.param.SpecialParam;
|
||||||
import ca.uhn.fhir.rest.param.StringParam;
|
import ca.uhn.fhir.rest.param.StringParam;
|
||||||
import ca.uhn.fhir.rest.param.TokenParam;
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
import ca.uhn.fhir.rest.param.TokenParamModifier;
|
import ca.uhn.fhir.rest.param.TokenParamModifier;
|
||||||
|
import ca.uhn.fhir.rest.param.UriParam;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
|
@ -656,6 +657,8 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder {
|
||||||
}
|
}
|
||||||
throw new InternalErrorException("Don't know how to convert param type: " + theParam.getParamType());
|
throw new InternalErrorException("Don't know how to convert param type: " + theParam.getParamType());
|
||||||
case URI:
|
case URI:
|
||||||
|
qp = new UriParam();
|
||||||
|
break;
|
||||||
case HAS:
|
case HAS:
|
||||||
default:
|
default:
|
||||||
throw new InternalErrorException("Don't know how to convert param type: " + theParam.getParamType());
|
throw new InternalErrorException("Don't know how to convert param type: " + theParam.getParamType());
|
||||||
|
|
|
@ -769,6 +769,48 @@ public class ChainingR4SearchTest extends BaseJpaR4Test {
|
||||||
assertThat(oids, contains(oid1.getIdPart()));
|
assertThat(oids, contains(oid1.getIdPart()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShouldResolveAFourLinkChainWhereTheFirstTwoReferencesAreContained() throws Exception {
|
||||||
|
|
||||||
|
// setup
|
||||||
|
myModelConfig.setIndexOnContainedResourcesRecursively(true);
|
||||||
|
IIdType oid1;
|
||||||
|
|
||||||
|
{
|
||||||
|
Organization org = new Organization();
|
||||||
|
org.setId(IdType.newRandomUuid());
|
||||||
|
org.setName("HealthCo");
|
||||||
|
myOrganizationDao.create(org, mySrd);
|
||||||
|
|
||||||
|
Organization partOfOrg = new Organization();
|
||||||
|
partOfOrg.setId("child");
|
||||||
|
partOfOrg.getPartOf().setReference(org.getId());
|
||||||
|
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.setId("pat");
|
||||||
|
p.addName().setFamily("Smith").addGiven("John");
|
||||||
|
p.getManagingOrganization().setReference("#child");
|
||||||
|
|
||||||
|
Observation obs = new Observation();
|
||||||
|
obs.getContained().add(org);
|
||||||
|
obs.getContained().add(partOfOrg);
|
||||||
|
obs.getContained().add(p);
|
||||||
|
obs.getCode().setText("Observation 1");
|
||||||
|
obs.getSubject().setReference("#pat");
|
||||||
|
|
||||||
|
oid1 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
}
|
||||||
|
|
||||||
|
String url = "/Observation?subject.organization.partof.name=HealthCo";
|
||||||
|
|
||||||
|
// execute
|
||||||
|
List<String> oids = searchAndReturnUnqualifiedVersionlessIdValues(url);
|
||||||
|
|
||||||
|
// validate
|
||||||
|
assertEquals(1L, oids.size());
|
||||||
|
assertThat(oids, contains(oid1.getIdPart()));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testShouldResolveAFourLinkChainWhereAllReferencesAreContained() throws Exception {
|
public void testShouldResolveAFourLinkChainWhereAllReferencesAreContained() throws Exception {
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,6 @@ public class FhirResourceDaoR4ContainedTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
map = new SearchParameterMap();
|
map = new SearchParameterMap();
|
||||||
map.add("subject", new ReferenceParam("name", "Smith"));
|
map.add("subject", new ReferenceParam("name", "Smith"));
|
||||||
map.setSearchContainedMode(SearchContainedModeEnum.TRUE);
|
|
||||||
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id)));
|
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +111,6 @@ public class FhirResourceDaoR4ContainedTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
map = new SearchParameterMap();
|
map = new SearchParameterMap();
|
||||||
map.add("subject", new ReferenceParam("name", "Smith"));
|
map.add("subject", new ReferenceParam("name", "Smith"));
|
||||||
map.setSearchContainedMode(SearchContainedModeEnum.TRUE);
|
|
||||||
map.setLoadSynchronous(true);
|
map.setLoadSynchronous(true);
|
||||||
|
|
||||||
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id)));
|
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id)));
|
||||||
|
@ -183,7 +181,6 @@ public class FhirResourceDaoR4ContainedTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
map = new SearchParameterMap();
|
map = new SearchParameterMap();
|
||||||
map.add("general-practitioner", new ReferenceParam("family", "Smith"));
|
map.add("general-practitioner", new ReferenceParam("family", "Smith"));
|
||||||
map.setSearchContainedMode(SearchContainedModeEnum.TRUE);
|
|
||||||
|
|
||||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), containsInAnyOrder(toValues(id)));
|
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), containsInAnyOrder(toValues(id)));
|
||||||
}
|
}
|
||||||
|
@ -268,30 +265,10 @@ public class FhirResourceDaoR4ContainedTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
map = new SearchParameterMap();
|
map = new SearchParameterMap();
|
||||||
map.add("based-on", new ReferenceParam("authored", "2021-02-23"));
|
map.add("based-on", new ReferenceParam("authored", "2021-02-23"));
|
||||||
map.setSearchContainedMode(SearchContainedModeEnum.TRUE);
|
|
||||||
|
|
||||||
assertThat(toUnqualifiedVersionlessIdValues(myEncounterDao.search(map)), containsInAnyOrder(toValues(id)));
|
assertThat(toUnqualifiedVersionlessIdValues(myEncounterDao.search(map)), containsInAnyOrder(toValues(id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSearchWithNotSupportedSearchType() {
|
|
||||||
|
|
||||||
SearchParameterMap map;
|
|
||||||
|
|
||||||
map = new SearchParameterMap();
|
|
||||||
map.add("subject", new ReferenceParam("near", "toronto"));
|
|
||||||
map.setSearchContainedMode(SearchContainedModeEnum.TRUE);
|
|
||||||
|
|
||||||
try {
|
|
||||||
IBundleProvider outcome = myObservationDao.search(map);
|
|
||||||
outcome.getResources(0, 1).get(0);
|
|
||||||
fail();
|
|
||||||
} catch (InvalidRequestException e) {
|
|
||||||
assertEquals(e.getMessage(), "The search type: SPECIAL is not supported.");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchWithNotSupportedSearchParameter() {
|
public void testSearchWithNotSupportedSearchParameter() {
|
||||||
|
|
||||||
|
@ -299,14 +276,13 @@ public class FhirResourceDaoR4ContainedTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
map = new SearchParameterMap();
|
map = new SearchParameterMap();
|
||||||
map.add("subject", new ReferenceParam("marital-status", "M"));
|
map.add("subject", new ReferenceParam("marital-status", "M"));
|
||||||
map.setSearchContainedMode(SearchContainedModeEnum.TRUE);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
IBundleProvider outcome = myObservationDao.search(map);
|
IBundleProvider outcome = myObservationDao.search(map);
|
||||||
outcome.getResources(0, 1).get(0);
|
outcome.getResources(0, 1).get(0);
|
||||||
fail();
|
fail();
|
||||||
} catch (InvalidRequestException e) {
|
} catch (InvalidRequestException e) {
|
||||||
assertEquals(e.getMessage(), "Unknown search parameter name: subject.marital-status.");
|
assertEquals("Invalid parameter chain: subject.marital-status", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,7 +135,7 @@ public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
||||||
p.getNameFirstRep().setFamily("Smith");
|
p.getNameFirstRep().setFamily("Smith");
|
||||||
|
|
||||||
Observation containedObs = new Observation();
|
Observation containedObs = new Observation();
|
||||||
containedObs.setId("#obs");
|
containedObs.setId("obs");
|
||||||
containedObs.setSubject(new Reference("#pat"));
|
containedObs.setSubject(new Reference("#pat"));
|
||||||
|
|
||||||
Encounter enc = new Encounter();
|
Encounter enc = new Encounter();
|
||||||
|
@ -172,7 +172,7 @@ public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
||||||
org2.setPartOf(new Reference("#org1"));
|
org2.setPartOf(new Reference("#org1"));
|
||||||
|
|
||||||
Observation containedObs = new Observation();
|
Observation containedObs = new Observation();
|
||||||
containedObs.setId("#obs");
|
containedObs.setId("obs");
|
||||||
containedObs.addPerformer(new Reference("#org1"));
|
containedObs.addPerformer(new Reference("#org1"));
|
||||||
|
|
||||||
Encounter enc = new Encounter();
|
Encounter enc = new Encounter();
|
||||||
|
@ -206,6 +206,90 @@ public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateLinkCreatesAppropriatePaths_ContainedResourceRecursive_ToOutboundReference() {
|
||||||
|
myModelConfig.setIndexOnContainedResources(true);
|
||||||
|
myModelConfig.setIndexOnContainedResourcesRecursively(true);
|
||||||
|
|
||||||
|
Organization org = new Organization();
|
||||||
|
org.setId("Organization/ABC");
|
||||||
|
myOrganizationDao.update(org);
|
||||||
|
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.setId("pat");
|
||||||
|
p.setActive(true);
|
||||||
|
p.setManagingOrganization(new Reference("Organization/ABC"));
|
||||||
|
|
||||||
|
Observation containedObs = new Observation();
|
||||||
|
containedObs.setId("#cont");
|
||||||
|
containedObs.setSubject(new Reference("#pat"));
|
||||||
|
|
||||||
|
Encounter enc = new Encounter();
|
||||||
|
enc.getContained().add(p);
|
||||||
|
enc.getContained().add(containedObs);
|
||||||
|
enc.addReasonReference(new Reference("#cont"));
|
||||||
|
myEncounterDao.create(enc, mySrd);
|
||||||
|
|
||||||
|
runInTransaction(() ->{
|
||||||
|
List<ResourceLink> allLinks = myResourceLinkDao.findAll();
|
||||||
|
Optional<ResourceLink> link = allLinks
|
||||||
|
.stream()
|
||||||
|
.filter(t -> "Encounter.reasonReference.subject.managingOrganization".equals(t.getSourcePath()))
|
||||||
|
.findFirst();
|
||||||
|
assertTrue(link.isPresent());
|
||||||
|
assertEquals("Organization", link.get().getTargetResourceType());
|
||||||
|
assertEquals("ABC", link.get().getTargetResourceId());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateLinkCreatesAppropriatePaths_ContainedResourceRecursive_ToOutboundReference_NoLoops() {
|
||||||
|
myModelConfig.setIndexOnContainedResources(true);
|
||||||
|
myModelConfig.setIndexOnContainedResourcesRecursively(true);
|
||||||
|
|
||||||
|
Organization org = new Organization();
|
||||||
|
org.setId("Organization/ABC");
|
||||||
|
myOrganizationDao.update(org);
|
||||||
|
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.setId("pat");
|
||||||
|
p.setActive(true);
|
||||||
|
p.setManagingOrganization(new Reference("Organization/ABC"));
|
||||||
|
|
||||||
|
Observation obs1 = new Observation();
|
||||||
|
obs1.setId("obs1");
|
||||||
|
obs1.setSubject(new Reference("#pat"));
|
||||||
|
obs1.addPartOf(new Reference("#obs2"));
|
||||||
|
|
||||||
|
Observation obs2 = new Observation();
|
||||||
|
obs2.setId("obs2");
|
||||||
|
obs2.addPartOf(new Reference("#obs1"));
|
||||||
|
|
||||||
|
Encounter enc = new Encounter();
|
||||||
|
enc.getContained().add(p);
|
||||||
|
enc.getContained().add(obs1);
|
||||||
|
enc.getContained().add(obs2);
|
||||||
|
enc.addReasonReference(new Reference("#obs2"));
|
||||||
|
myEncounterDao.create(enc, mySrd);
|
||||||
|
|
||||||
|
runInTransaction(() ->{
|
||||||
|
List<ResourceLink> allLinks = myResourceLinkDao.findAll();
|
||||||
|
Optional<ResourceLink> link = allLinks
|
||||||
|
.stream()
|
||||||
|
.filter(t -> "Encounter.reasonReference.partOf.subject.managingOrganization".equals(t.getSourcePath()))
|
||||||
|
.findFirst();
|
||||||
|
assertTrue(link.isPresent());
|
||||||
|
assertEquals("Organization", link.get().getTargetResourceType());
|
||||||
|
assertEquals("ABC", link.get().getTargetResourceId());
|
||||||
|
|
||||||
|
Optional<ResourceLink> noLink = allLinks
|
||||||
|
.stream()
|
||||||
|
.filter(t -> "Encounter.reasonReference.partOf.partOf.partOf.subject.managingOrganization".equals(t.getSourcePath()))
|
||||||
|
.findFirst();
|
||||||
|
assertFalse(noLink.isPresent());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConditionalCreateWithPlusInUrl() {
|
public void testConditionalCreateWithPlusInUrl() {
|
||||||
Observation obs = new Observation();
|
Observation obs = new Observation();
|
||||||
|
|
|
@ -823,20 +823,20 @@ public class ResourceProviderR4SearchContainedTest extends BaseResourceProviderR
|
||||||
}
|
}
|
||||||
|
|
||||||
//-- Search by uri
|
//-- Search by uri
|
||||||
String uri = ourServerBase + "/Observation?based-on.instantiates-uri=http://www.hl7.com&_contained=true";
|
String uri = ourServerBase + "/Observation?based-on.instantiates-uri=http://www.hl7.com";
|
||||||
List<String> oids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
|
List<String> oids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
|
||||||
|
|
||||||
assertEquals(1L, oids.size());
|
assertEquals(1L, oids.size());
|
||||||
assertThat(oids, contains(oid1.getValue()));
|
assertThat(oids, contains(oid1.getValue()));
|
||||||
|
|
||||||
//-- Search by uri more than 1 results
|
//-- Search by uri more than 1 results
|
||||||
uri = ourServerBase + "/Observation?based-on.instantiates-uri=http://www2.hl7.com&_contained=true";
|
uri = ourServerBase + "/Observation?based-on.instantiates-uri=http://www2.hl7.com";
|
||||||
oids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
|
oids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
|
||||||
|
|
||||||
assertEquals(2L, oids.size());
|
assertEquals(2L, oids.size());
|
||||||
|
|
||||||
//-- Search by uri with 'or'
|
//-- Search by uri with 'or'
|
||||||
uri = ourServerBase + "/Observation?based-on.instantiates-uri=http://www.hl7.com,http://www2.hl7.com&_contained=true";
|
uri = ourServerBase + "/Observation?based-on.instantiates-uri=http://www.hl7.com,http://www2.hl7.com";
|
||||||
oids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
|
oids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
|
||||||
|
|
||||||
assertEquals(3L, oids.size());
|
assertEquals(3L, oids.size());
|
||||||
|
|
|
@ -137,7 +137,7 @@ public class SearchParamExtractorService {
|
||||||
extractSearchIndexParametersForContainedResources(theRequestDetails, theParams, theResource, theEntity, containedResources, new HashSet<>());
|
extractSearchIndexParametersForContainedResources(theRequestDetails, theParams, theResource, theEntity, containedResources, new HashSet<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void extractSearchIndexParametersForContainedResources(RequestDetails theRequestDetails, ResourceIndexedSearchParams theParams, IBaseResource theResource, ResourceTable theEntity, Collection<IBaseResource> containedResources, Collection<IBaseResource> theAlreadySeenResources) {
|
private void extractSearchIndexParametersForContainedResources(RequestDetails theRequestDetails, ResourceIndexedSearchParams theParams, IBaseResource theResource, ResourceTable theEntity, Collection<IBaseResource> theContainedResources, Collection<IBaseResource> theAlreadySeenResources) {
|
||||||
// 2. Find referenced search parameters
|
// 2. Find referenced search parameters
|
||||||
ISearchParamExtractor.SearchParamSet<PathAndRef> referencedSearchParamSet = mySearchParamExtractor.extractResourceLinks(theResource, true);
|
ISearchParamExtractor.SearchParamSet<PathAndRef> referencedSearchParamSet = mySearchParamExtractor.extractResourceLinks(theResource, true);
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ public class SearchParamExtractorService {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// 3.2 find the contained resource
|
// 3.2 find the contained resource
|
||||||
IBaseResource containedResource = findContainedResource(containedResources, nextPathAndRef.getRef());
|
IBaseResource containedResource = findContainedResource(theContainedResources, nextPathAndRef.getRef());
|
||||||
if (containedResource == null)
|
if (containedResource == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ public class SearchParamExtractorService {
|
||||||
if (myModelConfig.isIndexOnContainedResourcesRecursively()) {
|
if (myModelConfig.isIndexOnContainedResourcesRecursively()) {
|
||||||
HashSet<IBaseResource> nextAlreadySeenResources = new HashSet<>(theAlreadySeenResources);
|
HashSet<IBaseResource> nextAlreadySeenResources = new HashSet<>(theAlreadySeenResources);
|
||||||
nextAlreadySeenResources.add(containedResource);
|
nextAlreadySeenResources.add(containedResource);
|
||||||
extractSearchIndexParametersForContainedResources(theRequestDetails, currParams, containedResource, theEntity, containedResources, nextAlreadySeenResources);
|
extractSearchIndexParametersForContainedResources(theRequestDetails, currParams, containedResource, theEntity, theContainedResources, nextAlreadySeenResources);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3.5 added reference name as a prefix for the contained resource if any
|
// 3.5 added reference name as a prefix for the contained resource if any
|
||||||
|
@ -430,6 +430,11 @@ public class SearchParamExtractorService {
|
||||||
// 1. get all contained resources
|
// 1. get all contained resources
|
||||||
Collection<IBaseResource> containedResources = terser.getAllEmbeddedResources(theResource, false);
|
Collection<IBaseResource> containedResources = terser.getAllEmbeddedResources(theResource, false);
|
||||||
|
|
||||||
|
extractResourceLinksForContainedResources(theRequestPartitionId, theParams, theEntity, theResource, theTransactionDetails, theFailOnInvalidReference, theRequest, containedResources, new HashSet<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void extractResourceLinksForContainedResources(RequestPartitionId theRequestPartitionId, ResourceIndexedSearchParams theParams, ResourceTable theEntity, IBaseResource theResource, TransactionDetails theTransactionDetails, boolean theFailOnInvalidReference, RequestDetails theRequest, Collection<IBaseResource> theContainedResources, Collection<IBaseResource> theAlreadySeenResources) {
|
||||||
|
|
||||||
// 2. Find referenced search parameters
|
// 2. Find referenced search parameters
|
||||||
ISearchParamExtractor.SearchParamSet<PathAndRef> referencedSearchParamSet = mySearchParamExtractor.extractResourceLinks(theResource, true);
|
ISearchParamExtractor.SearchParamSet<PathAndRef> referencedSearchParamSet = mySearchParamExtractor.extractResourceLinks(theResource, true);
|
||||||
|
|
||||||
|
@ -445,15 +450,27 @@ public class SearchParamExtractorService {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// 3.2 find the contained resource
|
// 3.2 find the contained resource
|
||||||
IBaseResource containedResource = findContainedResource(containedResources, nextPathAndRef.getRef());
|
IBaseResource containedResource = findContainedResource(theContainedResources, nextPathAndRef.getRef());
|
||||||
if (containedResource == null)
|
if (containedResource == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// 3.2.1 if we've already processed this resource upstream, do not process it again, to prevent infinite loops
|
||||||
|
if (theAlreadySeenResources.contains(containedResource)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
currParams = new ResourceIndexedSearchParams();
|
currParams = new ResourceIndexedSearchParams();
|
||||||
|
|
||||||
// 3.3 create indexes for the current contained resource
|
// 3.3 create indexes for the current contained resource
|
||||||
extractResourceLinks(theRequestPartitionId, currParams, theEntity, containedResource, theTransactionDetails, theFailOnInvalidReference, theRequest);
|
extractResourceLinks(theRequestPartitionId, currParams, theEntity, containedResource, theTransactionDetails, theFailOnInvalidReference, theRequest);
|
||||||
|
|
||||||
|
// 3.4 recurse to process any other contained resources referenced by this one
|
||||||
|
if (myModelConfig.isIndexOnContainedResourcesRecursively()) {
|
||||||
|
HashSet<IBaseResource> nextAlreadySeenResources = new HashSet<>(theAlreadySeenResources);
|
||||||
|
nextAlreadySeenResources.add(containedResource);
|
||||||
|
extractResourceLinksForContainedResources(theRequestPartitionId, currParams, theEntity, containedResource, theTransactionDetails, theFailOnInvalidReference, theRequest, theContainedResources, nextAlreadySeenResources);
|
||||||
|
}
|
||||||
|
|
||||||
// 3.4 added reference name as a prefix for the contained resource if any
|
// 3.4 added reference name as a prefix for the contained resource if any
|
||||||
// e.g. for Observation.subject contained reference
|
// e.g. for Observation.subject contained reference
|
||||||
// the SP_NAME = subject.family
|
// the SP_NAME = subject.family
|
||||||
|
|
Loading…
Reference in New Issue