From a5257f0fa8e0c792bde7c3a1a9d3a1e32c60aacf Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Thu, 19 Mar 2020 20:19:40 -0400 Subject: [PATCH] Add new indexing extractor method --- .../dao/r4/SearchParamExtractorR4Test.java | 17 ++ .../extractor/BaseSearchParamExtractor.java | 213 ++++++++++-------- .../extractor/ISearchParamExtractor.java | 3 + 3 files changed, 140 insertions(+), 93 deletions(-) diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/SearchParamExtractorR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/SearchParamExtractorR4Test.java index 38997c5fb5b..07f53c62737 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/SearchParamExtractorR4Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/SearchParamExtractorR4Test.java @@ -117,6 +117,23 @@ public class SearchParamExtractorR4Test { } + @Test + public void testExtractSearchParamTokenTest() { + Patient p = new Patient(); + p.addIdentifier().setSystem("sys").setValue("val"); + + SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), ourCtx, ourValidationSupport, mySearchParamRegistry); + RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam("Patient", Patient.SP_IDENTIFIER); + assertNotNull(param); + ISearchParamExtractor.SearchParamSet params = extractor.extractSearchParamTokens(p, param); + assertEquals(1, params.size()); + ResourceIndexedSearchParamToken paramValue = (ResourceIndexedSearchParamToken) params.iterator().next(); + assertEquals("identifier", paramValue.getParamName()); + assertEquals("sys", paramValue.getSystem()); + assertEquals("val", paramValue.getValue()); + } + + @Test public void testExtensionContainingReference() { String path = "Patient.extension('http://patext').value.as(Reference)"; diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/BaseSearchParamExtractor.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/BaseSearchParamExtractor.java index 10583e7095d..9ccff73e0a9 100644 --- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/BaseSearchParamExtractor.java +++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/BaseSearchParamExtractor.java @@ -186,7 +186,19 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor @Override public SearchParamSet extractSearchParamTokens(IBaseResource theResource) { + IExtractor extractor = createTokenExtractor(theResource); + return extractSearchParams(theResource, extractor, RestSearchParameterTypeEnum.TOKEN); + } + @Override + public SearchParamSet extractSearchParamTokens(IBaseResource theResource, RuntimeSearchParam theSearchParam) { + IExtractor extractor = createTokenExtractor(theResource); + SearchParamSet setToPopulate = new SearchParamSet<>(); + extractSearchParam(theSearchParam, theResource, extractor, setToPopulate); + return setToPopulate; + } + + private IExtractor createTokenExtractor(IBaseResource theResource) { String resourceTypeName = toRootTypeName(theResource); String useSystem; if (getContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2)) { @@ -204,85 +216,7 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor } } - IExtractor extractor = (params, searchParam, value, path) -> { - - // DSTU3+ - if (value instanceof IBaseEnumeration) { - IBaseEnumeration obj = (IBaseEnumeration) value; - String system = extractSystem(obj); - String code = obj.getValueAsString(); - createTokenIndexIfNotBlank(resourceTypeName, params, searchParam, system, code); - return; - } - - // DSTU2 only - if (value instanceof BoundCodeDt) { - BoundCodeDt boundCode = (BoundCodeDt) value; - Enum valueAsEnum = boundCode.getValueAsEnum(); - String system = null; - if (valueAsEnum != null) { - //noinspection unchecked - system = boundCode.getBinder().toSystemString(valueAsEnum); - } - String code = boundCode.getValueAsString(); - createTokenIndexIfNotBlank(resourceTypeName, params, searchParam, system, code); - return; - } - - if (value instanceof IPrimitiveType) { - IPrimitiveType nextValue = (IPrimitiveType) value; - String systemAsString = null; - String valueAsString = nextValue.getValueAsString(); - if ("CodeSystem.concept.code".equals(path)) { - systemAsString = useSystem; - } else if ("ValueSet.codeSystem.concept.code".equals(path)) { - systemAsString = useSystem; - } - - createTokenIndexIfNotBlank(resourceTypeName, params, searchParam, systemAsString, valueAsString); - return; - } - - switch (path) { - case "Patient.communication": - addToken_PatientCommunication(resourceTypeName, params, searchParam, value); - return; - case "Consent.source": - // Consent#source-identifier has a path that isn't typed - This is a one-off to deal with that - return; - case "Location.position": - addCoords_Position(resourceTypeName, params, searchParam, value); - return; - case "StructureDefinition.context": - // TODO: implement this - ourLog.warn("StructureDefinition context indexing not currently supported"); - return; - case "CapabilityStatement.rest.security": - addToken_CapabilityStatementRestSecurity(resourceTypeName, params, searchParam, value); - return; - } - - String nextType = toRootTypeName(value); - switch (nextType) { - case "Identifier": - addToken_Identifier(resourceTypeName, params, searchParam, value); - break; - case "CodeableConcept": - addToken_CodeableConcept(resourceTypeName, params, searchParam, value); - break; - case "Coding": - addToken_Coding(resourceTypeName, params, searchParam, value); - break; - case "ContactPoint": - addToken_ContactPoint(resourceTypeName, params, searchParam, value); - break; - default: - addUnexpectedDatatypeWarning(params, searchParam, value); - break; - } - }; - - return extractSearchParams(theResource, extractor, RestSearchParameterTypeEnum.TOKEN); + return new TokenExtractor(resourceTypeName, useSystem); } @Override @@ -798,25 +732,29 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor continue; } - String nextPathUnsplit = nextSpDef.getPath(); - if (isBlank(nextPathUnsplit)) { - continue; - } + extractSearchParam(nextSpDef, theResource, theExtractor, retVal); + } + return retVal; + } - String[] splitPaths = split(nextPathUnsplit); - for (String nextPath : splitPaths) { - nextPath = trim(nextPath); - for (IBase nextObject : extractValues(nextPath, theResource)) { - if (nextObject != null) { - String typeName = toRootTypeName(nextObject); - if (!myIgnoredForSearchDatatypes.contains(typeName)) { - theExtractor.extract(retVal, nextSpDef, nextObject, nextPath); - } + private void extractSearchParam(RuntimeSearchParam theSearchParameterDef, IBaseResource theResource, IExtractor theExtractor, SearchParamSet theSetToPopulate) { + String nextPathUnsplit = theSearchParameterDef.getPath(); + if (isBlank(nextPathUnsplit)) { + return; + } + + String[] splitPaths = split(nextPathUnsplit); + for (String nextPath : splitPaths) { + nextPath = trim(nextPath); + for (IBase nextObject : extractValues(nextPath, theResource)) { + if (nextObject != null) { + String typeName = toRootTypeName(nextObject); + if (!myIgnoredForSearchDatatypes.contains(typeName)) { + theExtractor.extract(theSetToPopulate, theSearchParameterDef, nextObject, nextPath); } } } } - return retVal; } private String toRootTypeName(IBase nextObject) { @@ -1032,6 +970,95 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor } + private class TokenExtractor implements IExtractor { + private final String myResourceTypeName; + private final String myUseSystem; + + public TokenExtractor(String theResourceTypeName, String theUseSystem) { + myResourceTypeName = theResourceTypeName; + myUseSystem = theUseSystem; + } + + @Override + public void extract(SearchParamSet params, RuntimeSearchParam searchParam, IBase value, String path) { + + // DSTU3+ + if (value instanceof IBaseEnumeration) { + IBaseEnumeration obj = (IBaseEnumeration) value; + String system = extractSystem(obj); + String code = obj.getValueAsString(); + BaseSearchParamExtractor.this.createTokenIndexIfNotBlank(myResourceTypeName, params, searchParam, system, code); + return; + } + + // DSTU2 only + if (value instanceof BoundCodeDt) { + BoundCodeDt boundCode = (BoundCodeDt) value; + Enum valueAsEnum = boundCode.getValueAsEnum(); + String system = null; + if (valueAsEnum != null) { + //noinspection unchecked + system = boundCode.getBinder().toSystemString(valueAsEnum); + } + String code = boundCode.getValueAsString(); + BaseSearchParamExtractor.this.createTokenIndexIfNotBlank(myResourceTypeName, params, searchParam, system, code); + return; + } + + if (value instanceof IPrimitiveType) { + IPrimitiveType nextValue = (IPrimitiveType) value; + String systemAsString = null; + String valueAsString = nextValue.getValueAsString(); + if ("CodeSystem.concept.code".equals(path)) { + systemAsString = myUseSystem; + } else if ("ValueSet.codeSystem.concept.code".equals(path)) { + systemAsString = myUseSystem; + } + + BaseSearchParamExtractor.this.createTokenIndexIfNotBlank(myResourceTypeName, params, searchParam, systemAsString, valueAsString); + return; + } + + switch (path) { + case "Patient.communication": + BaseSearchParamExtractor.this.addToken_PatientCommunication(myResourceTypeName, params, searchParam, value); + return; + case "Consent.source": + // Consent#source-identifier has a path that isn't typed - This is a one-off to deal with that + return; + case "Location.position": + BaseSearchParamExtractor.this.addCoords_Position(myResourceTypeName, params, searchParam, value); + return; + case "StructureDefinition.context": + // TODO: implement this + ourLog.warn("StructureDefinition context indexing not currently supported"); + return; + case "CapabilityStatement.rest.security": + BaseSearchParamExtractor.this.addToken_CapabilityStatementRestSecurity(myResourceTypeName, params, searchParam, value); + return; + } + + String nextType = BaseSearchParamExtractor.this.toRootTypeName(value); + switch (nextType) { + case "Identifier": + BaseSearchParamExtractor.this.addToken_Identifier(myResourceTypeName, params, searchParam, value); + break; + case "CodeableConcept": + BaseSearchParamExtractor.this.addToken_CodeableConcept(myResourceTypeName, params, searchParam, value); + break; + case "Coding": + BaseSearchParamExtractor.this.addToken_Coding(myResourceTypeName, params, searchParam, value); + break; + case "ContactPoint": + BaseSearchParamExtractor.this.addToken_ContactPoint(myResourceTypeName, params, searchParam, value); + break; + default: + BaseSearchParamExtractor.this.addUnexpectedDatatypeWarning(params, searchParam, value); + break; + } + } + } + private static void addIgnoredType(FhirContext theCtx, String theType, Set theIgnoredTypes) { BaseRuntimeElementDefinition elementDefinition = theCtx.getElementDefinition(theType); if (elementDefinition != null) { diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ISearchParamExtractor.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ISearchParamExtractor.java index 1f9ef8bb3ea..15e4479ab8c 100644 --- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ISearchParamExtractor.java +++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ISearchParamExtractor.java @@ -1,5 +1,6 @@ package ca.uhn.fhir.jpa.searchparam.extractor; +import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.jpa.model.entity.*; import org.hl7.fhir.instance.model.api.IBaseResource; @@ -42,6 +43,8 @@ public interface ISearchParamExtractor { SearchParamSet extractSearchParamTokens(IBaseResource theResource); + SearchParamSet extractSearchParamTokens(IBaseResource theResource, RuntimeSearchParam theSearchParam); + SearchParamSet extractSearchParamSpecial(IBaseResource theResource); SearchParamSet extractSearchParamUri(IBaseResource theResource);