From 6d005cfdac608192393f8368861de2c7a47e977d Mon Sep 17 00:00:00 2001 From: Troy Biesterfeld Date: Mon, 26 Oct 2020 14:37:27 -0500 Subject: [PATCH] issue #1351 - Add searchInclude and searchRevInclude to capabilities Signed-off-by: Troy Biesterfeld --- .../fhir/server/resources/Capabilities.java | 60 +++++++++++++++---- .../fhir/server/test/CapabilitiesTest.java | 23 ++++--- .../config/empty/fhir-server-config.json | 8 ++- .../smart-enabled/fhir-server-config.json | 6 +- 4 files changed, 73 insertions(+), 24 deletions(-) diff --git a/fhir-server/src/main/java/com/ibm/fhir/server/resources/Capabilities.java b/fhir-server/src/main/java/com/ibm/fhir/server/resources/Capabilities.java index 03559e0506e..1255dd91433 100644 --- a/fhir-server/src/main/java/com/ibm/fhir/server/resources/Capabilities.java +++ b/fhir-server/src/main/java/com/ibm/fhir/server/resources/Capabilities.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -183,18 +184,28 @@ private CapabilityStatement buildCapabilityStatement() throws Exception { // Retrieve the "resources" config property group. PropertyGroup rsrcsGroup = FHIRConfigHelper.getPropertyGroup(FHIRConfiguration.PROPERTY_RESOURCES); - // Build the list of interactions that are supported for each resource type by default. - List interactionConfig = null; + // Build the list of interactions, searchIncludes, and searchRevIncludes supported for each resource type by default. + List defaultInteractions = buildInteractions(ALL_INTERACTIONS); + List defaultSearchIncludes = Collections.emptyList(); + List defaultSearchRevIncludes = Collections.emptyList(); if (rsrcsGroup != null) { PropertyGroup parentResourcePropGroup = rsrcsGroup.getPropertyGroup(ResourceType.ValueSet.RESOURCE.value()); if (parentResourcePropGroup != null) { - interactionConfig = parentResourcePropGroup.getStringListProperty(FHIRConfiguration.PROPERTY_FIELD_RESOURCES_INTERACTIONS); + List interactionConfig = parentResourcePropGroup.getStringListProperty(FHIRConfiguration.PROPERTY_FIELD_RESOURCES_INTERACTIONS); + if (interactionConfig != null) { + defaultInteractions = buildInteractions(interactionConfig); + } + List searchIncludeConfig = parentResourcePropGroup.getStringListProperty(FHIRConfiguration.PROPERTY_FIELD_RESOURCES_SEARCH_INCLUDES); + if (searchIncludeConfig != null) { + defaultSearchIncludes = convertStringList(searchIncludeConfig); + } + List searchRevIncludeConfig = + parentResourcePropGroup.getStringListProperty(FHIRConfiguration.PROPERTY_FIELD_RESOURCES_SEARCH_REV_INCLUDES); + if (searchRevIncludeConfig != null) { + defaultSearchRevIncludes = convertStringList(searchRevIncludeConfig); + } } } - if (interactionConfig == null) { - interactionConfig = ALL_INTERACTIONS; - } - List defaultInteractions = buildInteractions(interactionConfig); // Build the lists of operations that are supported List systemOps = new ArrayList<>(); @@ -257,18 +268,29 @@ private CapabilityStatement buildCapabilityStatement() throws Exception { ops.addAll(mapOperationDefinitionsToRestOperations(typeOps.get(ResourceType.ValueSet.DOMAIN_RESOURCE))); } - List interactions = null; + // Build the list of interactions, searchIncludes, and searchRevIncludes supported for the resource type. + List interactions = defaultInteractions; + List searchIncludes = defaultSearchIncludes; + List searchRevIncludes = defaultSearchRevIncludes; if (rsrcsGroup != null) { PropertyGroup resourcePropGroup = rsrcsGroup.getPropertyGroup(resourceTypeName); if (resourcePropGroup != null) { List resourceInteractionConfig = resourcePropGroup.getStringListProperty(FHIRConfiguration.PROPERTY_FIELD_RESOURCES_INTERACTIONS); - interactions = buildInteractions(resourceInteractionConfig); + if (resourceInteractionConfig != null) { + interactions = buildInteractions(resourceInteractionConfig); + } + List searchIncludeConfig = resourcePropGroup.getStringListProperty(FHIRConfiguration.PROPERTY_FIELD_RESOURCES_SEARCH_INCLUDES); + if (searchIncludeConfig != null) { + searchIncludes = convertStringList(searchIncludeConfig); + } + List searchRevIncludeConfig = + resourcePropGroup.getStringListProperty(FHIRConfiguration.PROPERTY_FIELD_RESOURCES_SEARCH_REV_INCLUDES); + if (searchRevIncludeConfig != null) { + searchRevIncludes = convertStringList(searchRevIncludeConfig); + } } } - if (interactions == null) { - interactions = defaultInteractions; - } // Build the ConformanceResource for this resource type. Rest.Resource cr = Rest.Resource.builder() @@ -282,6 +304,8 @@ private CapabilityStatement buildCapabilityStatement() throws Exception { .conditionalDelete(ConditionalDeleteStatus.MULTIPLE) .conditionalRead(ConditionalReadStatus.FULL_SUPPORT) .searchParam(conformanceSearchParams) + .searchInclude(searchIncludes) + .searchRevInclude(searchRevIncludes) .build(); resources.add(cr); @@ -436,6 +460,18 @@ private List buildInteractions(List interacti return interactions; } + /** + * Convert list of Java strings to list of FHIR strings. + * @param stringList a list of Java string, or null + * @return a list of FHIR strings, or null + */ + private List convertStringList(List stringList) { + if (stringList != null) { + return stringList.stream().map(k -> com.ibm.fhir.model.type.String.of(k)).collect(Collectors.toList()); + } + return null; + } + /** * @param rsrcsGroup the "resources" propertyGroup from the server configuration * @return a list of resource types to support diff --git a/fhir-server/src/test/java/com/ibm/fhir/server/test/CapabilitiesTest.java b/fhir-server/src/test/java/com/ibm/fhir/server/test/CapabilitiesTest.java index 202fdfd90d2..919b541694c 100644 --- a/fhir-server/src/test/java/com/ibm/fhir/server/test/CapabilitiesTest.java +++ b/fhir-server/src/test/java/com/ibm/fhir/server/test/CapabilitiesTest.java @@ -51,7 +51,7 @@ void testBuildCapabilityStatement_resources_omitted() throws Exception { assertEquals(capabilityStatement.getRest().size(), 1, "Number of REST Elements"); CapabilityStatement.Rest restDefinition = capabilityStatement.getRest().get(0); - assertRestDefinition(restDefinition, 146, 8, 8); + assertRestDefinition(restDefinition, 146, 8, 0, 0, 8, 0, 0); } @Test @@ -66,7 +66,7 @@ void testBuildCapabilityStatement_resources_empty() throws Exception { assertEquals(capabilityStatement.getRest().size(), 1, "Number of REST Elements"); CapabilityStatement.Rest restDefinition = capabilityStatement.getRest().get(0); - assertRestDefinition(restDefinition, 146, 0, 0); + assertRestDefinition(restDefinition, 146, 0, 0, 0, 0, 0, 0); } @Test @@ -81,26 +81,33 @@ void testBuildCapabilityStatement_resources_filtered() throws Exception { assertEquals(capabilityStatement.getRest().size(), 1, "Number of REST Elements"); CapabilityStatement.Rest restDefinition = capabilityStatement.getRest().get(0); - assertRestDefinition(restDefinition, 2, 2, 4); + assertRestDefinition(restDefinition, 2, 2, 1, 0, 4, 0, 1); } - private void assertRestDefinition(CapabilityStatement.Rest restDefinition, int numOfResources, int patientInteractions, int practitionerInteractions) { + private void assertRestDefinition(CapabilityStatement.Rest restDefinition, int numOfResources, + int patientInteractions, int patientIncludes, int patientRevIncludes, + int practitionerInteractions, int practitionerIncludes, int practitionerRevIncludes) { assertEquals(restDefinition.getResource().size(), numOfResources, "Number of supported resources"); assertFalse(restDefinition.getResource().stream().anyMatch(r -> r.getType().getValueAsEnumConstant() == ResourceType.ValueSet.RESOURCE)); assertFalse(restDefinition.getResource().stream().anyMatch(r -> r.getType().getValueAsEnumConstant() == ResourceType.ValueSet.DOMAIN_RESOURCE)); - assertInteractions(restDefinition, ResourceType.ValueSet.PATIENT, patientInteractions); - assertInteractions(restDefinition, ResourceType.ValueSet.PRACTITIONER, practitionerInteractions); + assertResourceDefinition(restDefinition, ResourceType.ValueSet.PATIENT, patientInteractions, patientIncludes, patientRevIncludes); + assertResourceDefinition(restDefinition, ResourceType.ValueSet.PRACTITIONER, practitionerInteractions, practitionerIncludes, practitionerRevIncludes); } - private void assertInteractions(CapabilityStatement.Rest restDefinition, ResourceType.ValueSet resourceType, int numOfInteractions) { + private void assertResourceDefinition(CapabilityStatement.Rest restDefinition, ResourceType.ValueSet resourceType, int numOfInteractions, + int numIncludes, int numRevIncludes) { Optional resource = restDefinition.getResource().stream() .filter(r -> r.getType().getValueAsEnumConstant() == resourceType) .findFirst(); assertTrue(resource.isPresent()); List interactions = resource.get().getInteraction(); - assertEquals(interactions.size(), numOfInteractions, "Number of supported interactions for the Patient resource type"); + assertEquals(interactions.size(), numOfInteractions, "Number of supported interactions for the " + resourceType + " resource type"); + List includes = resource.get().getSearchInclude(); + assertEquals(includes.size(), numIncludes, "Number of supported search includes for the " + resourceType + " resource type"); + List revIncludes = resource.get().getSearchRevInclude(); + assertEquals(revIncludes.size(), numRevIncludes, "Number of supported search revincludes for the " + resourceType + " resource type"); } /** diff --git a/fhir-server/src/test/resources/config/empty/fhir-server-config.json b/fhir-server/src/test/resources/config/empty/fhir-server-config.json index fe15a9ce7ad..30989f7f6a6 100644 --- a/fhir-server/src/test/resources/config/empty/fhir-server-config.json +++ b/fhir-server/src/test/resources/config/empty/fhir-server-config.json @@ -5,11 +5,15 @@ "open": true, "Patient": { "interactions": [], - "searchParameters": {} + "searchParameters": {}, + "searchInclude": [], + "searchRevInclude": [] }, "Resource": { "interactions": [], - "searchParameters": {} + "searchParameters": {}, + "searchInclude": [], + "searchRevInclude": [] } }, "security": { diff --git a/fhir-server/src/test/resources/config/smart-enabled/fhir-server-config.json b/fhir-server/src/test/resources/config/smart-enabled/fhir-server-config.json index 08683cfa355..c7e91daf006 100644 --- a/fhir-server/src/test/resources/config/smart-enabled/fhir-server-config.json +++ b/fhir-server/src/test/resources/config/smart-enabled/fhir-server-config.json @@ -11,13 +11,15 @@ "gender": "http://hl7.org/fhir/SearchParameter/individual-gender", "identifier": "http://hl7.org/fhir/SearchParameter/Patient-identifier", "name": "http://hl7.org/fhir/SearchParameter/Patient-name" - } + }, + "searchIncludes": ["Patient:general-practitioner"] }, "Practitioner": { "searchParameters": { "name": "http://hl7.org/fhir/SearchParameter/Practitioner-name", "identifier": "http://hl7.org/fhir/SearchParameter/Practitioner-identifier" - } + }, + "searchRevIncludes": ["Patient:general-practitioner"] }, "Resource": { "interactions": ["read", "vread", "history", "search"],