mirror of
https://github.com/hapifhir/hapi-fhir.git
synced 2025-03-09 14:33:32 +00:00
Add support for _lanugage SP (#5300)
* Add support for _lanugage SP * Add changelog * Formatting fix * Add to JPA * Add validator * Validate language SP * Assign new code * Fixes
This commit is contained in:
parent
d4717a08d6
commit
2da8aafad0
@ -182,6 +182,11 @@ public class Constants {
|
|||||||
public static final String PARAM_HAS = "_has";
|
public static final String PARAM_HAS = "_has";
|
||||||
public static final String PARAM_HISTORY = "_history";
|
public static final String PARAM_HISTORY = "_history";
|
||||||
public static final String PARAM_INCLUDE = "_include";
|
public static final String PARAM_INCLUDE = "_include";
|
||||||
|
/**
|
||||||
|
* @since 7.0.0
|
||||||
|
*/
|
||||||
|
public static final String PARAM_LANGUAGE = "_language";
|
||||||
|
|
||||||
public static final String PARAM_INCLUDE_QUALIFIER_RECURSE = ":recurse";
|
public static final String PARAM_INCLUDE_QUALIFIER_RECURSE = ":recurse";
|
||||||
public static final String PARAM_INCLUDE_RECURSE = "_include" + PARAM_INCLUDE_QUALIFIER_RECURSE;
|
public static final String PARAM_INCLUDE_RECURSE = "_include" + PARAM_INCLUDE_QUALIFIER_RECURSE;
|
||||||
public static final String PARAM_INCLUDE_QUALIFIER_ITERATE = ":iterate";
|
public static final String PARAM_INCLUDE_QUALIFIER_ITERATE = ":iterate";
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5300
|
||||||
|
title: "A bug in DefaultProfileValidationSupport in R5 mode caused it to return duplicates
|
||||||
|
in the lists returned by `fetchAllStructureDefinitions()`, `fetchAllSearchParameters()`, etc.
|
||||||
|
This has been corrected."
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 5300
|
||||||
|
title: "A new configuration option has been added to `StorageSettings` which enables
|
||||||
|
support in the JPA server for the `_language` SearchParameter."
|
@ -138,6 +138,13 @@ public class StorageSettings {
|
|||||||
* Since 6.4.0
|
* Since 6.4.0
|
||||||
*/
|
*/
|
||||||
private boolean myQualifySubscriptionMatchingChannelName = true;
|
private boolean myQualifySubscriptionMatchingChannelName = true;
|
||||||
|
/**
|
||||||
|
* Should the {@literal _lamguage} SearchParameter be supported
|
||||||
|
* on this server?
|
||||||
|
*
|
||||||
|
* @since 7.0.0
|
||||||
|
*/
|
||||||
|
private boolean myLanguageSearchParameterEnabled = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If set to true, the server will prevent the creation of Subscriptions which cannot be evaluated IN-MEMORY. This can improve
|
* If set to true, the server will prevent the creation of Subscriptions which cannot be evaluated IN-MEMORY. This can improve
|
||||||
@ -1295,6 +1302,23 @@ public class StorageSettings {
|
|||||||
return myQualifySubscriptionMatchingChannelName;
|
return myQualifySubscriptionMatchingChannelName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Should the {@literal _lamguage} SearchParameter be supported on this server? Defaults to {@literal false}.
|
||||||
|
* @since 7.0.0
|
||||||
|
*/
|
||||||
|
public boolean isLanguageSearchParameterEnabled() {
|
||||||
|
return myLanguageSearchParameterEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should the {@literal _lamguage} SearchParameter be supported on this server? Defaults to {@literal false}.
|
||||||
|
*
|
||||||
|
* @since 7.0.0
|
||||||
|
*/
|
||||||
|
public void setLanguageSearchParameterEnabled(boolean theLanguageSearchParameterEnabled) {
|
||||||
|
myLanguageSearchParameterEnabled = theLanguageSearchParameterEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
private static void validateTreatBaseUrlsAsLocal(String theUrl) {
|
private static void validateTreatBaseUrlsAsLocal(String theUrl) {
|
||||||
Validate.notBlank(theUrl, "Base URL must not be null or empty");
|
Validate.notBlank(theUrl, "Base URL must not be null or empty");
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ public class MatchUrlService {
|
|||||||
IQueryParameterAnd<?> param = JpaParamUtil.parseQueryParams(
|
IQueryParameterAnd<?> param = JpaParamUtil.parseQueryParams(
|
||||||
myFhirContext, RestSearchParameterTypeEnum.TOKEN, nextParamName, paramList);
|
myFhirContext, RestSearchParameterTypeEnum.TOKEN, nextParamName, paramList);
|
||||||
paramMap.add(nextParamName, param);
|
paramMap.add(nextParamName, param);
|
||||||
} else if (nextParamName.startsWith("_")) {
|
} else if (nextParamName.startsWith("_") && !Constants.PARAM_LANGUAGE.equals(nextParamName)) {
|
||||||
// ignore these since they aren't search params (e.g. _sort)
|
// ignore these since they aren't search params (e.g. _sort)
|
||||||
} else {
|
} else {
|
||||||
RuntimeSearchParam paramDef =
|
RuntimeSearchParam paramDef =
|
||||||
|
@ -32,6 +32,8 @@ import ca.uhn.fhir.jpa.cache.IResourceChangeListenerRegistry;
|
|||||||
import ca.uhn.fhir.jpa.cache.ResourceChangeResult;
|
import ca.uhn.fhir.jpa.cache.ResourceChangeResult;
|
||||||
import ca.uhn.fhir.jpa.model.entity.StorageSettings;
|
import ca.uhn.fhir.jpa.model.entity.StorageSettings;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
|
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
||||||
@ -193,6 +195,31 @@ public class SearchParamRegistryImpl
|
|||||||
long overriddenCount = overrideBuiltinSearchParamsWithActiveJpaSearchParams(searchParams, theJpaSearchParams);
|
long overriddenCount = overrideBuiltinSearchParamsWithActiveJpaSearchParams(searchParams, theJpaSearchParams);
|
||||||
ourLog.trace("Have overridden {} built-in search parameters", overriddenCount);
|
ourLog.trace("Have overridden {} built-in search parameters", overriddenCount);
|
||||||
removeInactiveSearchParams(searchParams);
|
removeInactiveSearchParams(searchParams);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The _language SearchParameter is a weird exception - It is actually just a normal
|
||||||
|
* token SP, but we explcitly ban SPs from registering themselves with a prefix
|
||||||
|
* of "_" since that's system reserved so we put this one behind a settings toggle
|
||||||
|
*/
|
||||||
|
if (myStorageSettings.isLanguageSearchParameterEnabled()) {
|
||||||
|
IIdType id = myFhirContext.getVersion().newIdType();
|
||||||
|
id.setValue("SearchParameter/Resource-language");
|
||||||
|
RuntimeSearchParam sp = new RuntimeSearchParam(
|
||||||
|
id,
|
||||||
|
"http://hl7.org/fhir/SearchParameter/Resource-language",
|
||||||
|
Constants.PARAM_LANGUAGE,
|
||||||
|
"Language of the resource content",
|
||||||
|
"language",
|
||||||
|
RestSearchParameterTypeEnum.TOKEN,
|
||||||
|
Collections.emptySet(),
|
||||||
|
Collections.emptySet(),
|
||||||
|
RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE,
|
||||||
|
myFhirContext.getResourceTypes());
|
||||||
|
for (String baseResourceType : sp.getBase()) {
|
||||||
|
searchParams.add(baseResourceType, sp.getName(), sp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
myActiveSearchParams = searchParams;
|
myActiveSearchParams = searchParams;
|
||||||
|
|
||||||
myJpaSearchParamCache.populateActiveSearchParams(
|
myJpaSearchParamCache.populateActiveSearchParams(
|
||||||
@ -282,7 +309,13 @@ public class SearchParamRegistryImpl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void forceRefresh() {
|
public void forceRefresh() {
|
||||||
|
RuntimeSearchParamCache activeSearchParams = myActiveSearchParams;
|
||||||
myResourceChangeListenerCache.forceRefresh();
|
myResourceChangeListenerCache.forceRefresh();
|
||||||
|
|
||||||
|
// If the refresh didn't trigger a change, proceed with one anyway
|
||||||
|
if (myActiveSearchParams == activeSearchParams) {
|
||||||
|
rebuildActiveSearchParams();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -40,279 +40,285 @@ import java.util.List;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.contains;
|
||||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
@ContextConfiguration(classes = TestHSearchAddInConfig.NoFT.class)
|
@ContextConfiguration(classes = TestHSearchAddInConfig.NoFT.class)
|
||||||
@SuppressWarnings({"Duplicates"})
|
@SuppressWarnings({"Duplicates"})
|
||||||
public class FhirResourceDaoR5SearchNoFtTest extends BaseJpaR5Test {
|
public class FhirResourceDaoR5SearchNoFtTest extends BaseJpaR5Test {
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR5SearchNoFtTest.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR5SearchNoFtTest.class);
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void after() {
|
public void after() {
|
||||||
myStorageSettings.setIndexMissingFields(new JpaStorageSettings().getIndexMissingFields());
|
JpaStorageSettings defaults = new JpaStorageSettings();
|
||||||
}
|
myStorageSettings.setIndexMissingFields(defaults.getIndexMissingFields());
|
||||||
|
myStorageSettings.setLanguageSearchParameterEnabled(defaults.isLanguageSearchParameterEnabled());
|
||||||
|
mySearchParamRegistry.forceRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHasWithTargetReference() {
|
public void testHasWithTargetReference() {
|
||||||
Organization org = new Organization();
|
Organization org = new Organization();
|
||||||
org.setId("ORG");
|
org.setId("ORG");
|
||||||
org.setName("ORG");
|
org.setName("ORG");
|
||||||
myOrganizationDao.update(org);
|
myOrganizationDao.update(org);
|
||||||
|
|
||||||
Practitioner practitioner = new Practitioner();
|
Practitioner practitioner = new Practitioner();
|
||||||
practitioner.setId("PRACT");
|
practitioner.setId("PRACT");
|
||||||
practitioner.addName().setFamily("PRACT");
|
practitioner.addName().setFamily("PRACT");
|
||||||
myPractitionerDao.update(practitioner);
|
myPractitionerDao.update(practitioner);
|
||||||
|
|
||||||
PractitionerRole role = new PractitionerRole();
|
PractitionerRole role = new PractitionerRole();
|
||||||
role.setId("ROLE");
|
role.setId("ROLE");
|
||||||
role.getPractitioner().setReference("Practitioner/PRACT");
|
role.getPractitioner().setReference("Practitioner/PRACT");
|
||||||
role.getOrganization().setReference("Organization/ORG");
|
role.getOrganization().setReference("Organization/ORG");
|
||||||
myPractitionerRoleDao.update(role);
|
myPractitionerRoleDao.update(role);
|
||||||
|
|
||||||
SearchParameterMap params = new SearchParameterMap();
|
SearchParameterMap params = new SearchParameterMap();
|
||||||
HasAndListParam value = new HasAndListParam();
|
HasAndListParam value = new HasAndListParam();
|
||||||
value.addAnd(new HasOrListParam().addOr(new HasParam("PractitionerRole", "practitioner", "organization", "ORG")));
|
value.addAnd(new HasOrListParam().addOr(new HasParam("PractitionerRole", "practitioner", "organization", "ORG")));
|
||||||
params.add("_has", value);
|
params.add("_has", value);
|
||||||
IBundleProvider outcome = myPractitionerDao.search(params);
|
IBundleProvider outcome = myPractitionerDao.search(params);
|
||||||
assertEquals(1, outcome.getResources(0, 1).size());
|
assertEquals(1, outcome.getResources(0, 1).size());
|
||||||
}
|
}
|
||||||
@Test
|
|
||||||
public void testHasWithTargetReferenceQualified() {
|
|
||||||
Organization org = new Organization();
|
|
||||||
org.setId("ORG");
|
|
||||||
org.setName("ORG");
|
|
||||||
myOrganizationDao.update(org);
|
|
||||||
|
|
||||||
Practitioner practitioner = new Practitioner();
|
@Test
|
||||||
practitioner.setId("PRACT");
|
public void testHasWithTargetReferenceQualified() {
|
||||||
practitioner.addName().setFamily("PRACT");
|
Organization org = new Organization();
|
||||||
myPractitionerDao.update(practitioner);
|
org.setId("ORG");
|
||||||
|
org.setName("ORG");
|
||||||
|
myOrganizationDao.update(org);
|
||||||
|
|
||||||
PractitionerRole role = new PractitionerRole();
|
Practitioner practitioner = new Practitioner();
|
||||||
role.setId("ROLE");
|
practitioner.setId("PRACT");
|
||||||
role.getPractitioner().setReference("Practitioner/PRACT");
|
practitioner.addName().setFamily("PRACT");
|
||||||
role.getOrganization().setReference("Organization/ORG");
|
myPractitionerDao.update(practitioner);
|
||||||
myPractitionerRoleDao.update(role);
|
|
||||||
|
|
||||||
SearchParameterMap params = new SearchParameterMap();
|
PractitionerRole role = new PractitionerRole();
|
||||||
HasAndListParam value = new HasAndListParam();
|
role.setId("ROLE");
|
||||||
value.addAnd(new HasOrListParam().addOr(new HasParam("PractitionerRole", "practitioner", "organization", "Organization/ORG")));
|
role.getPractitioner().setReference("Practitioner/PRACT");
|
||||||
params.add("_has", value);
|
role.getOrganization().setReference("Organization/ORG");
|
||||||
IBundleProvider outcome = myPractitionerDao.search(params);
|
myPractitionerRoleDao.update(role);
|
||||||
assertEquals(1, outcome.getResources(0, 1).size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
SearchParameterMap params = new SearchParameterMap();
|
||||||
public void testHasWithTargetId() {
|
HasAndListParam value = new HasAndListParam();
|
||||||
Organization org = new Organization();
|
value.addAnd(new HasOrListParam().addOr(new HasParam("PractitionerRole", "practitioner", "organization", "Organization/ORG")));
|
||||||
org.setId("ORG");
|
params.add("_has", value);
|
||||||
org.setName("ORG");
|
IBundleProvider outcome = myPractitionerDao.search(params);
|
||||||
myOrganizationDao.update(org);
|
assertEquals(1, outcome.getResources(0, 1).size());
|
||||||
|
}
|
||||||
|
|
||||||
Practitioner practitioner = new Practitioner();
|
@Test
|
||||||
practitioner.setId("PRACT");
|
public void testHasWithTargetId() {
|
||||||
practitioner.addName().setFamily("PRACT");
|
Organization org = new Organization();
|
||||||
myPractitionerDao.update(practitioner);
|
org.setId("ORG");
|
||||||
|
org.setName("ORG");
|
||||||
|
myOrganizationDao.update(org);
|
||||||
|
|
||||||
PractitionerRole role = new PractitionerRole();
|
Practitioner practitioner = new Practitioner();
|
||||||
role.setId("ROLE");
|
practitioner.setId("PRACT");
|
||||||
role.getPractitioner().setReference("Practitioner/PRACT");
|
practitioner.addName().setFamily("PRACT");
|
||||||
role.getOrganization().setReference("Organization/ORG");
|
myPractitionerDao.update(practitioner);
|
||||||
myPractitionerRoleDao.update(role);
|
|
||||||
|
|
||||||
runInTransaction(() -> {
|
PractitionerRole role = new PractitionerRole();
|
||||||
ourLog.info("Links:\n * {}", myResourceLinkDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * ")));
|
role.setId("ROLE");
|
||||||
});
|
role.getPractitioner().setReference("Practitioner/PRACT");
|
||||||
|
role.getOrganization().setReference("Organization/ORG");
|
||||||
|
myPractitionerRoleDao.update(role);
|
||||||
|
|
||||||
SearchParameterMap params = SearchParameterMap.newSynchronous();
|
runInTransaction(() -> {
|
||||||
HasAndListParam value = new HasAndListParam();
|
ourLog.info("Links:\n * {}", myResourceLinkDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * ")));
|
||||||
value.addAnd(new HasOrListParam().addOr(new HasParam("PractitionerRole", "practitioner", "_id", "ROLE")));
|
});
|
||||||
params.add("_has", value);
|
|
||||||
myCaptureQueriesListener.clear();
|
|
||||||
IBundleProvider outcome = myPractitionerDao.search(params);
|
|
||||||
myCaptureQueriesListener.logSelectQueriesForCurrentThread(1);
|
|
||||||
assertEquals(1, outcome.getResources(0, 1).size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
SearchParameterMap params = SearchParameterMap.newSynchronous();
|
||||||
public void testSearchDoesntFailIfResourcesAreDeleted() {
|
HasAndListParam value = new HasAndListParam();
|
||||||
|
value.addAnd(new HasOrListParam().addOr(new HasParam("PractitionerRole", "practitioner", "_id", "ROLE")));
|
||||||
|
params.add("_has", value);
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
IBundleProvider outcome = myPractitionerDao.search(params);
|
||||||
|
myCaptureQueriesListener.logSelectQueriesForCurrentThread(1);
|
||||||
|
assertEquals(1, outcome.getResources(0, 1).size());
|
||||||
|
}
|
||||||
|
|
||||||
Patient p = new Patient();
|
@Test
|
||||||
p.addIdentifier().setValue("1");
|
public void testSearchDoesntFailIfResourcesAreDeleted() {
|
||||||
myPatientDao.create(p);
|
|
||||||
|
|
||||||
p = new Patient();
|
Patient p = new Patient();
|
||||||
p.addIdentifier().setValue("2");
|
p.addIdentifier().setValue("1");
|
||||||
myPatientDao.create(p);
|
myPatientDao.create(p);
|
||||||
|
|
||||||
p = new Patient();
|
p = new Patient();
|
||||||
p.addIdentifier().setValue("3");
|
p.addIdentifier().setValue("2");
|
||||||
Long id = myPatientDao.create(p).getId().getIdPartAsLong();
|
myPatientDao.create(p);
|
||||||
|
|
||||||
IBundleProvider outcome = myPatientDao.search(new SearchParameterMap());
|
p = new Patient();
|
||||||
assertEquals(3, outcome.size().intValue());
|
p.addIdentifier().setValue("3");
|
||||||
|
Long id = myPatientDao.create(p).getId().getIdPartAsLong();
|
||||||
|
|
||||||
runInTransaction(() -> {
|
IBundleProvider outcome = myPatientDao.search(new SearchParameterMap());
|
||||||
ResourceTable table = myResourceTableDao.findById(id).orElseThrow(() -> new IllegalArgumentException());
|
assertEquals(3, outcome.size().intValue());
|
||||||
table.setDeleted(new Date());
|
|
||||||
myResourceTableDao.save(table);
|
|
||||||
});
|
|
||||||
|
|
||||||
assertEquals(2, outcome.getResources(0, 3).size());
|
runInTransaction(() -> {
|
||||||
|
ResourceTable table = myResourceTableDao.findById(id).orElseThrow(() -> new IllegalArgumentException());
|
||||||
|
table.setDeleted(new Date());
|
||||||
|
myResourceTableDao.save(table);
|
||||||
|
});
|
||||||
|
|
||||||
runInTransaction(() -> {
|
assertEquals(2, outcome.getResources(0, 3).size());
|
||||||
myResourceHistoryTableDao.deleteAll();
|
|
||||||
});
|
|
||||||
|
|
||||||
assertEquals(0, outcome.getResources(0, 3).size());
|
runInTransaction(() -> {
|
||||||
}
|
myResourceHistoryTableDao.deleteAll();
|
||||||
|
});
|
||||||
|
|
||||||
@Test
|
assertEquals(0, outcome.getResources(0, 3).size());
|
||||||
public void testToken_CodeableReference_Reference() {
|
}
|
||||||
// Setup
|
|
||||||
|
|
||||||
ObservationDefinition obs = new ObservationDefinition();
|
@Test
|
||||||
obs.setApprovalDate(new Date());
|
public void testToken_CodeableReference_Reference() {
|
||||||
String obsId = myObservationDefinitionDao.create(obs, mySrd).getId().toUnqualifiedVersionless().getValue();
|
// Setup
|
||||||
|
|
||||||
ClinicalUseDefinition def = new ClinicalUseDefinition();
|
ObservationDefinition obs = new ObservationDefinition();
|
||||||
def.getContraindication().getDiseaseSymptomProcedure().setReference(new Reference(obsId));
|
obs.setApprovalDate(new Date());
|
||||||
String id = myClinicalUseDefinitionDao.create(def, mySrd).getId().toUnqualifiedVersionless().getValue();
|
String obsId = myObservationDefinitionDao.create(obs, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
ClinicalUseDefinition def2 = new ClinicalUseDefinition();
|
ClinicalUseDefinition def = new ClinicalUseDefinition();
|
||||||
def2.getContraindication().getDiseaseSymptomProcedure().setConcept(new CodeableConcept().addCoding(new Coding("http://foo", "bar", "baz")));
|
def.getContraindication().getDiseaseSymptomProcedure().setReference(new Reference(obsId));
|
||||||
myClinicalUseDefinitionDao.create(def2, mySrd).getId().toUnqualifiedVersionless().getValue();
|
String id = myClinicalUseDefinitionDao.create(def, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
// Test
|
ClinicalUseDefinition def2 = new ClinicalUseDefinition();
|
||||||
|
def2.getContraindication().getDiseaseSymptomProcedure().setConcept(new CodeableConcept().addCoding(new Coding("http://foo", "bar", "baz")));
|
||||||
|
myClinicalUseDefinitionDao.create(def2, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
SearchParameterMap map = SearchParameterMap.newSynchronous(ClinicalUseDefinition.SP_CONTRAINDICATION_REFERENCE, new ReferenceParam(obsId));
|
// Test
|
||||||
List<String> outcome = toUnqualifiedVersionlessIdValues(myClinicalUseDefinitionDao.search(map, mySrd));
|
|
||||||
assertThat(outcome, Matchers.contains(id));
|
|
||||||
|
|
||||||
}
|
SearchParameterMap map = SearchParameterMap.newSynchronous(ClinicalUseDefinition.SP_CONTRAINDICATION_REFERENCE, new ReferenceParam(obsId));
|
||||||
|
List<String> outcome = toUnqualifiedVersionlessIdValues(myClinicalUseDefinitionDao.search(map, mySrd));
|
||||||
|
assertThat(outcome, Matchers.contains(id));
|
||||||
|
|
||||||
@Test
|
}
|
||||||
public void testToken_CodeableReference_Coding() {
|
|
||||||
// Setup
|
|
||||||
|
|
||||||
ObservationDefinition obs = new ObservationDefinition();
|
@Test
|
||||||
obs.setApprovalDate(new Date());
|
public void testToken_CodeableReference_Coding() {
|
||||||
String obsId = myObservationDefinitionDao.create(obs, mySrd).getId().toUnqualifiedVersionless().getValue();
|
// Setup
|
||||||
|
|
||||||
ClinicalUseDefinition def = new ClinicalUseDefinition();
|
ObservationDefinition obs = new ObservationDefinition();
|
||||||
def.getContraindication().getDiseaseSymptomProcedure().setReference(new Reference(obsId));
|
obs.setApprovalDate(new Date());
|
||||||
myClinicalUseDefinitionDao.create(def, mySrd).getId().toUnqualifiedVersionless().getValue();
|
String obsId = myObservationDefinitionDao.create(obs, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
ClinicalUseDefinition def2 = new ClinicalUseDefinition();
|
ClinicalUseDefinition def = new ClinicalUseDefinition();
|
||||||
def2.getContraindication().getDiseaseSymptomProcedure().setConcept(new CodeableConcept().addCoding(new Coding("http://foo", "bar", "baz")));
|
def.getContraindication().getDiseaseSymptomProcedure().setReference(new Reference(obsId));
|
||||||
String id =myClinicalUseDefinitionDao.create(def2, mySrd).getId().toUnqualifiedVersionless().getValue();
|
myClinicalUseDefinitionDao.create(def, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
// Test
|
ClinicalUseDefinition def2 = new ClinicalUseDefinition();
|
||||||
|
def2.getContraindication().getDiseaseSymptomProcedure().setConcept(new CodeableConcept().addCoding(new Coding("http://foo", "bar", "baz")));
|
||||||
|
String id = myClinicalUseDefinitionDao.create(def2, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
SearchParameterMap map = SearchParameterMap.newSynchronous(ClinicalUseDefinition.SP_CONTRAINDICATION, new TokenParam("http://foo", "bar"));
|
// Test
|
||||||
List<String> outcome = toUnqualifiedVersionlessIdValues(myClinicalUseDefinitionDao.search(map, mySrd));
|
|
||||||
assertThat(outcome, Matchers.contains(id));
|
|
||||||
|
|
||||||
}
|
SearchParameterMap map = SearchParameterMap.newSynchronous(ClinicalUseDefinition.SP_CONTRAINDICATION, new TokenParam("http://foo", "bar"));
|
||||||
|
List<String> outcome = toUnqualifiedVersionlessIdValues(myClinicalUseDefinitionDao.search(map, mySrd));
|
||||||
|
assertThat(outcome, Matchers.contains(id));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIndexAddressDistrict() {
|
public void testIndexAddressDistrict() {
|
||||||
// Setup
|
// Setup
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.addAddress()
|
p.addAddress()
|
||||||
.setDistrict("DISTRICT123");
|
.setDistrict("DISTRICT123");
|
||||||
String id = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless().getValue();
|
String id = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
logAllStringIndexes();
|
logAllStringIndexes();
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
SearchParameterMap params = SearchParameterMap
|
SearchParameterMap params = SearchParameterMap
|
||||||
.newSynchronous(Patient.SP_ADDRESS, new StringParam("DISTRICT123"));
|
.newSynchronous(Patient.SP_ADDRESS, new StringParam("DISTRICT123"));
|
||||||
IBundleProvider outcome = myPatientDao.search(params, mySrd);
|
IBundleProvider outcome = myPatientDao.search(params, mySrd);
|
||||||
|
|
||||||
// Verify
|
// Verify
|
||||||
assertThat(toUnqualifiedVersionlessIdValues(outcome), Matchers.contains(id));
|
assertThat(toUnqualifiedVersionlessIdValues(outcome), Matchers.contains(id));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Index for
|
* Index for
|
||||||
* [base]/Bundle?composition.patient.identifier=foo
|
* [base]/Bundle?composition.patient.identifier=foo
|
||||||
*/
|
*/
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@CsvSource({"urn:uuid:5c34dc2c-9b5d-4ec1-b30b-3e2d4371508b", "Patient/ABC"})
|
@CsvSource({"urn:uuid:5c34dc2c-9b5d-4ec1-b30b-3e2d4371508b", "Patient/ABC"})
|
||||||
public void testCreateAndSearchForFullyChainedSearchParameter(String thePatientId) {
|
public void testCreateAndSearchForFullyChainedSearchParameter(String thePatientId) {
|
||||||
// Setup 1
|
// Setup 1
|
||||||
|
|
||||||
myStorageSettings.setIndexMissingFields(JpaStorageSettings.IndexEnabledEnum.DISABLED);
|
myStorageSettings.setIndexMissingFields(JpaStorageSettings.IndexEnabledEnum.DISABLED);
|
||||||
|
|
||||||
SearchParameter sp = new SearchParameter();
|
SearchParameter sp = new SearchParameter();
|
||||||
sp.setId("SearchParameter/Bundle-composition-patient-identifier");
|
sp.setId("SearchParameter/Bundle-composition-patient-identifier");
|
||||||
sp.setCode("composition.patient.identifier");
|
sp.setCode("composition.patient.identifier");
|
||||||
sp.setName("composition.patient.identifier");
|
sp.setName("composition.patient.identifier");
|
||||||
sp.setUrl("http://example.org/SearchParameter/Bundle-composition-patient-identifier");
|
sp.setUrl("http://example.org/SearchParameter/Bundle-composition-patient-identifier");
|
||||||
sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||||
sp.setType(Enumerations.SearchParamType.TOKEN);
|
sp.setType(Enumerations.SearchParamType.TOKEN);
|
||||||
sp.setExpression("Bundle.entry[0].resource.as(Composition).subject.resolve().as(Patient).identifier");
|
sp.setExpression("Bundle.entry[0].resource.as(Composition).subject.resolve().as(Patient).identifier");
|
||||||
sp.addBase(Enumerations.VersionIndependentResourceTypesAll.BUNDLE);
|
sp.addBase(Enumerations.VersionIndependentResourceTypesAll.BUNDLE);
|
||||||
ourLog.info("SP: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(sp));
|
ourLog.info("SP: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(sp));
|
||||||
mySearchParameterDao.update(sp, mySrd);
|
mySearchParameterDao.update(sp, mySrd);
|
||||||
|
|
||||||
mySearchParamRegistry.forceRefresh();
|
mySearchParamRegistry.forceRefresh();
|
||||||
|
|
||||||
// Test 1
|
// Test 1
|
||||||
|
|
||||||
Composition composition = new Composition();
|
Composition composition = new Composition();
|
||||||
composition.addSubject().setReference(thePatientId);
|
composition.addSubject().setReference(thePatientId);
|
||||||
|
|
||||||
Patient patient = new Patient();
|
Patient patient = new Patient();
|
||||||
patient.setId(new IdType(thePatientId));
|
patient.setId(new IdType(thePatientId));
|
||||||
patient.addIdentifier().setSystem("http://foo").setValue("bar");
|
patient.addIdentifier().setSystem("http://foo").setValue("bar");
|
||||||
|
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.setType(Bundle.BundleType.DOCUMENT);
|
bundle.setType(Bundle.BundleType.DOCUMENT);
|
||||||
bundle.addEntry().setResource(composition);
|
bundle.addEntry().setResource(composition);
|
||||||
bundle.addEntry().setResource(patient);
|
bundle.addEntry().setResource(patient);
|
||||||
|
|
||||||
myBundleDao.create(bundle, mySrd);
|
myBundleDao.create(bundle, mySrd);
|
||||||
|
|
||||||
Bundle bundle2 = new Bundle();
|
Bundle bundle2 = new Bundle();
|
||||||
bundle2.setType(Bundle.BundleType.DOCUMENT);
|
bundle2.setType(Bundle.BundleType.DOCUMENT);
|
||||||
myBundleDao.create(bundle2, mySrd);
|
myBundleDao.create(bundle2, mySrd);
|
||||||
|
|
||||||
// Verify 1
|
// Verify 1
|
||||||
runInTransaction(() -> {
|
runInTransaction(() -> {
|
||||||
logAllTokenIndexes();
|
logAllTokenIndexes();
|
||||||
|
|
||||||
List<String> params = myResourceIndexedSearchParamTokenDao
|
List<String> params = myResourceIndexedSearchParamTokenDao
|
||||||
.findAll()
|
.findAll()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(t -> t.getParamName().contains("."))
|
.filter(t -> t.getParamName().contains("."))
|
||||||
.map(t -> t.getParamName() + " " + t.getSystem() + "|" + t.getValue())
|
.map(t -> t.getParamName() + " " + t.getSystem() + "|" + t.getValue())
|
||||||
.toList();
|
.toList();
|
||||||
assertThat(params.toString(), params, containsInAnyOrder(
|
assertThat(params.toString(), params, containsInAnyOrder(
|
||||||
"composition.patient.identifier http://foo|bar"
|
"composition.patient.identifier http://foo|bar"
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Test 2
|
// Test 2
|
||||||
IBundleProvider outcome;
|
IBundleProvider outcome;
|
||||||
|
|
||||||
SearchParameterMap map = SearchParameterMap
|
SearchParameterMap map = SearchParameterMap
|
||||||
.newSynchronous("composition.patient.identifier", new TokenParam("http://foo", "bar"));
|
.newSynchronous("composition.patient.identifier", new TokenParam("http://foo", "bar"));
|
||||||
outcome = myBundleDao.search(map, mySrd);
|
outcome = myBundleDao.search(map, mySrd);
|
||||||
assertEquals(1, outcome.size());
|
assertEquals(1, outcome.size());
|
||||||
|
|
||||||
map = SearchParameterMap
|
map = SearchParameterMap
|
||||||
.newSynchronous("composition", new ReferenceParam("patient.identifier", "http://foo|bar"));
|
.newSynchronous("composition", new ReferenceParam("patient.identifier", "http://foo|bar"));
|
||||||
outcome = myBundleDao.search(map, mySrd);
|
outcome = myBundleDao.search(map, mySrd);
|
||||||
assertEquals(1, outcome.size());
|
assertEquals(1, outcome.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHasWithNonExistentReferenceField() {
|
public void testHasWithNonExistentReferenceField() {
|
||||||
@ -334,5 +340,33 @@ public class FhirResourceDaoR5SearchNoFtTest extends BaseJpaR5Test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLanguageSearchParameter_DefaultDisabled() {
|
||||||
|
createObservation(withId("A"), withLanguage("en"));
|
||||||
|
createObservation(withId("B"), withLanguage("fr"));
|
||||||
|
|
||||||
|
logAllTokenIndexes();
|
||||||
|
runInTransaction(() -> assertEquals(0, myResourceIndexedSearchParamTokenDao.count()));
|
||||||
|
|
||||||
|
SearchParameterMap params = SearchParameterMap.newSynchronous();
|
||||||
|
params.add(Constants.PARAM_LANGUAGE, new TokenParam("en"));
|
||||||
|
assertThrows(InvalidRequestException.class, () -> myObservationDao.search(params, mySrd));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLanguageSearchParameter_Enabled() {
|
||||||
|
myStorageSettings.setLanguageSearchParameterEnabled(true);
|
||||||
|
mySearchParamRegistry.forceRefresh();
|
||||||
|
|
||||||
|
createObservation(withId("A"), withLanguage("en"));
|
||||||
|
createObservation(withId("B"), withLanguage("fr"));
|
||||||
|
|
||||||
|
logAllTokenIndexes();
|
||||||
|
runInTransaction(() -> assertEquals(2, myResourceIndexedSearchParamTokenDao.count()));
|
||||||
|
|
||||||
|
SearchParameterMap params = SearchParameterMap.newSynchronous();
|
||||||
|
params.add(Constants.PARAM_LANGUAGE, new TokenParam("en"));
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params, mySrd)), contains("Observation/A"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -46,189 +46,186 @@ import static org.mockito.Mockito.lenient;
|
|||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
public class SearchParameterDaoValidatorTest {
|
public class SearchParameterDaoValidatorTest {
|
||||||
|
|
||||||
@Spy
|
private static final String SP_COMPONENT_DEFINITION_OF_TYPE_TOKEN = "SearchParameter/observation-code";
|
||||||
private FhirContext myFhirContext = FhirContext.forR5Cached();
|
private static final String SP_COMPONENT_DEFINITION_OF_TYPE_REFERENCE = "SearchParameter/observation-patient";
|
||||||
@Mock
|
private static final String SP_COMPONENT_DEFINITION_OF_TYPE_STRING = "SearchParameter/observation-markdown";
|
||||||
private ISearchParamRegistry mySearchParamRegistry;
|
private static final String SP_COMPONENT_DEFINITION_OF_TYPE_DATE = "SearchParameter/observation-date";
|
||||||
@Spy
|
private static final String SP_COMPONENT_DEFINITION_OF_TYPE_QUANTITY = "SearchParameter/observation-code";
|
||||||
private JpaStorageSettings myStorageSettings = new JpaStorageSettings();
|
private static final String SP_COMPONENT_DEFINITION_OF_TYPE_URI = "SearchParameter/component-value-canonical";
|
||||||
@InjectMocks
|
private static final String SP_COMPONENT_DEFINITION_OF_TYPE_NUMBER = "SearchParameter/component-value-number";
|
||||||
private SearchParameterDaoValidator mySvc;
|
@Spy
|
||||||
|
private FhirContext myFhirContext = FhirContext.forR5Cached();
|
||||||
|
private final VersionCanonicalizer myVersionCanonicalizer = new VersionCanonicalizer(myFhirContext);
|
||||||
|
private final SearchParameterCanonicalizer mySearchParameterCanonicalizer = new SearchParameterCanonicalizer(myFhirContext);
|
||||||
|
@Mock
|
||||||
|
private ISearchParamRegistry mySearchParamRegistry;
|
||||||
|
@Spy
|
||||||
|
private JpaStorageSettings myStorageSettings = new JpaStorageSettings();
|
||||||
|
@InjectMocks
|
||||||
|
private SearchParameterDaoValidator mySvc;
|
||||||
|
|
||||||
private final VersionCanonicalizer myVersionCanonicalizer = new VersionCanonicalizer(myFhirContext);
|
@BeforeEach
|
||||||
|
public void before() {
|
||||||
|
createAndMockSearchParameter(TOKEN, SP_COMPONENT_DEFINITION_OF_TYPE_TOKEN, "observation-code", "Observation.code");
|
||||||
|
createAndMockSearchParameter(REFERENCE, SP_COMPONENT_DEFINITION_OF_TYPE_REFERENCE, "observation-patient", "Observation.subject.where(resolve() is Patient");
|
||||||
|
createAndMockSearchParameter(STRING, SP_COMPONENT_DEFINITION_OF_TYPE_DATE, "observation-category", "Observation.value.ofType(markdown)");
|
||||||
|
createAndMockSearchParameter(DATE, SP_COMPONENT_DEFINITION_OF_TYPE_STRING, "observation-date", "Observation.value.ofType(dateTime)");
|
||||||
|
createAndMockSearchParameter(QUANTITY, SP_COMPONENT_DEFINITION_OF_TYPE_QUANTITY, "observation-quantity", "Observation.value.ofType(Quantity)");
|
||||||
|
createAndMockSearchParameter(URI, SP_COMPONENT_DEFINITION_OF_TYPE_URI, "observation-component-value-canonical", "Observation.component.value.ofType(canonical)");
|
||||||
|
createAndMockSearchParameter(NUMBER, SP_COMPONENT_DEFINITION_OF_TYPE_NUMBER, "observation-component-value-number", "Observation.component.valueInteger");
|
||||||
|
}
|
||||||
|
|
||||||
private final SearchParameterCanonicalizer mySearchParameterCanonicalizer = new SearchParameterCanonicalizer(myFhirContext);
|
private void createAndMockSearchParameter(Enumerations.SearchParamType theType, String theDefinition, String theCodeValue, String theExpression) {
|
||||||
|
SearchParameter observationCodeSp = createSearchParameter(theType, theDefinition, theCodeValue, theExpression);
|
||||||
|
RuntimeSearchParam observationCodeRuntimeSearchParam = mySearchParameterCanonicalizer.canonicalizeSearchParameter(observationCodeSp);
|
||||||
|
lenient().when(mySearchParamRegistry.getActiveSearchParamByUrl(eq(theDefinition))).thenReturn(observationCodeRuntimeSearchParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateSubscription() {
|
||||||
|
SearchParameter sp = new SearchParameter();
|
||||||
|
sp.setId("SearchParameter/patient-eyecolour");
|
||||||
|
sp.setUrl("http://example.org/SearchParameter/patient-eyecolour");
|
||||||
|
sp.addBase(PATIENT);
|
||||||
|
sp.setCode("eyecolour");
|
||||||
|
sp.setType(TOKEN);
|
||||||
|
sp.setStatus(ACTIVE);
|
||||||
|
sp.setExpression("Patient.extension('http://foo')");
|
||||||
|
sp.addTarget(PATIENT);
|
||||||
|
|
||||||
private static final String SP_COMPONENT_DEFINITION_OF_TYPE_TOKEN = "SearchParameter/observation-code";
|
SearchParameter canonicalSp = myVersionCanonicalizer.searchParameterToCanonical(sp);
|
||||||
private static final String SP_COMPONENT_DEFINITION_OF_TYPE_REFERENCE = "SearchParameter/observation-patient";
|
mySvc.validate(canonicalSp);
|
||||||
private static final String SP_COMPONENT_DEFINITION_OF_TYPE_STRING = "SearchParameter/observation-markdown";
|
}
|
||||||
private static final String SP_COMPONENT_DEFINITION_OF_TYPE_DATE = "SearchParameter/observation-date";
|
|
||||||
private static final String SP_COMPONENT_DEFINITION_OF_TYPE_QUANTITY = "SearchParameter/observation-code";
|
|
||||||
private static final String SP_COMPONENT_DEFINITION_OF_TYPE_URI = "SearchParameter/component-value-canonical";
|
|
||||||
private static final String SP_COMPONENT_DEFINITION_OF_TYPE_NUMBER = "SearchParameter/component-value-number";
|
|
||||||
|
|
||||||
@BeforeEach
|
@Test
|
||||||
public void before() {
|
public void testValidateSubscriptionWithCustomType() {
|
||||||
createAndMockSearchParameter(TOKEN, SP_COMPONENT_DEFINITION_OF_TYPE_TOKEN, "observation-code", "Observation.code");
|
SearchParameter sp = new SearchParameter();
|
||||||
createAndMockSearchParameter(REFERENCE, SP_COMPONENT_DEFINITION_OF_TYPE_REFERENCE, "observation-patient", "Observation.subject.where(resolve() is Patient");
|
sp.setId("SearchParameter/meal-chef");
|
||||||
createAndMockSearchParameter(STRING, SP_COMPONENT_DEFINITION_OF_TYPE_DATE, "observation-category", "Observation.value.ofType(markdown)");
|
sp.setUrl("http://example.org/SearchParameter/meal-chef");
|
||||||
createAndMockSearchParameter(DATE, SP_COMPONENT_DEFINITION_OF_TYPE_STRING, "observation-date", "Observation.value.ofType(dateTime)");
|
sp.addExtension(new Extension(HapiExtensions.EXTENSION_SEARCHPARAM_CUSTOM_BASE_RESOURCE).setValue(new StringType("Meal")));
|
||||||
createAndMockSearchParameter(QUANTITY, SP_COMPONENT_DEFINITION_OF_TYPE_QUANTITY, "observation-quantity", "Observation.value.ofType(Quantity)");
|
sp.addExtension(new Extension(HapiExtensions.EXTENSION_SEARCHPARAM_CUSTOM_TARGET_RESOURCE).setValue(new StringType("Chef")));
|
||||||
createAndMockSearchParameter(URI, SP_COMPONENT_DEFINITION_OF_TYPE_URI, "observation-component-value-canonical", "Observation.component.value.ofType(canonical)");
|
sp.setCode("chef");
|
||||||
createAndMockSearchParameter(NUMBER, SP_COMPONENT_DEFINITION_OF_TYPE_NUMBER, "observation-component-value-number", "Observation.component.valueInteger");
|
sp.setType(REFERENCE);
|
||||||
}
|
sp.setStatus(ACTIVE);
|
||||||
|
sp.setExpression("Meal.chef");
|
||||||
|
|
||||||
private void createAndMockSearchParameter(Enumerations.SearchParamType theType, String theDefinition, String theCodeValue, String theExpression) {
|
SearchParameter canonicalSp = myVersionCanonicalizer.searchParameterToCanonical(sp);
|
||||||
SearchParameter observationCodeSp = createSearchParameter(theType, theDefinition, theCodeValue, theExpression);
|
mySvc.validate(canonicalSp);
|
||||||
RuntimeSearchParam observationCodeRuntimeSearchParam = mySearchParameterCanonicalizer.canonicalizeSearchParameter(observationCodeSp);
|
}
|
||||||
lenient().when(mySearchParamRegistry.getActiveSearchParamByUrl(eq(theDefinition))).thenReturn(observationCodeRuntimeSearchParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest
|
||||||
public void testValidateSubscription() {
|
@MethodSource("extensionProvider")
|
||||||
SearchParameter sp = new SearchParameter();
|
public void testMethodValidate_nonUniqueComboAndCompositeSearchParamWithComponentOfTypeReference_isNotAllowed(Extension theExtension) {
|
||||||
sp.setId("SearchParameter/patient-eyecolour");
|
SearchParameter sp = createSearchParameter(COMPOSITE, "SearchParameter/patient-code", "patient-code", "Observation");
|
||||||
sp.setUrl("http://example.org/SearchParameter/patient-eyecolour");
|
sp.addExtension(theExtension);
|
||||||
sp.addBase(PATIENT);
|
|
||||||
sp.setCode("eyecolour");
|
|
||||||
sp.setType(TOKEN);
|
|
||||||
sp.setStatus(ACTIVE);
|
|
||||||
sp.setExpression("Patient.extension('http://foo')");
|
|
||||||
sp.addTarget(PATIENT);
|
|
||||||
|
|
||||||
SearchParameter canonicalSp = myVersionCanonicalizer.searchParameterToCanonical(sp);
|
sp.addComponent(new SearchParameterComponentComponent().setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_TOKEN));
|
||||||
mySvc.validate(canonicalSp);
|
sp.addComponent(new SearchParameterComponentComponent().setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_REFERENCE));
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
try {
|
||||||
public void testValidateSubscriptionWithCustomType() {
|
mySvc.validate(sp);
|
||||||
SearchParameter sp = new SearchParameter();
|
fail();
|
||||||
sp.setId("SearchParameter/meal-chef");
|
} catch (UnprocessableEntityException ex) {
|
||||||
sp.setUrl("http://example.org/SearchParameter/meal-chef");
|
assertTrue(ex.getMessage().startsWith("HAPI-2347: "));
|
||||||
sp.addExtension(new Extension(HapiExtensions.EXTENSION_SEARCHPARAM_CUSTOM_BASE_RESOURCE).setValue(new StringType("Meal")));
|
assertTrue(ex.getMessage().contains("Invalid component search parameter type: REFERENCE in component.definition: http://example.org/SearchParameter/observation-patient"));
|
||||||
sp.addExtension(new Extension(HapiExtensions.EXTENSION_SEARCHPARAM_CUSTOM_TARGET_RESOURCE).setValue(new StringType("Chef")));
|
}
|
||||||
sp.setCode("chef");
|
}
|
||||||
sp.setType(REFERENCE);
|
|
||||||
sp.setStatus(ACTIVE);
|
|
||||||
sp.setExpression("Meal.chef");
|
|
||||||
|
|
||||||
SearchParameter canonicalSp = myVersionCanonicalizer.searchParameterToCanonical(sp);
|
@Test
|
||||||
mySvc.validate(canonicalSp);
|
public void testMethodValidate_uniqueComboSearchParamWithComponentOfTypeReference_isValid() {
|
||||||
}
|
SearchParameter sp = createSearchParameter(COMPOSITE, "SearchParameter/patient-code", "patient-code", "Observation");
|
||||||
|
sp.addExtension(new Extension(HapiExtensions.EXT_SP_UNIQUE, new BooleanType(true)));
|
||||||
|
|
||||||
@ParameterizedTest
|
sp.addComponent(new SearchParameterComponentComponent()
|
||||||
@MethodSource("extensionProvider")
|
.setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_TOKEN));
|
||||||
public void testMethodValidate_nonUniqueComboAndCompositeSearchParamWithComponentOfTypeReference_isNotAllowed(Extension theExtension) {
|
sp.addComponent(new SearchParameterComponentComponent()
|
||||||
SearchParameter sp = createSearchParameter(COMPOSITE, "SearchParameter/patient-code", "patient-code", "Observation");
|
.setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_REFERENCE));
|
||||||
sp.addExtension(theExtension);
|
|
||||||
|
|
||||||
sp.addComponent(new SearchParameterComponentComponent().setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_TOKEN));
|
mySvc.validate(sp);
|
||||||
sp.addComponent(new SearchParameterComponentComponent().setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_REFERENCE));
|
}
|
||||||
|
|
||||||
try {
|
@ParameterizedTest
|
||||||
mySvc.validate(sp);
|
@MethodSource("comboSpProvider")
|
||||||
fail();
|
public void testMethodValidate_comboSearchParamsWithNumberUriComponents_isValid(SearchParameter theSearchParameter) {
|
||||||
} catch (UnprocessableEntityException ex) {
|
theSearchParameter.addComponent(new SearchParameterComponentComponent()
|
||||||
assertTrue(ex.getMessage().startsWith("HAPI-2347: "));
|
.setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_URI));
|
||||||
assertTrue(ex.getMessage().contains("Invalid component search parameter type: REFERENCE in component.definition: http://example.org/SearchParameter/observation-patient"));
|
theSearchParameter.addComponent(new SearchParameterComponentComponent()
|
||||||
}
|
.setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_NUMBER));
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
mySvc.validate(theSearchParameter);
|
||||||
public void testMethodValidate_uniqueComboSearchParamWithComponentOfTypeReference_isValid() {
|
}
|
||||||
SearchParameter sp = createSearchParameter(COMPOSITE, "SearchParameter/patient-code", "patient-code", "Observation");
|
|
||||||
sp.addExtension(new Extension(HapiExtensions.EXT_SP_UNIQUE, new BooleanType(true)));
|
|
||||||
|
|
||||||
sp.addComponent(new SearchParameterComponentComponent()
|
@Test
|
||||||
.setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_TOKEN));
|
public void testMethodValidate_compositeSearchParamsWithNumberUriComponents_isNotAllowed() {
|
||||||
sp.addComponent(new SearchParameterComponentComponent()
|
SearchParameter sp = createSearchParameter(COMPOSITE, "SearchParameter/component-value-uri-number", "component-value-uri-number", "Observation");
|
||||||
.setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_REFERENCE));
|
|
||||||
|
|
||||||
mySvc.validate(sp);
|
sp.addComponent(new SearchParameterComponentComponent().setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_URI));
|
||||||
}
|
sp.addComponent(new SearchParameterComponentComponent().setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_NUMBER));
|
||||||
|
|
||||||
@ParameterizedTest
|
try {
|
||||||
@MethodSource("comboSpProvider")
|
mySvc.validate(sp);
|
||||||
public void testMethodValidate_comboSearchParamsWithNumberUriComponents_isValid(SearchParameter theSearchParameter) {
|
fail();
|
||||||
theSearchParameter.addComponent(new SearchParameterComponentComponent()
|
} catch (UnprocessableEntityException ex) {
|
||||||
.setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_URI));
|
assertTrue(ex.getMessage().startsWith("HAPI-2347: "));
|
||||||
theSearchParameter.addComponent(new SearchParameterComponentComponent()
|
assertTrue(ex.getMessage().contains("Invalid component search parameter type: URI in component.definition: http://example.org/SearchParameter/component-value-canonical"));
|
||||||
.setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_NUMBER));
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mySvc.validate(theSearchParameter);
|
@ParameterizedTest
|
||||||
}
|
@MethodSource("compositeSpProvider")
|
||||||
|
// we're testing for:
|
||||||
|
// SP of type composite,
|
||||||
|
// SP of type combo composite non-unique,
|
||||||
|
// SP of type combo composite unique,
|
||||||
|
public void testMethodValidate_allCompositeSpTypesWithComponentOfValidType_isValid(SearchParameter theSearchParameter) {
|
||||||
|
|
||||||
@Test
|
theSearchParameter.addComponent(new SearchParameter.SearchParameterComponentComponent()
|
||||||
public void testMethodValidate_compositeSearchParamsWithNumberUriComponents_isNotAllowed() {
|
.setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_TOKEN).setExpression("Observation"));
|
||||||
SearchParameter sp = createSearchParameter(COMPOSITE, "SearchParameter/component-value-uri-number", "component-value-uri-number", "Observation");
|
theSearchParameter.addComponent(new SearchParameter.SearchParameterComponentComponent()
|
||||||
|
.setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_QUANTITY).setExpression("Observation"));
|
||||||
|
theSearchParameter.addComponent(new SearchParameter.SearchParameterComponentComponent()
|
||||||
|
.setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_STRING).setExpression("Observation"));
|
||||||
|
theSearchParameter.addComponent(new SearchParameter.SearchParameterComponentComponent()
|
||||||
|
.setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_DATE).setExpression("Observation"));
|
||||||
|
|
||||||
sp.addComponent(new SearchParameterComponentComponent().setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_URI));
|
mySvc.validate(theSearchParameter);
|
||||||
sp.addComponent(new SearchParameterComponentComponent().setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_NUMBER));
|
}
|
||||||
|
|
||||||
try {
|
private static SearchParameter createSearchParameter(Enumerations.SearchParamType theType, String theId, String theCodeValue, String theExpression) {
|
||||||
mySvc.validate(sp);
|
|
||||||
fail();
|
|
||||||
} catch (UnprocessableEntityException ex) {
|
|
||||||
assertTrue(ex.getMessage().startsWith("HAPI-2347: "));
|
|
||||||
assertTrue(ex.getMessage().contains("Invalid component search parameter type: URI in component.definition: http://example.org/SearchParameter/component-value-canonical"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest
|
SearchParameter retVal = new SearchParameter();
|
||||||
@MethodSource("compositeSpProvider")
|
retVal.setId(theId);
|
||||||
// we're testing for:
|
retVal.setUrl("http://example.org/" + theId);
|
||||||
// SP of type composite,
|
retVal.addBase(OBSERVATION);
|
||||||
// SP of type combo composite non-unique,
|
retVal.setCode(theCodeValue);
|
||||||
// SP of type combo composite unique,
|
retVal.setType(theType);
|
||||||
public void testMethodValidate_allCompositeSpTypesWithComponentOfValidType_isValid(SearchParameter theSearchParameter) {
|
retVal.setStatus(ACTIVE);
|
||||||
|
retVal.setExpression(theExpression);
|
||||||
|
|
||||||
theSearchParameter.addComponent(new SearchParameter.SearchParameterComponentComponent()
|
return retVal;
|
||||||
.setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_TOKEN).setExpression("Observation"));
|
}
|
||||||
theSearchParameter.addComponent(new SearchParameter.SearchParameterComponentComponent()
|
|
||||||
.setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_QUANTITY).setExpression("Observation"));
|
|
||||||
theSearchParameter.addComponent(new SearchParameter.SearchParameterComponentComponent()
|
|
||||||
.setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_STRING).setExpression("Observation"));
|
|
||||||
theSearchParameter.addComponent(new SearchParameter.SearchParameterComponentComponent()
|
|
||||||
.setDefinition(SP_COMPONENT_DEFINITION_OF_TYPE_DATE).setExpression("Observation"));
|
|
||||||
|
|
||||||
mySvc.validate(theSearchParameter);
|
static Stream<Arguments> extensionProvider() {
|
||||||
}
|
return Stream.of(
|
||||||
|
Arguments.of(
|
||||||
|
new Extension(HapiExtensions.EXT_SP_UNIQUE, new BooleanType(false))), // composite SP of type combo with non-unique index
|
||||||
|
Arguments.of((Object) null) // composite SP
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private static SearchParameter createSearchParameter(Enumerations.SearchParamType theType, String theId, String theCodeValue, String theExpression) {
|
static Stream<Arguments> comboSpProvider() {
|
||||||
|
return Stream.of(
|
||||||
|
Arguments.of(createSearchParameter(Enumerations.SearchParamType.COMPOSITE, "SearchParameter/any-type", "any-type", "Observation")
|
||||||
|
.addExtension(new Extension(HapiExtensions.EXT_SP_UNIQUE, new BooleanType(false)))), // composite SP of type combo with non-unique index
|
||||||
|
|
||||||
SearchParameter retVal = new SearchParameter();
|
Arguments.of(createSearchParameter(Enumerations.SearchParamType.COMPOSITE, "SearchParameter/any-type", "any-type", "Observation")
|
||||||
retVal.setId(theId);
|
.addExtension(new Extension(HapiExtensions.EXT_SP_UNIQUE, new BooleanType(true)))) // composite SP of type combo with unique index
|
||||||
retVal.setUrl("http://example.org/" + theId);
|
);
|
||||||
retVal.addBase(OBSERVATION);
|
}
|
||||||
retVal.setCode(theCodeValue);
|
|
||||||
retVal.setType(theType);
|
|
||||||
retVal.setStatus(ACTIVE);
|
|
||||||
retVal.setExpression(theExpression);
|
|
||||||
|
|
||||||
return retVal;
|
static Stream<Arguments> compositeSpProvider() {
|
||||||
}
|
return Stream.concat(comboSpProvider(), Stream.of(
|
||||||
|
Arguments.of(createSearchParameter(Enumerations.SearchParamType.COMPOSITE, "SearchParameter/any-type", "any-type", "Observation")) // composite SP
|
||||||
static Stream<Arguments> extensionProvider() {
|
));
|
||||||
return Stream.of(
|
}
|
||||||
Arguments.of(
|
|
||||||
new Extension(HapiExtensions.EXT_SP_UNIQUE, new BooleanType(false))), // composite SP of type combo with non-unique index
|
|
||||||
Arguments.of((Object) null) // composite SP
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Stream<Arguments> comboSpProvider() {
|
|
||||||
return Stream.of(
|
|
||||||
Arguments.of(createSearchParameter(Enumerations.SearchParamType.COMPOSITE, "SearchParameter/any-type", "any-type", "Observation")
|
|
||||||
.addExtension(new Extension(HapiExtensions.EXT_SP_UNIQUE, new BooleanType(false)))), // composite SP of type combo with non-unique index
|
|
||||||
|
|
||||||
Arguments.of(createSearchParameter(Enumerations.SearchParamType.COMPOSITE, "SearchParameter/any-type", "any-type", "Observation")
|
|
||||||
.addExtension(new Extension(HapiExtensions.EXT_SP_UNIQUE, new BooleanType(true)))) // composite SP of type combo with unique index
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Stream<Arguments> compositeSpProvider() {
|
|
||||||
return Stream.concat(comboSpProvider(), Stream.of(
|
|
||||||
Arguments.of(createSearchParameter(Enumerations.SearchParamType.COMPOSITE, "SearchParameter/any-type", "any-type", "Observation")) // composite SP
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -6,5 +6,6 @@ public class CommonJpaStorageSettingsConfigurer {
|
|||||||
public CommonJpaStorageSettingsConfigurer(JpaStorageSettings theStorageSettings) {
|
public CommonJpaStorageSettingsConfigurer(JpaStorageSettings theStorageSettings) {
|
||||||
theStorageSettings.setIndexOnUpliftedRefchains(true);
|
theStorageSettings.setIndexOnUpliftedRefchains(true);
|
||||||
theStorageSettings.setMarkResourcesForReindexingUponSearchParameterChange(false);
|
theStorageSettings.setMarkResourcesForReindexingUponSearchParameterChange(false);
|
||||||
|
theStorageSettings.setLanguageSearchParameterEnabled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,10 +98,12 @@ public class SearchParameterDaoValidator {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Search parameters must have a base
|
||||||
if (isCompositeWithoutBase(searchParameter)) {
|
if (isCompositeWithoutBase(searchParameter)) {
|
||||||
throw new UnprocessableEntityException(Msg.code(1113) + "SearchParameter.base is missing");
|
throw new UnprocessableEntityException(Msg.code(1113) + "SearchParameter.base is missing");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do we have a valid expression
|
||||||
if (isCompositeWithoutExpression(searchParameter)) {
|
if (isCompositeWithoutExpression(searchParameter)) {
|
||||||
|
|
||||||
// this is ok
|
// this is ok
|
||||||
|
@ -80,6 +80,13 @@ public interface ITestDataBuilder {
|
|||||||
return t -> __setPrimitiveChild(getFhirContext(), t, "active", "boolean", "false");
|
return t -> __setPrimitiveChild(getFhirContext(), t, "active", "boolean", "false");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Resource.language
|
||||||
|
*/
|
||||||
|
default ICreationArgument withLanguage(String theLanguage) {
|
||||||
|
return t -> __setPrimitiveChild(getFhirContext(), t, "language", "string", theLanguage);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set Patient.gender
|
* Set Patient.gender
|
||||||
*/
|
*/
|
||||||
|
@ -16,12 +16,14 @@ import org.hl7.fhir.r4.model.ValueSet;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@ -34,10 +36,14 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||||||
public class PrePopulatedValidationSupport extends BaseStaticResourceValidationSupport
|
public class PrePopulatedValidationSupport extends BaseStaticResourceValidationSupport
|
||||||
implements IValidationSupport, ILockable {
|
implements IValidationSupport, ILockable {
|
||||||
|
|
||||||
private final Map<String, IBaseResource> myCodeSystems;
|
private final Map<String, IBaseResource> myUrlToCodeSystems;
|
||||||
private final Map<String, IBaseResource> myStructureDefinitions;
|
private final Map<String, IBaseResource> myUrlToStructureDefinitions;
|
||||||
private final Map<String, IBaseResource> mySearchParameters;
|
private final Map<String, IBaseResource> myUrlToSearchParameters;
|
||||||
private final Map<String, IBaseResource> myValueSets;
|
private final Map<String, IBaseResource> myUrlToValueSets;
|
||||||
|
private final List<IBaseResource> myCodeSystems;
|
||||||
|
private final List<IBaseResource> myStructureDefinitions;
|
||||||
|
private final List<IBaseResource> mySearchParameters;
|
||||||
|
private final List<IBaseResource> myValueSets;
|
||||||
private final Map<String, byte[]> myBinaries;
|
private final Map<String, byte[]> myBinaries;
|
||||||
private boolean myLocked;
|
private boolean myLocked;
|
||||||
|
|
||||||
@ -51,51 +57,67 @@ public class PrePopulatedValidationSupport extends BaseStaticResourceValidationS
|
|||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param theStructureDefinitions The StructureDefinitions to be returned by this module. Keys are the logical URL for the resource, and
|
* @param theUrlToStructureDefinitions The StructureDefinitions to be returned by this module. Keys are the logical URL for the resource, and
|
||||||
* values are the resource itself.
|
* values are the resource itself.
|
||||||
* @param theValueSets The ValueSets to be returned by this module. Keys are the logical URL for the resource, and values are
|
* @param theUrlToValueSets The ValueSets to be returned by this module. Keys are the logical URL for the resource, and values are
|
||||||
* the resource itself.
|
* the resource itself.
|
||||||
* @param theCodeSystems The CodeSystems to be returned by this module. Keys are the logical URL for the resource, and values are
|
* @param theUrlToCodeSystems The CodeSystems to be returned by this module. Keys are the logical URL for the resource, and values are
|
||||||
* the resource itself.
|
* the resource itself.
|
||||||
**/
|
**/
|
||||||
public PrePopulatedValidationSupport(
|
public PrePopulatedValidationSupport(
|
||||||
FhirContext theFhirContext,
|
FhirContext theFhirContext,
|
||||||
Map<String, IBaseResource> theStructureDefinitions,
|
Map<String, IBaseResource> theUrlToStructureDefinitions,
|
||||||
Map<String, IBaseResource> theValueSets,
|
Map<String, IBaseResource> theUrlToValueSets,
|
||||||
Map<String, IBaseResource> theCodeSystems) {
|
Map<String, IBaseResource> theUrlToCodeSystems) {
|
||||||
this(theFhirContext, theStructureDefinitions, theValueSets, theCodeSystems, new HashMap<>(), new HashMap<>());
|
this(
|
||||||
|
theFhirContext,
|
||||||
|
theUrlToStructureDefinitions,
|
||||||
|
theUrlToValueSets,
|
||||||
|
theUrlToCodeSystems,
|
||||||
|
new HashMap<>(),
|
||||||
|
new HashMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param theStructureDefinitions The StructureDefinitions to be returned by this module. Keys are the logical URL for the resource, and
|
* @param theUrlToStructureDefinitions The StructureDefinitions to be returned by this module. Keys are the logical URL for the resource, and
|
||||||
* values are the resource itself.
|
* values are the resource itself.
|
||||||
* @param theValueSets The ValueSets to be returned by this module. Keys are the logical URL for the resource, and values are
|
* @param theUrlToValueSets The ValueSets to be returned by this module. Keys are the logical URL for the resource, and values are
|
||||||
* the resource itself.
|
* the resource itself.
|
||||||
* @param theCodeSystems The CodeSystems to be returned by this module. Keys are the logical URL for the resource, and values are
|
* @param theUrlToCodeSystems The CodeSystems to be returned by this module. Keys are the logical URL for the resource, and values are
|
||||||
* the resource itself.
|
* the resource itself.
|
||||||
* @param theBinaries The binary files to be returned by this module. Keys are the unique filename for the binary, and values
|
* @param theBinaries The binary files to be returned by this module. Keys are the unique filename for the binary, and values
|
||||||
* are the contents of the file as a byte array.
|
* are the contents of the file as a byte array.
|
||||||
*/
|
*/
|
||||||
public PrePopulatedValidationSupport(
|
public PrePopulatedValidationSupport(
|
||||||
FhirContext theFhirContext,
|
FhirContext theFhirContext,
|
||||||
Map<String, IBaseResource> theStructureDefinitions,
|
Map<String, IBaseResource> theUrlToStructureDefinitions,
|
||||||
Map<String, IBaseResource> theValueSets,
|
Map<String, IBaseResource> theUrlToValueSets,
|
||||||
Map<String, IBaseResource> theCodeSystems,
|
Map<String, IBaseResource> theUrlToCodeSystems,
|
||||||
Map<String, IBaseResource> theSearchParameters,
|
Map<String, IBaseResource> theUrlToSearchParameters,
|
||||||
Map<String, byte[]> theBinaries) {
|
Map<String, byte[]> theBinaries) {
|
||||||
super(theFhirContext);
|
super(theFhirContext);
|
||||||
Validate.notNull(theFhirContext, "theFhirContext must not be null");
|
Validate.notNull(theFhirContext, "theFhirContext must not be null");
|
||||||
Validate.notNull(theStructureDefinitions, "theStructureDefinitions must not be null");
|
Validate.notNull(theUrlToStructureDefinitions, "theStructureDefinitions must not be null");
|
||||||
Validate.notNull(theValueSets, "theValueSets must not be null");
|
Validate.notNull(theUrlToValueSets, "theValueSets must not be null");
|
||||||
Validate.notNull(theCodeSystems, "theCodeSystems must not be null");
|
Validate.notNull(theUrlToCodeSystems, "theCodeSystems must not be null");
|
||||||
Validate.notNull(theSearchParameters, "theSearchParameters must not be null");
|
Validate.notNull(theUrlToSearchParameters, "theSearchParameters must not be null");
|
||||||
Validate.notNull(theBinaries, "theBinaries must not be null");
|
Validate.notNull(theBinaries, "theBinaries must not be null");
|
||||||
myStructureDefinitions = theStructureDefinitions;
|
myUrlToStructureDefinitions = theUrlToStructureDefinitions;
|
||||||
myValueSets = theValueSets;
|
myStructureDefinitions =
|
||||||
myCodeSystems = theCodeSystems;
|
theUrlToStructureDefinitions.values().stream().distinct().collect(Collectors.toList());
|
||||||
mySearchParameters = theSearchParameters;
|
|
||||||
|
myUrlToValueSets = theUrlToValueSets;
|
||||||
|
myValueSets = theUrlToValueSets.values().stream().distinct().collect(Collectors.toList());
|
||||||
|
|
||||||
|
myUrlToCodeSystems = theUrlToCodeSystems;
|
||||||
|
myCodeSystems = theUrlToCodeSystems.values().stream().distinct().collect(Collectors.toList());
|
||||||
|
|
||||||
|
myUrlToSearchParameters = theUrlToSearchParameters;
|
||||||
|
mySearchParameters =
|
||||||
|
theUrlToSearchParameters.values().stream().distinct().collect(Collectors.toList());
|
||||||
|
|
||||||
myBinaries = theBinaries;
|
myBinaries = theBinaries;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +149,7 @@ public class PrePopulatedValidationSupport extends BaseStaticResourceValidationS
|
|||||||
public void addCodeSystem(IBaseResource theCodeSystem) {
|
public void addCodeSystem(IBaseResource theCodeSystem) {
|
||||||
validateNotLocked();
|
validateNotLocked();
|
||||||
Set<String> urls = processResourceAndReturnUrls(theCodeSystem, "CodeSystem");
|
Set<String> urls = processResourceAndReturnUrls(theCodeSystem, "CodeSystem");
|
||||||
addToMap(theCodeSystem, myCodeSystems, urls);
|
addToMap(theCodeSystem, myCodeSystems, myUrlToCodeSystems, urls);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<String> processResourceAndReturnUrls(IBaseResource theResource, String theResourceName) {
|
private Set<String> processResourceAndReturnUrls(IBaseResource theResource, String theResourceName) {
|
||||||
@ -185,16 +207,18 @@ public class PrePopulatedValidationSupport extends BaseStaticResourceValidationS
|
|||||||
public void addStructureDefinition(IBaseResource theStructureDefinition) {
|
public void addStructureDefinition(IBaseResource theStructureDefinition) {
|
||||||
validateNotLocked();
|
validateNotLocked();
|
||||||
Set<String> url = processResourceAndReturnUrls(theStructureDefinition, "StructureDefinition");
|
Set<String> url = processResourceAndReturnUrls(theStructureDefinition, "StructureDefinition");
|
||||||
addToMap(theStructureDefinition, myStructureDefinitions, url);
|
addToMap(theStructureDefinition, myStructureDefinitions, myUrlToStructureDefinitions, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSearchParameter(IBaseResource theSearchParameter) {
|
public void addSearchParameter(IBaseResource theSearchParameter) {
|
||||||
validateNotLocked();
|
validateNotLocked();
|
||||||
Set<String> url = processResourceAndReturnUrls(theSearchParameter, "SearchParameter");
|
Set<String> url = processResourceAndReturnUrls(theSearchParameter, "SearchParameter");
|
||||||
addToMap(theSearchParameter, mySearchParameters, url);
|
addToMap(theSearchParameter, mySearchParameters, myUrlToSearchParameters, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends IBaseResource> void addToMap(T theResource, Map<String, T> theMap, Collection<String> theUrls) {
|
private <T extends IBaseResource> void addToMap(
|
||||||
|
T theResource, List<T> theList, Map<String, T> theMap, Collection<String> theUrls) {
|
||||||
|
theList.add(theResource);
|
||||||
for (String urls : theUrls) {
|
for (String urls : theUrls) {
|
||||||
if (isNotBlank(urls)) {
|
if (isNotBlank(urls)) {
|
||||||
theMap.put(urls, theResource);
|
theMap.put(urls, theResource);
|
||||||
@ -228,7 +252,7 @@ public class PrePopulatedValidationSupport extends BaseStaticResourceValidationS
|
|||||||
public void addValueSet(IBaseResource theValueSet) {
|
public void addValueSet(IBaseResource theValueSet) {
|
||||||
validateNotLocked();
|
validateNotLocked();
|
||||||
Set<String> urls = processResourceAndReturnUrls(theValueSet, "ValueSet");
|
Set<String> urls = processResourceAndReturnUrls(theValueSet, "ValueSet");
|
||||||
addToMap(theValueSet, myValueSets, urls);
|
addToMap(theValueSet, myValueSets, myUrlToValueSets, urls);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -259,36 +283,38 @@ public class PrePopulatedValidationSupport extends BaseStaticResourceValidationS
|
|||||||
@Override
|
@Override
|
||||||
public List<IBaseResource> fetchAllConformanceResources() {
|
public List<IBaseResource> fetchAllConformanceResources() {
|
||||||
ArrayList<IBaseResource> retVal = new ArrayList<>();
|
ArrayList<IBaseResource> retVal = new ArrayList<>();
|
||||||
retVal.addAll(myCodeSystems.values());
|
retVal.addAll(myCodeSystems);
|
||||||
retVal.addAll(myStructureDefinitions.values());
|
retVal.addAll(myStructureDefinitions);
|
||||||
retVal.addAll(myValueSets.values());
|
retVal.addAll(myValueSets);
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public <T extends IBaseResource> List<T> fetchAllSearchParameters() {
|
public <T extends IBaseResource> List<T> fetchAllSearchParameters() {
|
||||||
return toList(mySearchParameters);
|
return (List<T>) Collections.unmodifiableList(mySearchParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public <T extends IBaseResource> List<T> fetchAllStructureDefinitions() {
|
public <T extends IBaseResource> List<T> fetchAllStructureDefinitions() {
|
||||||
return toList(myStructureDefinitions);
|
return (List<T>) Collections.unmodifiableList(myStructureDefinitions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBaseResource fetchCodeSystem(String theSystem) {
|
public IBaseResource fetchCodeSystem(String theSystem) {
|
||||||
return myCodeSystems.get(theSystem);
|
return myUrlToCodeSystems.get(theSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBaseResource fetchValueSet(String theUri) {
|
public IBaseResource fetchValueSet(String theUri) {
|
||||||
return myValueSets.get(theUri);
|
return myUrlToValueSets.get(theUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBaseResource fetchStructureDefinition(String theUrl) {
|
public IBaseResource fetchStructureDefinition(String theUrl) {
|
||||||
return myStructureDefinitions.get(theUrl);
|
return myUrlToStructureDefinitions.get(theUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -298,19 +324,23 @@ public class PrePopulatedValidationSupport extends BaseStaticResourceValidationS
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) {
|
public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) {
|
||||||
return myCodeSystems.containsKey(theSystem);
|
return myUrlToCodeSystems.containsKey(theSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValueSetSupported(ValidationSupportContext theValidationSupportContext, String theValueSetUrl) {
|
public boolean isValueSetSupported(ValidationSupportContext theValidationSupportContext, String theValueSetUrl) {
|
||||||
return myValueSets.containsKey(theValueSetUrl);
|
return myUrlToValueSets.containsKey(theValueSetUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a count of all known resources
|
* Returns a count of all known resources
|
||||||
*/
|
*/
|
||||||
public int countAll() {
|
public int countAll() {
|
||||||
return myBinaries.size() + myCodeSystems.size() + myStructureDefinitions.size() + myValueSets.size();
|
return myBinaries.size()
|
||||||
|
+ myCodeSystems.size()
|
||||||
|
+ myStructureDefinitions.size()
|
||||||
|
+ myValueSets.size()
|
||||||
|
+ myStructureDefinitions.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2,7 +2,6 @@ package org.hl7.fhir.dstu3.hapi.validation;
|
|||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
import org.hl7.fhir.r4.model.CodeSystem;
|
import org.hl7.fhir.r4.model.CodeSystem;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
@ -10,7 +9,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
|
||||||
public class DefaultProfileValidationSupportTest {
|
public class DefaultProfileValidationSupportR4Test {
|
||||||
|
|
||||||
private static FhirContext ourCtx = FhirContext.forR4Cached();
|
private static FhirContext ourCtx = FhirContext.forR4Cached();
|
||||||
private DefaultProfileValidationSupport mySvc = new DefaultProfileValidationSupport(ourCtx);
|
private DefaultProfileValidationSupport mySvc = new DefaultProfileValidationSupport(ourCtx);
|
@ -0,0 +1,29 @@
|
|||||||
|
package org.hl7.fhir.dstu3.hapi.validation;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
public class DefaultProfileValidationSupportR5Test {
|
||||||
|
|
||||||
|
private static FhirContext ourCtx = FhirContext.forR5Cached();
|
||||||
|
private DefaultProfileValidationSupport mySvc = new DefaultProfileValidationSupport(ourCtx);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoDuplicates() {
|
||||||
|
List<IBaseResource> allSds = mySvc.fetchAllStructureDefinitions()
|
||||||
|
.stream()
|
||||||
|
.map(t->(StructureDefinition)t)
|
||||||
|
.filter(t->t.getUrl().equals("http://hl7.org/fhir/StructureDefinition/language"))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
assertEquals(1, allSds.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user