Merge remote-tracking branch 'remotes/origin/master' into im_20200630_code_system_load
This commit is contained in:
commit
46abdfafe0
|
@ -44,7 +44,7 @@
|
|||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>6.0.5</version>
|
||||
<version>8.0.16</version>
|
||||
</dependency>
|
||||
|
||||
<!-- This dependency includes the core HAPI-FHIR classes -->
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<!-- <version>6.0.5</version>-->
|
||||
<version>5.1.40</version>
|
||||
<version>8.0.16</version>
|
||||
</dependency>
|
||||
<!--
|
||||
<dependency>
|
||||
|
|
|
@ -21,13 +21,32 @@ package ca.uhn.fhir.context;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam.RuntimeSearchParamStatusEnum;
|
||||
import ca.uhn.fhir.model.api.*;
|
||||
import ca.uhn.fhir.model.api.annotation.*;
|
||||
import ca.uhn.fhir.model.api.BaseIdentifiableElement;
|
||||
import ca.uhn.fhir.model.api.ExtensionDt;
|
||||
import ca.uhn.fhir.model.api.IDatatype;
|
||||
import ca.uhn.fhir.model.api.IElement;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.IResourceBlock;
|
||||
import ca.uhn.fhir.model.api.IValueSetEnumBinder;
|
||||
import ca.uhn.fhir.model.api.annotation.Block;
|
||||
import ca.uhn.fhir.model.api.annotation.Child;
|
||||
import ca.uhn.fhir.model.api.annotation.Compartment;
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.model.api.annotation.SearchParamDefinition;
|
||||
import ca.uhn.fhir.model.primitive.BoundCodeDt;
|
||||
import ca.uhn.fhir.model.primitive.XhtmlDt;
|
||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||
import ca.uhn.fhir.util.ReflectionUtil;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBackboneElement;
|
||||
import org.hl7.fhir.instance.model.api.IBaseDatatype;
|
||||
import org.hl7.fhir.instance.model.api.IBaseDatatypeElement;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IBaseXhtml;
|
||||
import org.hl7.fhir.instance.model.api.ICompositeType;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.IOException;
|
||||
|
@ -37,8 +56,18 @@ import java.lang.reflect.AnnotatedElement;
|
|||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
|
@ -390,7 +419,7 @@ class ModelScanner {
|
|||
for (String nextName : searchParam.compositeOf()) {
|
||||
RuntimeSearchParam param = nameToParam.get(nextName);
|
||||
if (param == null) {
|
||||
ourLog.warn("Search parameter {}.{} declares that it is a composite with compositeOf value '{}' but that is not a valid parametr name itself. Valid values are: {}",
|
||||
ourLog.warn("Search parameter {}.{} declares that it is a composite with compositeOf value '{}' but that is not a valid parameter name itself. Valid values are: {}",
|
||||
theResourceDef.getName(), searchParam.name(), nextName, nameToParam.keySet());
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,13 @@ package ca.uhn.fhir.context;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IDomainResource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
@ -28,15 +35,6 @@ import java.util.LinkedHashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IDomainResource;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
|
||||
public class RuntimeResourceDefinition extends BaseRuntimeElementCompositeDefinition<IBaseResource> {
|
||||
|
||||
private Class<? extends IBaseResource> myBaseType;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package ca.uhn.fhir.context;
|
||||
|
||||
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
|
||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
|
@ -55,6 +56,7 @@ public class RuntimeSearchParam {
|
|||
private final RuntimeSearchParamStatusEnum myStatus;
|
||||
private final String myUri;
|
||||
private final Map<String, List<IBaseExtension<?, ?>>> myExtensions = new HashMap<>();
|
||||
private IPhoneticEncoder myPhoneticEncoder;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -245,7 +247,6 @@ public class RuntimeSearchParam {
|
|||
return myProvidesMembershipInCompartments;
|
||||
}
|
||||
|
||||
|
||||
public enum RuntimeSearchParamStatusEnum {
|
||||
ACTIVE,
|
||||
DRAFT,
|
||||
|
@ -253,4 +254,15 @@ public class RuntimeSearchParam {
|
|||
UNKNOWN
|
||||
}
|
||||
|
||||
public RuntimeSearchParam setPhoneticEncoder(IPhoneticEncoder thePhoneticEncoder) {
|
||||
myPhoneticEncoder = thePhoneticEncoder;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String encode(String theString) {
|
||||
if (myPhoneticEncoder == null || theString == null) {
|
||||
return theString;
|
||||
}
|
||||
return myPhoneticEncoder.encode(theString);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package ca.uhn.fhir.empi.rules.metric.matcher;
|
||||
package ca.uhn.fhir.context.phonetic;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Enterprise Master Patient Index
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2020 University Health Network
|
||||
* %%
|
||||
|
@ -25,22 +25,29 @@ import org.apache.commons.codec.StringEncoder;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class StringEncoderMatcher implements IEmpiStringMatcher {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(StringEncoderMatcher.class);
|
||||
public class ApacheEncoder implements IPhoneticEncoder {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(ApacheEncoder.class);
|
||||
|
||||
private final String myName;
|
||||
private final StringEncoder myStringEncoder;
|
||||
|
||||
public StringEncoderMatcher(StringEncoder theStringEncoder) {
|
||||
public ApacheEncoder(String theName, StringEncoder theStringEncoder) {
|
||||
myName = theName;
|
||||
myStringEncoder = theStringEncoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(String theLeftString, String theRightString) {
|
||||
public String name() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encode(String theString) {
|
||||
try {
|
||||
return myStringEncoder.encode(theLeftString).equals(myStringEncoder.encode(theRightString));
|
||||
return myStringEncoder.encode(theString);
|
||||
} catch (EncoderException e) {
|
||||
ourLog.error("Failed to match strings '{}' and '{}' using encoder {}", theLeftString, theRightString, myStringEncoder.getClass().getName(), e);
|
||||
ourLog.error("Failed to encode string " + theString, e);
|
||||
return theString;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
package ca.uhn.fhir.empi.rules.metric.matcher;
|
||||
package ca.uhn.fhir.context.phonetic;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Enterprise Master Patient Index
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2020 University Health Network
|
||||
* %%
|
||||
|
@ -20,11 +20,13 @@ package ca.uhn.fhir.empi.rules.metric.matcher;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import org.apache.commons.codec.language.Metaphone;
|
||||
public interface IPhoneticEncoder {
|
||||
String name();
|
||||
|
||||
public class MetaphoneStringMatcher implements IEmpiStringMatcher {
|
||||
@Override
|
||||
public boolean matches(String theLeftString, String theRightString) {
|
||||
return new Metaphone().isMetaphoneEqual(theLeftString, theRightString);
|
||||
}
|
||||
/**
|
||||
* Encode the provided string using a phonetic encoder like Soundex
|
||||
* @param theString
|
||||
* @return
|
||||
*/
|
||||
String encode(String theString);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package ca.uhn.fhir.context.phonetic;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2020 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import org.apache.commons.codec.language.Caverphone1;
|
||||
import org.apache.commons.codec.language.Caverphone2;
|
||||
import org.apache.commons.codec.language.ColognePhonetic;
|
||||
import org.apache.commons.codec.language.DoubleMetaphone;
|
||||
import org.apache.commons.codec.language.MatchRatingApproachEncoder;
|
||||
import org.apache.commons.codec.language.Metaphone;
|
||||
import org.apache.commons.codec.language.Nysiis;
|
||||
import org.apache.commons.codec.language.RefinedSoundex;
|
||||
import org.apache.commons.codec.language.Soundex;
|
||||
|
||||
public enum PhoneticEncoderEnum {
|
||||
CAVERPHONE1(new ApacheEncoder("CAVERPHONE1", new Caverphone1())),
|
||||
CAVERPHONE2(new ApacheEncoder("CAVERPHONE2", new Caverphone2())),
|
||||
COLOGNE(new ApacheEncoder("COLOGNE", new ColognePhonetic())),
|
||||
DOUBLE_METAPHONE(new ApacheEncoder("DOUBLE_METAPHONE", new DoubleMetaphone())),
|
||||
MATCH_RATING_APPROACH(new ApacheEncoder("MATCH_RATING_APPROACH", new MatchRatingApproachEncoder())),
|
||||
METAPHONE(new ApacheEncoder("METAPHONE", new Metaphone())),
|
||||
NYSIIS(new ApacheEncoder("NYSIIS", new Nysiis())),
|
||||
REFINED_SOUNDEX(new ApacheEncoder("REFINED_SOUNDEX", new RefinedSoundex())),
|
||||
SOUNDEX(new ApacheEncoder("SOUNDEX", new Soundex()));
|
||||
|
||||
private final IPhoneticEncoder myPhoneticEncoder;
|
||||
|
||||
PhoneticEncoderEnum(IPhoneticEncoder thePhoneticEncoder) {
|
||||
myPhoneticEncoder = thePhoneticEncoder;
|
||||
}
|
||||
|
||||
public IPhoneticEncoder getPhoneticEncoder() {
|
||||
return myPhoneticEncoder;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,25 @@
|
|||
package ca.uhn.fhir.util;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2020 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
public class HapiExtensions {
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
package ca.uhn.fhir.util;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2020 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
||||
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
type: add
|
||||
issue: 1936
|
||||
title: "Phonetic name search is now supported via ISearchParamRegistry.setStringEncoder()."
|
|
@ -158,46 +158,6 @@ The following metrics are currently supported:
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>STRING</td>
|
||||
<td>matcher</td>
|
||||
<td>
|
||||
Match the values as strings. This matcher should be used with tokens (e.g. gender).
|
||||
</td>
|
||||
<td>MCTAVISH = McTavish when exact = false, MCTAVISH != McTavish when exact = true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SUBSTRING</td>
|
||||
<td>matcher</td>
|
||||
<td>
|
||||
True if one string starts with the other.
|
||||
</td>
|
||||
<td>Bill = Billy, Egbert = Bert</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>METAPHONE</td>
|
||||
<td>matcher</td>
|
||||
<td>
|
||||
<a href="https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/language/Metaphone.html">Apache Metaphone</a>
|
||||
</td>
|
||||
<td>Dury = Durie, Allsop != Allsob, Smith != Schmidt</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DOUBLE_METAPHONE</td>
|
||||
<td>matcher</td>
|
||||
<td>
|
||||
<a href="https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/language/DoubleMetaphone.html">Apache Double Metaphone</a>
|
||||
</td>
|
||||
<td>Dury = Durie, Allsop = Allsob, Smith != Schmidt</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SOUNDEX</td>
|
||||
<td>matcher</td>
|
||||
<td>
|
||||
<a href="https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/language/Soundex.html">Apache Soundex</a>
|
||||
</td>
|
||||
<td>Jon = John, Thomas != Tom</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>CAVERPHONE1</td>
|
||||
<td>matcher</td>
|
||||
|
@ -214,6 +174,78 @@ The following metrics are currently supported:
|
|||
</td>
|
||||
<td>Gail = Gael, Gail = Gale, Thomas != Tom</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>COLOGNE</td>
|
||||
<td>matcher</td>
|
||||
<td>
|
||||
<a href="https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/language/ColognePhonetic.html">Apache Cologne Phonetic</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DOUBLE_METAPHONE</td>
|
||||
<td>matcher</td>
|
||||
<td>
|
||||
<a href="https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/language/DoubleMetaphone.html">Apache Double Metaphone</a>
|
||||
</td>
|
||||
<td>Dury = Durie, Allsop = Allsob, Smith != Schmidt</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MATCH_RATING_APPROACH</td>
|
||||
<td>matcher</td>
|
||||
<td>
|
||||
<a href="https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/language/MatchRatingApproachEncoder.html">Apache Match Rating Approach Encoder</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>METAPHONE</td>
|
||||
<td>matcher</td>
|
||||
<td>
|
||||
<a href="https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/language/Metaphone.html">Apache Metaphone</a>
|
||||
</td>
|
||||
<td>Dury = Durie, Allsop != Allsob, Smith != Schmidt</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>NYSIIS</td>
|
||||
<td>matcher</td>
|
||||
<td>
|
||||
<a href="https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/language/Nysiis.html">Apache Nysiis</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>REFINED_SOUNDEX</td>
|
||||
<td>matcher</td>
|
||||
<td>
|
||||
<a href="https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/language/RefinedSoundex.html">Apache Refined Soundex</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SOUNDEX</td>
|
||||
<td>matcher</td>
|
||||
<td>
|
||||
<a href="https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/language/Soundex.html">Apache Soundex</a>
|
||||
</td>
|
||||
<td>Jon = John, Thomas != Tom</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>STRING</td>
|
||||
<td>matcher</td>
|
||||
<td>
|
||||
Match the values as strings. This matcher should be used with tokens (e.g. gender).
|
||||
</td>
|
||||
<td>MCTAVISH = McTavish when exact = false, MCTAVISH != McTavish when exact = true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SUBSTRING</td>
|
||||
<td>matcher</td>
|
||||
<td>
|
||||
True if one string starts with the other.
|
||||
</td>
|
||||
<td>Bill = Billy, Egbert = Bert</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DATE</td>
|
||||
<td>matcher</td>
|
||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.dao.predicate;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
|
||||
|
@ -30,7 +31,7 @@ import java.util.List;
|
|||
public interface IPredicateBuilder {
|
||||
@Nullable
|
||||
Predicate addPredicate(String theResourceName,
|
||||
String theParamName,
|
||||
RuntimeSearchParam theSearchParam,
|
||||
List<? extends IQueryParameterType> theList,
|
||||
SearchFilterParser.CompareOperation operation,
|
||||
RequestPartitionId theRequestPartitionId);
|
||||
|
|
|
@ -20,13 +20,22 @@ package ca.uhn.fhir.jpa.dao.predicate;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
||||
import ca.uhn.fhir.jpa.model.entity.*;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
|
||||
import javax.persistence.criteria.*;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.From;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Subquery;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
@ -56,40 +65,40 @@ public class PredicateBuilder {
|
|||
myPredicateBuilderUri = thePredicateBuilderFactory.newPredicateBuilderUri(theSearchBuilder);
|
||||
}
|
||||
|
||||
void addPredicateCoords(String theResourceName, String theParamName, List<? extends IQueryParameterType> theNextAnd, RequestPartitionId theRequestPartitionId) {
|
||||
myPredicateBuilderCoords.addPredicate(theResourceName, theParamName, theNextAnd, null, theRequestPartitionId);
|
||||
void addPredicateCoords(String theResourceName, RuntimeSearchParam theSearchParam, List<? extends IQueryParameterType> theNextAnd, RequestPartitionId theRequestPartitionId) {
|
||||
myPredicateBuilderCoords.addPredicate(theResourceName, theSearchParam, theNextAnd, null, theRequestPartitionId);
|
||||
}
|
||||
|
||||
Predicate addPredicateDate(String theResourceName, String theParamName, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||
return myPredicateBuilderDate.addPredicate(theResourceName, theParamName, theNextAnd, theOperation, theRequestPartitionId);
|
||||
Predicate addPredicateDate(String theResourceName, RuntimeSearchParam theSearchParam, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||
return myPredicateBuilderDate.addPredicate(theResourceName, theSearchParam, theNextAnd, theOperation, theRequestPartitionId);
|
||||
}
|
||||
|
||||
Predicate addPredicateNumber(String theResourceName, String theParamName, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||
return myPredicateBuilderNumber.addPredicate(theResourceName, theParamName, theNextAnd, theOperation, theRequestPartitionId);
|
||||
Predicate addPredicateNumber(String theResourceName, RuntimeSearchParam theSearchParam, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||
return myPredicateBuilderNumber.addPredicate(theResourceName, theSearchParam, theNextAnd, theOperation, theRequestPartitionId);
|
||||
}
|
||||
|
||||
Predicate addPredicateQuantity(String theResourceName, String theParamName, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||
return myPredicateBuilderQuantity.addPredicate(theResourceName, theParamName, theNextAnd, theOperation, theRequestPartitionId);
|
||||
Predicate addPredicateQuantity(String theResourceName, RuntimeSearchParam theSearchParam, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||
return myPredicateBuilderQuantity.addPredicate(theResourceName, theSearchParam, theNextAnd, theOperation, theRequestPartitionId);
|
||||
}
|
||||
|
||||
void addPredicateString(String theResourceName, String theParamName, List<? extends IQueryParameterType> theNextAnd, RequestPartitionId theRequestPartitionId) {
|
||||
myPredicateBuilderString.addPredicate(theResourceName, theParamName, theNextAnd, SearchFilterParser.CompareOperation.sw, theRequestPartitionId);
|
||||
void addPredicateString(String theResourceName, RuntimeSearchParam theSearchParam, List<? extends IQueryParameterType> theNextAnd, RequestPartitionId theRequestPartitionId) {
|
||||
myPredicateBuilderString.addPredicate(theResourceName, theSearchParam, theNextAnd, SearchFilterParser.CompareOperation.sw, theRequestPartitionId);
|
||||
}
|
||||
|
||||
Predicate addPredicateString(String theResourceName, String theParamName, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||
return myPredicateBuilderString.addPredicate(theResourceName, theParamName, theNextAnd, theOperation, theRequestPartitionId);
|
||||
Predicate addPredicateString(String theResourceName,RuntimeSearchParam theSearchParam, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||
return myPredicateBuilderString.addPredicate(theResourceName, theSearchParam, theNextAnd, theOperation, theRequestPartitionId);
|
||||
}
|
||||
|
||||
void addPredicateTag(List<List<IQueryParameterType>> theAndOrParams, String theParamName, RequestPartitionId theRequestPartitionId) {
|
||||
myPredicateBuilderTag.addPredicateTag(theAndOrParams, theParamName, theRequestPartitionId);
|
||||
}
|
||||
|
||||
Predicate addPredicateToken(String theResourceName, String theParamName, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||
return myPredicateBuilderToken.addPredicate(theResourceName, theParamName, theNextAnd, theOperation, theRequestPartitionId);
|
||||
Predicate addPredicateToken(String theResourceName, RuntimeSearchParam theSearchParam, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||
return myPredicateBuilderToken.addPredicate(theResourceName, theSearchParam, theNextAnd, theOperation, theRequestPartitionId);
|
||||
}
|
||||
|
||||
Predicate addPredicateUri(String theResourceName, String theName, List<? extends IQueryParameterType> theSingletonList, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||
return myPredicateBuilderUri.addPredicate(theResourceName, theName, theSingletonList, theOperation, theRequestPartitionId);
|
||||
Predicate addPredicateUri(String theResourceName, RuntimeSearchParam theSearchParam, List<? extends IQueryParameterType> theSingletonList, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||
return myPredicateBuilderUri.addPredicate(theResourceName, theSearchParam, theSingletonList, theOperation, theRequestPartitionId);
|
||||
}
|
||||
|
||||
public void searchForIdsWithAndOr(String theResourceName, String theNextParamName, List<List<IQueryParameterType>> theAndOrParams, RequestDetails theRequest, RequestPartitionId theRequestPartitionId) {
|
||||
|
@ -112,12 +121,12 @@ public class PredicateBuilder {
|
|||
return myPredicateBuilderResourceId.addPredicateResourceId(theValues, theResourceName, theOperation, theRequestPartitionId);
|
||||
}
|
||||
|
||||
Predicate createPredicateString(IQueryParameterType theLeftValue, String theResourceName, String theName, CriteriaBuilder theBuilder, From<ResourceIndexedSearchParamString, ResourceIndexedSearchParamString> theStringJoin, RequestPartitionId theRequestPartitionId) {
|
||||
return myPredicateBuilderString.createPredicateString(theLeftValue, theResourceName, theName, theBuilder, theStringJoin, theRequestPartitionId);
|
||||
Predicate createPredicateString(IQueryParameterType theLeftValue, String theResourceName, RuntimeSearchParam theSearchParam, CriteriaBuilder theBuilder, From<ResourceIndexedSearchParamString, ResourceIndexedSearchParamString> theStringJoin, RequestPartitionId theRequestPartitionId) {
|
||||
return myPredicateBuilderString.createPredicateString(theLeftValue, theResourceName, theSearchParam, theBuilder, theStringJoin, theRequestPartitionId);
|
||||
}
|
||||
|
||||
Collection<Predicate> createPredicateToken(List<IQueryParameterType> theTokens, String theResourceName, String theName, CriteriaBuilder theBuilder, From<ResourceIndexedSearchParamToken, ResourceIndexedSearchParamToken> theTokenJoin, RequestPartitionId theRequestPartitionId) {
|
||||
return myPredicateBuilderToken.createPredicateToken(theTokens, theResourceName, theName, theBuilder, theTokenJoin, theRequestPartitionId);
|
||||
Collection<Predicate> createPredicateToken(List<IQueryParameterType> theTokens, String theResourceName, RuntimeSearchParam theSearchParam, CriteriaBuilder theBuilder, From<ResourceIndexedSearchParamToken, ResourceIndexedSearchParamToken> theTokenJoin, RequestPartitionId theRequestPartitionId) {
|
||||
return myPredicateBuilderToken.createPredicateToken(theTokens, theResourceName, theSearchParam, theBuilder, theTokenJoin, theRequestPartitionId);
|
||||
}
|
||||
|
||||
Predicate createPredicateDate(IQueryParameterType theLeftValue, String theResourceName, String theName, CriteriaBuilder theBuilder, From<ResourceIndexedSearchParamDate, ResourceIndexedSearchParamDate> theDateJoin, RequestPartitionId theRequestPartitionId) {
|
||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.dao.predicate;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords;
|
||||
|
@ -55,7 +56,7 @@ public class PredicateBuilderCoords extends BasePredicateBuilder implements IPre
|
|||
|
||||
private Predicate createPredicateCoords(IQueryParameterType theParam,
|
||||
String theResourceName,
|
||||
String theParamName,
|
||||
RuntimeSearchParam theSearchParam,
|
||||
CriteriaBuilder theBuilder,
|
||||
From<?, ResourceIndexedSearchParamCoords> theFrom,
|
||||
RequestPartitionId theRequestPartitionId) {
|
||||
|
@ -119,7 +120,7 @@ public class PredicateBuilderCoords extends BasePredicateBuilder implements IPre
|
|||
longitudePredicate = longitudePredicateFromBox(theBuilder, theFrom, box);
|
||||
}
|
||||
Predicate singleCode = theBuilder.and(latitudePredicate, longitudePredicate);
|
||||
return combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, singleCode, theRequestPartitionId);
|
||||
return combineParamIndexPredicateWithParamNamePredicate(theResourceName, theSearchParam.getName(), theFrom, singleCode, theRequestPartitionId);
|
||||
}
|
||||
|
||||
private Predicate latitudePredicateFromBox(CriteriaBuilder theBuilder, From<?, ResourceIndexedSearchParamCoords> theFrom, SearchBox theBox) {
|
||||
|
@ -145,14 +146,14 @@ public class PredicateBuilderCoords extends BasePredicateBuilder implements IPre
|
|||
|
||||
@Override
|
||||
public Predicate addPredicate(String theResourceName,
|
||||
String theParamName,
|
||||
RuntimeSearchParam theSearchParam,
|
||||
List<? extends IQueryParameterType> theList,
|
||||
SearchFilterParser.CompareOperation theOperation,
|
||||
RequestPartitionId theRequestPartitionId) {
|
||||
From<?, ResourceIndexedSearchParamCoords> join = myQueryStack.createJoin(SearchBuilderJoinEnum.COORDS, theParamName);
|
||||
From<?, ResourceIndexedSearchParamCoords> join = myQueryStack.createJoin(SearchBuilderJoinEnum.COORDS, theSearchParam.getName());
|
||||
|
||||
if (theList.get(0).getMissing() != null) {
|
||||
addPredicateParamMissingForNonReference(theResourceName, theParamName, theList.get(0).getMissing(), join, theRequestPartitionId);
|
||||
addPredicateParamMissingForNonReference(theResourceName, theSearchParam.getName(), theList.get(0).getMissing(), join, theRequestPartitionId);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -163,7 +164,7 @@ public class PredicateBuilderCoords extends BasePredicateBuilder implements IPre
|
|||
|
||||
Predicate singleCode = createPredicateCoords(nextOr,
|
||||
theResourceName,
|
||||
theParamName,
|
||||
theSearchParam,
|
||||
myCriteriaBuilder,
|
||||
join,
|
||||
theRequestPartitionId);
|
||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.dao.predicate;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
|
@ -56,27 +57,28 @@ public class PredicateBuilderDate extends BasePredicateBuilder implements IPredi
|
|||
|
||||
@Override
|
||||
public Predicate addPredicate(String theResourceName,
|
||||
String theParamName,
|
||||
RuntimeSearchParam theSearchParam,
|
||||
List<? extends IQueryParameterType> theList,
|
||||
SearchFilterParser.CompareOperation operation,
|
||||
RequestPartitionId theRequestPartitionId) {
|
||||
|
||||
String paramName = theSearchParam.getName();
|
||||
boolean newJoin = false;
|
||||
if (myJoinMap == null) {
|
||||
myJoinMap = new HashMap<>();
|
||||
}
|
||||
String key = theResourceName + " " + theParamName;
|
||||
String key = theResourceName + " " + paramName;
|
||||
|
||||
From<?, ResourceIndexedSearchParamDate> join = myJoinMap.get(key);
|
||||
if (join == null) {
|
||||
join = myQueryStack.createJoin(SearchBuilderJoinEnum.DATE, theParamName);
|
||||
join = myQueryStack.createJoin(SearchBuilderJoinEnum.DATE, paramName);
|
||||
myJoinMap.put(key, join);
|
||||
newJoin = true;
|
||||
}
|
||||
|
||||
if (theList.get(0).getMissing() != null) {
|
||||
Boolean missing = theList.get(0).getMissing();
|
||||
addPredicateParamMissingForNonReference(theResourceName, theParamName, missing, join, theRequestPartitionId);
|
||||
addPredicateParamMissingForNonReference(theResourceName, paramName, missing, join, theRequestPartitionId);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -94,7 +96,7 @@ public class PredicateBuilderDate extends BasePredicateBuilder implements IPredi
|
|||
Predicate orPredicates = myCriteriaBuilder.or(toArray(codePredicates));
|
||||
|
||||
if (newJoin) {
|
||||
Predicate identityAndValuePredicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, join, orPredicates, theRequestPartitionId);
|
||||
Predicate identityAndValuePredicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, paramName, join, orPredicates, theRequestPartitionId);
|
||||
myQueryStack.addPredicateWithImplicitTypeSelection(identityAndValuePredicate);
|
||||
} else {
|
||||
myQueryStack.addPredicateWithImplicitTypeSelection(orPredicates);
|
||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.dao.predicate;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
||||
|
@ -51,15 +52,15 @@ class PredicateBuilderNumber extends BasePredicateBuilder implements IPredicateB
|
|||
|
||||
@Override
|
||||
public Predicate addPredicate(String theResourceName,
|
||||
String theParamName,
|
||||
RuntimeSearchParam theSearchParam,
|
||||
List<? extends IQueryParameterType> theList,
|
||||
SearchFilterParser.CompareOperation operation,
|
||||
RequestPartitionId theRequestPartitionId) {
|
||||
|
||||
From<?, ResourceIndexedSearchParamNumber> join = myQueryStack.createJoin(SearchBuilderJoinEnum.NUMBER, theParamName);
|
||||
From<?, ResourceIndexedSearchParamNumber> join = myQueryStack.createJoin(SearchBuilderJoinEnum.NUMBER, theSearchParam.getName());
|
||||
|
||||
if (theList.get(0).getMissing() != null) {
|
||||
addPredicateParamMissingForNonReference(theResourceName, theParamName, theList.get(0).getMissing(), join, theRequestPartitionId);
|
||||
addPredicateParamMissingForNonReference(theResourceName, theSearchParam.getName(), theList.get(0).getMissing(), join, theRequestPartitionId);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -97,8 +98,8 @@ class PredicateBuilderNumber extends BasePredicateBuilder implements IPredicateB
|
|||
|
||||
String invalidMessageName = "invalidNumberPrefix";
|
||||
|
||||
Predicate predicateNumeric = createPredicateNumeric(theResourceName, theParamName, join, myCriteriaBuilder, nextOr, prefix, value, fromObj, invalidMessageName, theRequestPartitionId);
|
||||
Predicate predicateOuter = combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, join, predicateNumeric, theRequestPartitionId);
|
||||
Predicate predicateNumeric = createPredicateNumeric(theResourceName, theSearchParam.getName(), join, myCriteriaBuilder, nextOr, prefix, value, fromObj, invalidMessageName, theRequestPartitionId);
|
||||
Predicate predicateOuter = combineParamIndexPredicateWithParamNamePredicate(theResourceName, theSearchParam.getName(), join, predicateNumeric, theRequestPartitionId);
|
||||
codePredicates.add(predicateOuter);
|
||||
|
||||
} else {
|
||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.dao.predicate;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||
|
@ -52,15 +53,15 @@ class PredicateBuilderQuantity extends BasePredicateBuilder implements IPredicat
|
|||
|
||||
@Override
|
||||
public Predicate addPredicate(String theResourceName,
|
||||
String theParamName,
|
||||
RuntimeSearchParam theSearchParam,
|
||||
List<? extends IQueryParameterType> theList,
|
||||
SearchFilterParser.CompareOperation theOperation,
|
||||
RequestPartitionId theRequestPartitionId) {
|
||||
|
||||
From<?, ResourceIndexedSearchParamQuantity> join = myQueryStack.createJoin(SearchBuilderJoinEnum.QUANTITY, theParamName);
|
||||
From<?, ResourceIndexedSearchParamQuantity> join = myQueryStack.createJoin(SearchBuilderJoinEnum.QUANTITY, theSearchParam.getName());
|
||||
|
||||
if (theList.get(0).getMissing() != null) {
|
||||
addPredicateParamMissingForNonReference(theResourceName, theParamName, theList.get(0).getMissing(), join, theRequestPartitionId);
|
||||
addPredicateParamMissingForNonReference(theResourceName, theSearchParam.getName(), theList.get(0).getMissing(), join, theRequestPartitionId);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -68,7 +69,7 @@ class PredicateBuilderQuantity extends BasePredicateBuilder implements IPredicat
|
|||
addPartitionIdPredicate(theRequestPartitionId, join, codePredicates);
|
||||
|
||||
for (IQueryParameterType nextOr : theList) {
|
||||
Predicate singleCode = createPredicateQuantity(nextOr, theResourceName, theParamName, myCriteriaBuilder, join, theOperation, theRequestPartitionId);
|
||||
Predicate singleCode = createPredicateQuantity(nextOr, theResourceName, theSearchParam.getName(), myCriteriaBuilder, join, theOperation, theRequestPartitionId);
|
||||
codePredicates.add(singleCode);
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,6 @@ import ca.uhn.fhir.rest.api.server.RequestDetails;
|
|||
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
|
||||
import ca.uhn.fhir.rest.param.CompositeParam;
|
||||
import ca.uhn.fhir.rest.param.DateParam;
|
||||
import ca.uhn.fhir.rest.param.HasOrListParam;
|
||||
import ca.uhn.fhir.rest.param.HasParam;
|
||||
import ca.uhn.fhir.rest.param.NumberParam;
|
||||
import ca.uhn.fhir.rest.param.ParameterUtil;
|
||||
|
@ -599,12 +598,12 @@ class PredicateBuilderReference extends BasePredicateBuilder {
|
|||
switch (nextParamDef.getParamType()) {
|
||||
case DATE:
|
||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||
myPredicateBuilder.addPredicateDate(theResourceName, theParamName, nextAnd, null, theRequestPartitionId);
|
||||
myPredicateBuilder.addPredicateDate(theResourceName, nextParamDef, nextAnd, null, theRequestPartitionId);
|
||||
}
|
||||
break;
|
||||
case QUANTITY:
|
||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||
myPredicateBuilder.addPredicateQuantity(theResourceName, theParamName, nextAnd, null, theRequestPartitionId);
|
||||
myPredicateBuilder.addPredicateQuantity(theResourceName, nextParamDef, nextAnd, null, theRequestPartitionId);
|
||||
}
|
||||
break;
|
||||
case REFERENCE:
|
||||
|
@ -614,21 +613,21 @@ class PredicateBuilderReference extends BasePredicateBuilder {
|
|||
break;
|
||||
case STRING:
|
||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||
myPredicateBuilder.addPredicateString(theResourceName, theParamName, nextAnd, SearchFilterParser.CompareOperation.sw, theRequestPartitionId);
|
||||
myPredicateBuilder.addPredicateString(theResourceName, nextParamDef, nextAnd, SearchFilterParser.CompareOperation.sw, theRequestPartitionId);
|
||||
}
|
||||
break;
|
||||
case TOKEN:
|
||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||
if ("Location.position".equals(nextParamDef.getPath())) {
|
||||
myPredicateBuilder.addPredicateCoords(theResourceName, theParamName, nextAnd, theRequestPartitionId);
|
||||
myPredicateBuilder.addPredicateCoords(theResourceName, nextParamDef, nextAnd, theRequestPartitionId);
|
||||
} else {
|
||||
myPredicateBuilder.addPredicateToken(theResourceName, theParamName, nextAnd, null, theRequestPartitionId);
|
||||
myPredicateBuilder.addPredicateToken(theResourceName, nextParamDef, nextAnd, null, theRequestPartitionId);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NUMBER:
|
||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||
myPredicateBuilder.addPredicateNumber(theResourceName, theParamName, nextAnd, null, theRequestPartitionId);
|
||||
myPredicateBuilder.addPredicateNumber(theResourceName, nextParamDef, nextAnd, null, theRequestPartitionId);
|
||||
}
|
||||
break;
|
||||
case COMPOSITE:
|
||||
|
@ -638,14 +637,14 @@ class PredicateBuilderReference extends BasePredicateBuilder {
|
|||
break;
|
||||
case URI:
|
||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||
myPredicateBuilder.addPredicateUri(theResourceName, theParamName, nextAnd, SearchFilterParser.CompareOperation.eq, theRequestPartitionId);
|
||||
myPredicateBuilder.addPredicateUri(theResourceName, nextParamDef, nextAnd, SearchFilterParser.CompareOperation.eq, theRequestPartitionId);
|
||||
}
|
||||
break;
|
||||
case HAS:
|
||||
case SPECIAL:
|
||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||
if ("Location.position".equals(nextParamDef.getPath())) {
|
||||
myPredicateBuilder.addPredicateCoords(theResourceName, theParamName, nextAnd, theRequestPartitionId);
|
||||
myPredicateBuilder.addPredicateCoords(theResourceName, nextParamDef, nextAnd, theRequestPartitionId);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -755,13 +754,13 @@ class PredicateBuilderReference extends BasePredicateBuilder {
|
|||
} else {
|
||||
RestSearchParameterTypeEnum typeEnum = searchParam.getParamType();
|
||||
if (typeEnum == RestSearchParameterTypeEnum.URI) {
|
||||
return myPredicateBuilder.addPredicateUri(theResourceName, theFilter.getParamPath().getName(), Collections.singletonList(new UriParam(theFilter.getValue())), theFilter.getOperation(), theRequestPartitionId);
|
||||
return myPredicateBuilder.addPredicateUri(theResourceName, searchParam, Collections.singletonList(new UriParam(theFilter.getValue())), theFilter.getOperation(), theRequestPartitionId);
|
||||
} else if (typeEnum == RestSearchParameterTypeEnum.STRING) {
|
||||
return myPredicateBuilder.addPredicateString(theResourceName, theFilter.getParamPath().getName(), Collections.singletonList(new StringParam(theFilter.getValue())), theFilter.getOperation(), theRequestPartitionId);
|
||||
return myPredicateBuilder.addPredicateString(theResourceName, searchParam, Collections.singletonList(new StringParam(theFilter.getValue())), theFilter.getOperation(), theRequestPartitionId);
|
||||
} else if (typeEnum == RestSearchParameterTypeEnum.DATE) {
|
||||
return myPredicateBuilder.addPredicateDate(theResourceName, theFilter.getParamPath().getName(), Collections.singletonList(new DateParam(theFilter.getValue())), theFilter.getOperation(), theRequestPartitionId);
|
||||
return myPredicateBuilder.addPredicateDate(theResourceName, searchParam, Collections.singletonList(new DateParam(theFilter.getValue())), theFilter.getOperation(), theRequestPartitionId);
|
||||
} else if (typeEnum == RestSearchParameterTypeEnum.NUMBER) {
|
||||
return myPredicateBuilder.addPredicateNumber(theResourceName, theFilter.getParamPath().getName(), Collections.singletonList(new NumberParam(theFilter.getValue())), theFilter.getOperation(), theRequestPartitionId);
|
||||
return myPredicateBuilder.addPredicateNumber(theResourceName, searchParam, Collections.singletonList(new NumberParam(theFilter.getValue())), theFilter.getOperation(), theRequestPartitionId);
|
||||
} else if (typeEnum == RestSearchParameterTypeEnum.REFERENCE) {
|
||||
String paramName = theFilter.getParamPath().getName();
|
||||
SearchFilterParser.CompareOperation operation = theFilter.getOperation();
|
||||
|
@ -771,7 +770,7 @@ class PredicateBuilderReference extends BasePredicateBuilder {
|
|||
ReferenceParam referenceParam = new ReferenceParam(resourceType, chain, value);
|
||||
return addPredicate(theResourceName, paramName, Collections.singletonList(referenceParam), operation, theRequest, theRequestPartitionId);
|
||||
} else if (typeEnum == RestSearchParameterTypeEnum.QUANTITY) {
|
||||
return myPredicateBuilder.addPredicateQuantity(theResourceName, theFilter.getParamPath().getName(), Collections.singletonList(new QuantityParam(theFilter.getValue())), theFilter.getOperation(), theRequestPartitionId);
|
||||
return myPredicateBuilder.addPredicateQuantity(theResourceName, searchParam, Collections.singletonList(new QuantityParam(theFilter.getValue())), theFilter.getOperation(), theRequestPartitionId);
|
||||
} else if (typeEnum == RestSearchParameterTypeEnum.COMPOSITE) {
|
||||
throw new InvalidRequestException("Composite search parameters not currently supported with _filter clauses");
|
||||
} else if (typeEnum == RestSearchParameterTypeEnum.TOKEN) {
|
||||
|
@ -780,7 +779,7 @@ class PredicateBuilderReference extends BasePredicateBuilder {
|
|||
null,
|
||||
null,
|
||||
theFilter.getValue());
|
||||
return myPredicateBuilder.addPredicateToken(theResourceName, theFilter.getParamPath().getName(), Collections.singletonList(param), theFilter.getOperation(), theRequestPartitionId);
|
||||
return myPredicateBuilder.addPredicateToken(theResourceName, searchParam, Collections.singletonList(param), theFilter.getOperation(), theRequestPartitionId);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -1033,13 +1032,13 @@ class PredicateBuilderReference extends BasePredicateBuilder {
|
|||
switch (theParam.getParamType()) {
|
||||
case STRING: {
|
||||
From<ResourceIndexedSearchParamString, ResourceIndexedSearchParamString> stringJoin = theRoot.join("myParamsString", JoinType.INNER);
|
||||
retVal = myPredicateBuilder.createPredicateString(leftValue, theResourceName, theParam.getName(), myCriteriaBuilder, stringJoin, theRequestPartitionId);
|
||||
retVal = myPredicateBuilder.createPredicateString(leftValue, theResourceName, theParam, myCriteriaBuilder, stringJoin, theRequestPartitionId);
|
||||
break;
|
||||
}
|
||||
case TOKEN: {
|
||||
From<ResourceIndexedSearchParamToken, ResourceIndexedSearchParamToken> tokenJoin = theRoot.join("myParamsToken", JoinType.INNER);
|
||||
List<IQueryParameterType> tokens = Collections.singletonList(leftValue);
|
||||
Collection<Predicate> tokenPredicates = myPredicateBuilder.createPredicateToken(tokens, theResourceName, theParam.getName(), myCriteriaBuilder, tokenJoin, theRequestPartitionId);
|
||||
Collection<Predicate> tokenPredicates = myPredicateBuilder.createPredicateToken(tokens, theResourceName, theParam, myCriteriaBuilder, tokenJoin, theRequestPartitionId);
|
||||
retVal = myCriteriaBuilder.and(tokenPredicates.toArray(new Predicate[0]));
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -20,8 +20,8 @@ package ca.uhn.fhir.jpa.dao.predicate;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
||||
|
@ -31,7 +31,6 @@ import ca.uhn.fhir.rest.param.TokenParam;
|
|||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
||||
import ca.uhn.fhir.util.StringUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
@ -44,25 +43,21 @@ import java.util.List;
|
|||
@Component
|
||||
@Scope("prototype")
|
||||
class PredicateBuilderString extends BasePredicateBuilder implements IPredicateBuilder {
|
||||
|
||||
@Autowired
|
||||
DaoConfig myDaoConfig;
|
||||
|
||||
PredicateBuilderString(SearchBuilder theSearchBuilder) {
|
||||
super(theSearchBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate addPredicate(String theResourceName,
|
||||
String theParamName,
|
||||
RuntimeSearchParam theSearchParam,
|
||||
List<? extends IQueryParameterType> theList,
|
||||
SearchFilterParser.CompareOperation theOperation,
|
||||
RequestPartitionId theRequestPartitionId) {
|
||||
|
||||
From<?, ResourceIndexedSearchParamString> join = myQueryStack.createJoin(SearchBuilderJoinEnum.STRING, theParamName);
|
||||
From<?, ResourceIndexedSearchParamString> join = myQueryStack.createJoin(SearchBuilderJoinEnum.STRING, theSearchParam.getName());
|
||||
|
||||
if (theList.get(0).getMissing() != null) {
|
||||
addPredicateParamMissingForNonReference(theResourceName, theParamName, theList.get(0).getMissing(), join, theRequestPartitionId);
|
||||
addPredicateParamMissingForNonReference(theResourceName, theSearchParam.getName(), theList.get(0).getMissing(), join, theRequestPartitionId);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -70,7 +65,7 @@ class PredicateBuilderString extends BasePredicateBuilder implements IPredicateB
|
|||
addPartitionIdPredicate(theRequestPartitionId, join, codePredicates);
|
||||
|
||||
for (IQueryParameterType nextOr : theList) {
|
||||
Predicate singleCode = createPredicateString(nextOr, theResourceName, theParamName, myCriteriaBuilder, join, theOperation, theRequestPartitionId);
|
||||
Predicate singleCode = createPredicateString(nextOr, theResourceName, theSearchParam, myCriteriaBuilder, join, theOperation, theRequestPartitionId);
|
||||
codePredicates.add(singleCode);
|
||||
}
|
||||
|
||||
|
@ -83,13 +78,13 @@ class PredicateBuilderString extends BasePredicateBuilder implements IPredicateB
|
|||
|
||||
public Predicate createPredicateString(IQueryParameterType theParameter,
|
||||
String theResourceName,
|
||||
String theParamName,
|
||||
RuntimeSearchParam theSearchParam,
|
||||
CriteriaBuilder theBuilder,
|
||||
From<?, ResourceIndexedSearchParamString> theFrom,
|
||||
RequestPartitionId theRequestPartitionId) {
|
||||
return createPredicateString(theParameter,
|
||||
theResourceName,
|
||||
theParamName,
|
||||
theSearchParam,
|
||||
theBuilder,
|
||||
theFrom,
|
||||
null,
|
||||
|
@ -98,12 +93,13 @@ class PredicateBuilderString extends BasePredicateBuilder implements IPredicateB
|
|||
|
||||
private Predicate createPredicateString(IQueryParameterType theParameter,
|
||||
String theResourceName,
|
||||
String theParamName,
|
||||
RuntimeSearchParam theSearchParam,
|
||||
CriteriaBuilder theBuilder,
|
||||
From<?, ResourceIndexedSearchParamString> theFrom,
|
||||
SearchFilterParser.CompareOperation operation,
|
||||
RequestPartitionId theRequestPartitionId) {
|
||||
String rawSearchTerm;
|
||||
String paramName = theSearchParam.getName();
|
||||
if (theParameter instanceof TokenParam) {
|
||||
TokenParam id = (TokenParam) theParameter;
|
||||
if (!id.isText()) {
|
||||
|
@ -117,6 +113,8 @@ class PredicateBuilderString extends BasePredicateBuilder implements IPredicateB
|
|||
if (!myDaoConfig.isAllowContainsSearches()) {
|
||||
throw new MethodNotAllowedException(":contains modifier is disabled on this server");
|
||||
}
|
||||
} else {
|
||||
rawSearchTerm = theSearchParam.encode(rawSearchTerm);
|
||||
}
|
||||
} else if (theParameter instanceof IPrimitiveDatatype<?>) {
|
||||
IPrimitiveDatatype<?> id = (IPrimitiveDatatype<?>) theParameter;
|
||||
|
@ -126,7 +124,7 @@ class PredicateBuilderString extends BasePredicateBuilder implements IPredicateB
|
|||
}
|
||||
|
||||
if (rawSearchTerm.length() > ResourceIndexedSearchParamString.MAX_LENGTH) {
|
||||
throw new InvalidRequestException("Parameter[" + theParamName + "] has length (" + rawSearchTerm.length() + ") that is longer than maximum allowed ("
|
||||
throw new InvalidRequestException("Parameter[" + paramName + "] has length (" + rawSearchTerm.length() + ") that is longer than maximum allowed ("
|
||||
+ ResourceIndexedSearchParamString.MAX_LENGTH + "): " + rawSearchTerm);
|
||||
}
|
||||
|
||||
|
@ -152,12 +150,12 @@ class PredicateBuilderString extends BasePredicateBuilder implements IPredicateB
|
|||
singleCode = theBuilder.and(singleCode, exactCode);
|
||||
}
|
||||
|
||||
return combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, singleCode, theRequestPartitionId);
|
||||
return combineParamIndexPredicateWithParamNamePredicate(theResourceName, paramName, theFrom, singleCode, theRequestPartitionId);
|
||||
}
|
||||
boolean exactMatch = theParameter instanceof StringParam && ((StringParam) theParameter).isExact();
|
||||
if (exactMatch) {
|
||||
// Exact match
|
||||
Long hash = ResourceIndexedSearchParamString.calculateHashExact(getPartitionSettings(), theRequestPartitionId, theResourceName, theParamName, rawSearchTerm);
|
||||
Long hash = ResourceIndexedSearchParamString.calculateHashExact(getPartitionSettings(), theRequestPartitionId, theResourceName, paramName, rawSearchTerm);
|
||||
return theBuilder.equal(theFrom.get("myHashExact").as(Long.class), hash);
|
||||
} else {
|
||||
// Normalized Match
|
||||
|
@ -185,34 +183,34 @@ class PredicateBuilderString extends BasePredicateBuilder implements IPredicateB
|
|||
Predicate predicate;
|
||||
if ((operation == null) ||
|
||||
(operation == SearchFilterParser.CompareOperation.sw)) {
|
||||
Long hash = ResourceIndexedSearchParamString.calculateHashNormalized(getPartitionSettings(), theRequestPartitionId, myDaoConfig.getModelConfig(), theResourceName, theParamName, normalizedString);
|
||||
Long hash = ResourceIndexedSearchParamString.calculateHashNormalized(getPartitionSettings(), theRequestPartitionId, myDaoConfig.getModelConfig(), theResourceName, paramName, normalizedString);
|
||||
Predicate hashCode = theBuilder.equal(theFrom.get("myHashNormalizedPrefix").as(Long.class), hash);
|
||||
Predicate singleCode = theBuilder.like(theFrom.get("myValueNormalized").as(String.class), likeExpression);
|
||||
predicate = theBuilder.and(hashCode, singleCode);
|
||||
} else if ((operation == SearchFilterParser.CompareOperation.ew) ||
|
||||
(operation == SearchFilterParser.CompareOperation.co)) {
|
||||
Predicate singleCode = theBuilder.like(theFrom.get("myValueNormalized").as(String.class), likeExpression);
|
||||
predicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, singleCode, theRequestPartitionId);
|
||||
predicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, paramName, theFrom, singleCode, theRequestPartitionId);
|
||||
} else if (operation == SearchFilterParser.CompareOperation.eq) {
|
||||
Long hash = ResourceIndexedSearchParamString.calculateHashNormalized(getPartitionSettings(), theRequestPartitionId, myDaoConfig.getModelConfig(), theResourceName, theParamName, normalizedString);
|
||||
Long hash = ResourceIndexedSearchParamString.calculateHashNormalized(getPartitionSettings(), theRequestPartitionId, myDaoConfig.getModelConfig(), theResourceName, paramName, normalizedString);
|
||||
Predicate hashCode = theBuilder.equal(theFrom.get("myHashNormalizedPrefix").as(Long.class), hash);
|
||||
Predicate singleCode = theBuilder.like(theFrom.get("myValueNormalized").as(String.class), normalizedString);
|
||||
predicate = theBuilder.and(hashCode, singleCode);
|
||||
} else if (operation == SearchFilterParser.CompareOperation.ne) {
|
||||
Predicate singleCode = theBuilder.notEqual(theFrom.get("myValueNormalized").as(String.class), likeExpression);
|
||||
predicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, singleCode, theRequestPartitionId);
|
||||
predicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, paramName, theFrom, singleCode, theRequestPartitionId);
|
||||
} else if (operation == SearchFilterParser.CompareOperation.gt) {
|
||||
Predicate singleCode = theBuilder.greaterThan(theFrom.get("myValueNormalized").as(String.class), likeExpression);
|
||||
predicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, singleCode, theRequestPartitionId);
|
||||
predicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, paramName, theFrom, singleCode, theRequestPartitionId);
|
||||
} else if (operation == SearchFilterParser.CompareOperation.lt) {
|
||||
Predicate singleCode = theBuilder.lessThan(theFrom.get("myValueNormalized").as(String.class), likeExpression);
|
||||
predicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, singleCode, theRequestPartitionId);
|
||||
predicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, paramName, theFrom, singleCode, theRequestPartitionId);
|
||||
} else if (operation == SearchFilterParser.CompareOperation.ge) {
|
||||
Predicate singleCode = theBuilder.greaterThanOrEqualTo(theFrom.get("myValueNormalized").as(String.class), likeExpression);
|
||||
predicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, singleCode, theRequestPartitionId);
|
||||
predicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, paramName, theFrom, singleCode, theRequestPartitionId);
|
||||
} else if (operation == SearchFilterParser.CompareOperation.le) {
|
||||
Predicate singleCode = theBuilder.lessThanOrEqualTo(theFrom.get("myValueNormalized").as(String.class), likeExpression);
|
||||
predicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, singleCode, theRequestPartitionId);
|
||||
predicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, paramName, theFrom, singleCode, theRequestPartitionId);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Don't yet know how to handle operation " + operation + " on a string");
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ package ca.uhn.fhir.jpa.dao.predicate;
|
|||
|
||||
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
||||
import ca.uhn.fhir.context.BaseRuntimeDeclaredChildDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
|
@ -31,7 +30,6 @@ import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
|||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.BaseSearchParamExtractor;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.term.api.ITermReadSvc;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
||||
|
@ -72,8 +70,6 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
|||
@Autowired
|
||||
private ITermReadSvc myTerminologySvc;
|
||||
@Autowired
|
||||
private ISearchParamRegistry mySearchParamRegistry;
|
||||
@Autowired
|
||||
private ModelConfig myModelConfig;
|
||||
|
||||
PredicateBuilderToken(SearchBuilder theSearchBuilder, PredicateBuilder thePredicateBuilder) {
|
||||
|
@ -83,14 +79,14 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
|||
|
||||
@Override
|
||||
public Predicate addPredicate(String theResourceName,
|
||||
String theParamName,
|
||||
RuntimeSearchParam theSearchParam,
|
||||
List<? extends IQueryParameterType> theList,
|
||||
SearchFilterParser.CompareOperation theOperation,
|
||||
RequestPartitionId theRequestPartitionId) {
|
||||
|
||||
if (theList.get(0).getMissing() != null) {
|
||||
From<?, ResourceIndexedSearchParamToken> join = myQueryStack.createJoin(SearchBuilderJoinEnum.TOKEN, theParamName);
|
||||
addPredicateParamMissingForNonReference(theResourceName, theParamName, theList.get(0).getMissing(), join, theRequestPartitionId);
|
||||
From<?, ResourceIndexedSearchParamToken> join = myQueryStack.createJoin(SearchBuilderJoinEnum.TOKEN, theSearchParam.getName());
|
||||
addPredicateParamMissingForNonReference(theResourceName, theSearchParam.getName(), theList.get(0).getMissing(), join, theRequestPartitionId);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -104,8 +100,7 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
|||
if (id.isText()) {
|
||||
|
||||
// Check whether the :text modifier is actually enabled here
|
||||
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam(theResourceName, theParamName);
|
||||
boolean tokenTextIndexingEnabled = BaseSearchParamExtractor.tokenTextIndexingEnabledForSearchParam(myModelConfig, param);
|
||||
boolean tokenTextIndexingEnabled = BaseSearchParamExtractor.tokenTextIndexingEnabledForSearchParam(myModelConfig, theSearchParam);
|
||||
if (!tokenTextIndexingEnabled) {
|
||||
String msg;
|
||||
if (myModelConfig.isSuppressStringIndexingInTokens()) {
|
||||
|
@ -116,7 +111,7 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
|||
throw new MethodNotAllowedException(msg);
|
||||
}
|
||||
|
||||
myPredicateBuilder.addPredicateString(theResourceName, theParamName, theList, theRequestPartitionId);
|
||||
myPredicateBuilder.addPredicateString(theResourceName, theSearchParam, theList, theRequestPartitionId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -128,10 +123,10 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
|||
return null;
|
||||
}
|
||||
|
||||
From<?, ResourceIndexedSearchParamToken> join = myQueryStack.createJoin(SearchBuilderJoinEnum.TOKEN, theParamName);
|
||||
From<?, ResourceIndexedSearchParamToken> join = myQueryStack.createJoin(SearchBuilderJoinEnum.TOKEN, theSearchParam.getName());
|
||||
addPartitionIdPredicate(theRequestPartitionId, join, codePredicates);
|
||||
|
||||
Collection<Predicate> singleCode = createPredicateToken(tokens, theResourceName, theParamName, myCriteriaBuilder, join, theOperation, theRequestPartitionId);
|
||||
Collection<Predicate> singleCode = createPredicateToken(tokens, theResourceName, theSearchParam, myCriteriaBuilder, join, theOperation, theRequestPartitionId);
|
||||
assert singleCode != null;
|
||||
codePredicates.addAll(singleCode);
|
||||
|
||||
|
@ -144,14 +139,14 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
|||
|
||||
public Collection<Predicate> createPredicateToken(Collection<IQueryParameterType> theParameters,
|
||||
String theResourceName,
|
||||
String theParamName,
|
||||
RuntimeSearchParam theSearchParam,
|
||||
CriteriaBuilder theBuilder,
|
||||
From<?, ResourceIndexedSearchParamToken> theFrom,
|
||||
RequestPartitionId theRequestPartitionId) {
|
||||
return createPredicateToken(
|
||||
theParameters,
|
||||
theResourceName,
|
||||
theParamName,
|
||||
theSearchParam,
|
||||
theBuilder,
|
||||
theFrom,
|
||||
null,
|
||||
|
@ -160,12 +155,13 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
|||
|
||||
private Collection<Predicate> createPredicateToken(Collection<IQueryParameterType> theParameters,
|
||||
String theResourceName,
|
||||
String theParamName,
|
||||
RuntimeSearchParam theSearchParam,
|
||||
CriteriaBuilder theBuilder,
|
||||
From<?, ResourceIndexedSearchParamToken> theFrom,
|
||||
SearchFilterParser.CompareOperation operation,
|
||||
RequestPartitionId theRequestPartitionId) {
|
||||
final List<VersionIndependentConcept> codes = new ArrayList<>();
|
||||
String paramName = theSearchParam.getName();
|
||||
|
||||
TokenParamModifier modifier = null;
|
||||
for (IQueryParameterType nextParameter : theParameters) {
|
||||
|
@ -195,12 +191,12 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
|||
|
||||
if (system != null && system.length() > ResourceIndexedSearchParamToken.MAX_LENGTH) {
|
||||
throw new InvalidRequestException(
|
||||
"Parameter[" + theParamName + "] has system (" + system.length() + ") that is longer than maximum allowed (" + ResourceIndexedSearchParamToken.MAX_LENGTH + "): " + system);
|
||||
"Parameter[" + paramName + "] has system (" + system.length() + ") that is longer than maximum allowed (" + ResourceIndexedSearchParamToken.MAX_LENGTH + "): " + system);
|
||||
}
|
||||
|
||||
if (code != null && code.length() > ResourceIndexedSearchParamToken.MAX_LENGTH) {
|
||||
throw new InvalidRequestException(
|
||||
"Parameter[" + theParamName + "] has code (" + code.length() + ") that is longer than maximum allowed (" + ResourceIndexedSearchParamToken.MAX_LENGTH + "): " + code);
|
||||
"Parameter[" + paramName + "] has code (" + code.length() + ") that is longer than maximum allowed (" + ResourceIndexedSearchParamToken.MAX_LENGTH + "): " + code);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -210,12 +206,12 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
|||
if (modifier == TokenParamModifier.IN) {
|
||||
codes.addAll(myTerminologySvc.expandValueSet(null, code));
|
||||
} else if (modifier == TokenParamModifier.ABOVE) {
|
||||
system = determineSystemIfMissing(theParamName, code, system);
|
||||
validateHaveSystemAndCodeForToken(theParamName, code, system);
|
||||
system = determineSystemIfMissing(theSearchParam, code, system);
|
||||
validateHaveSystemAndCodeForToken(paramName, code, system);
|
||||
codes.addAll(myTerminologySvc.findCodesAbove(system, code));
|
||||
} else if (modifier == TokenParamModifier.BELOW) {
|
||||
system = determineSystemIfMissing(theParamName, code, system);
|
||||
validateHaveSystemAndCodeForToken(theParamName, code, system);
|
||||
system = determineSystemIfMissing(theSearchParam, code, system);
|
||||
validateHaveSystemAndCodeForToken(paramName, code, system);
|
||||
codes.addAll(myTerminologySvc.findCodesBelow(system, code));
|
||||
} else {
|
||||
codes.add(new VersionIndependentConcept(system, code));
|
||||
|
@ -240,32 +236,30 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
|||
// System only
|
||||
List<VersionIndependentConcept> systemOnlyCodes = sortedCodesList.stream().filter(t -> isBlank(t.getCode())).collect(Collectors.toList());
|
||||
if (!systemOnlyCodes.isEmpty()) {
|
||||
retVal.add(addPredicate(theResourceName, theParamName, theBuilder, theFrom, systemOnlyCodes, modifier, SearchBuilderTokenModeEnum.SYSTEM_ONLY, theRequestPartitionId));
|
||||
retVal.add(addPredicate(theResourceName, paramName, theBuilder, theFrom, systemOnlyCodes, modifier, SearchBuilderTokenModeEnum.SYSTEM_ONLY, theRequestPartitionId));
|
||||
}
|
||||
|
||||
// Code only
|
||||
List<VersionIndependentConcept> codeOnlyCodes = sortedCodesList.stream().filter(t -> t.getSystem() == null).collect(Collectors.toList());
|
||||
if (!codeOnlyCodes.isEmpty()) {
|
||||
retVal.add(addPredicate(theResourceName, theParamName, theBuilder, theFrom, codeOnlyCodes, modifier, SearchBuilderTokenModeEnum.VALUE_ONLY, theRequestPartitionId));
|
||||
retVal.add(addPredicate(theResourceName, paramName, theBuilder, theFrom, codeOnlyCodes, modifier, SearchBuilderTokenModeEnum.VALUE_ONLY, theRequestPartitionId));
|
||||
}
|
||||
|
||||
// System and code
|
||||
List<VersionIndependentConcept> systemAndCodeCodes = sortedCodesList.stream().filter(t -> isNotBlank(t.getCode()) && t.getSystem() != null).collect(Collectors.toList());
|
||||
if (!systemAndCodeCodes.isEmpty()) {
|
||||
retVal.add(addPredicate(theResourceName, theParamName, theBuilder, theFrom, systemAndCodeCodes, modifier, SearchBuilderTokenModeEnum.SYSTEM_AND_VALUE, theRequestPartitionId));
|
||||
retVal.add(addPredicate(theResourceName, paramName, theBuilder, theFrom, systemAndCodeCodes, modifier, SearchBuilderTokenModeEnum.SYSTEM_AND_VALUE, theRequestPartitionId));
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private String determineSystemIfMissing(String theParamName, String code, String theSystem) {
|
||||
private String determineSystemIfMissing(RuntimeSearchParam theSearchParam, String code, String theSystem) {
|
||||
String retVal = theSystem;
|
||||
if (retVal == null) {
|
||||
RuntimeResourceDefinition resourceDef = myContext.getResourceDefinition(myResourceName);
|
||||
RuntimeSearchParam param = mySearchParamRegistry.getSearchParamByName(resourceDef, theParamName);
|
||||
if (param != null) {
|
||||
if (theSearchParam != null) {
|
||||
Set<String> valueSetUris = Sets.newHashSet();
|
||||
for (String nextPath : param.getPathsSplit()) {
|
||||
for (String nextPath : theSearchParam.getPathsSplit()) {
|
||||
BaseRuntimeChildDefinition def = myContext.newTerser().getDefinition(myResourceType, nextPath);
|
||||
if (def instanceof BaseRuntimeDeclaredChildDefinition) {
|
||||
String valueSet = ((BaseRuntimeDeclaredChildDefinition) def).getBindingValueSet();
|
||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.dao.predicate;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao;
|
||||
|
@ -53,15 +54,16 @@ class PredicateBuilderUri extends BasePredicateBuilder implements IPredicateBuil
|
|||
|
||||
@Override
|
||||
public Predicate addPredicate(String theResourceName,
|
||||
String theParamName,
|
||||
RuntimeSearchParam theSearchParam,
|
||||
List<? extends IQueryParameterType> theList,
|
||||
SearchFilterParser.CompareOperation operation,
|
||||
RequestPartitionId theRequestPartitionId) {
|
||||
|
||||
From<?, ResourceIndexedSearchParamUri> join = myQueryStack.createJoin(SearchBuilderJoinEnum.URI, theParamName);
|
||||
String paramName = theSearchParam.getName();
|
||||
From<?, ResourceIndexedSearchParamUri> join = myQueryStack.createJoin(SearchBuilderJoinEnum.URI, paramName);
|
||||
|
||||
if (theList.get(0).getMissing() != null) {
|
||||
addPredicateParamMissingForNonReference(theResourceName, theParamName, theList.get(0).getMissing(), join, theRequestPartitionId);
|
||||
addPredicateParamMissingForNonReference(theResourceName, paramName, theList.get(0).getMissing(), join, theRequestPartitionId);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -91,8 +93,8 @@ class PredicateBuilderUri extends BasePredicateBuilder implements IPredicateBuil
|
|||
*
|
||||
* If we ever need to make this more efficient, lucene could certainly be used as an optimization.
|
||||
*/
|
||||
ourLog.info("Searching for candidate URI:above parameters for Resource[{}] param[{}]", myResourceName, theParamName);
|
||||
Collection<String> candidates = myResourceIndexedSearchParamUriDao.findAllByResourceTypeAndParamName(myResourceName, theParamName);
|
||||
ourLog.info("Searching for candidate URI:above parameters for Resource[{}] param[{}]", myResourceName, paramName);
|
||||
Collection<String> candidates = myResourceIndexedSearchParamUriDao.findAllByResourceTypeAndParamName(myResourceName, paramName);
|
||||
List<String> toFind = new ArrayList<>();
|
||||
for (String next : candidates) {
|
||||
if (value.length() >= next.length()) {
|
||||
|
@ -107,13 +109,13 @@ class PredicateBuilderUri extends BasePredicateBuilder implements IPredicateBuil
|
|||
}
|
||||
|
||||
Predicate uriPredicate = join.get("myUri").as(String.class).in(toFind);
|
||||
Predicate hashAndUriPredicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, join, uriPredicate, theRequestPartitionId);
|
||||
Predicate hashAndUriPredicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, paramName, join, uriPredicate, theRequestPartitionId);
|
||||
codePredicates.add(hashAndUriPredicate);
|
||||
|
||||
} else if (param.getQualifier() == UriParamQualifierEnum.BELOW) {
|
||||
|
||||
Predicate uriPredicate = myCriteriaBuilder.like(join.get("myUri").as(String.class), createLeftMatchLikeExpression(value));
|
||||
Predicate hashAndUriPredicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, join, uriPredicate, theRequestPartitionId);
|
||||
Predicate hashAndUriPredicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, paramName, join, uriPredicate, theRequestPartitionId);
|
||||
codePredicates.add(hashAndUriPredicate);
|
||||
|
||||
} else {
|
||||
|
@ -124,7 +126,7 @@ class PredicateBuilderUri extends BasePredicateBuilder implements IPredicateBuil
|
|||
|
||||
Predicate uriPredicate = null;
|
||||
if (operation == null || operation == SearchFilterParser.CompareOperation.eq) {
|
||||
long hashUri = ResourceIndexedSearchParamUri.calculateHashUri(getPartitionSettings(), theRequestPartitionId, theResourceName, theParamName, value);
|
||||
long hashUri = ResourceIndexedSearchParamUri.calculateHashUri(getPartitionSettings(), theRequestPartitionId, theResourceName, paramName, value);
|
||||
Predicate hashPredicate = myCriteriaBuilder.equal(join.get("myHashUri"), hashUri);
|
||||
codePredicates.add(hashPredicate);
|
||||
} else if (operation == SearchFilterParser.CompareOperation.ne) {
|
||||
|
@ -149,7 +151,7 @@ class PredicateBuilderUri extends BasePredicateBuilder implements IPredicateBuil
|
|||
}
|
||||
|
||||
if (uriPredicate != null) {
|
||||
long hashIdentity = BaseResourceIndexedSearchParam.calculateHashIdentity(getPartitionSettings(), theRequestPartitionId, theResourceName, theParamName);
|
||||
long hashIdentity = BaseResourceIndexedSearchParam.calculateHashIdentity(getPartitionSettings(), theRequestPartitionId, theResourceName, paramName);
|
||||
Predicate hashIdentityPredicate = myCriteriaBuilder.equal(join.get("myHashIdentity"), hashIdentity);
|
||||
codePredicates.add(myCriteriaBuilder.and(hashIdentityPredicate, uriPredicate));
|
||||
}
|
||||
|
@ -175,7 +177,7 @@ class PredicateBuilderUri extends BasePredicateBuilder implements IPredicateBuil
|
|||
Predicate orPredicate = myCriteriaBuilder.or(toArray(codePredicates));
|
||||
|
||||
Predicate outerPredicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName,
|
||||
theParamName,
|
||||
paramName,
|
||||
join,
|
||||
orPredicate,
|
||||
theRequestPartitionId);
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
package ca.uhn.fhir.jpa.dao.dstu3;
|
||||
|
||||
import ca.uhn.fhir.context.phonetic.ApacheEncoder;
|
||||
import ca.uhn.fhir.context.phonetic.PhoneticEncoderEnum;
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import org.apache.commons.codec.language.Soundex;
|
||||
import org.hl7.fhir.dstu3.model.Enumerations;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.dstu3.model.SearchParameter;
|
||||
import org.hl7.fhir.dstu3.model.StringType;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class FhirResourceDaoDstu3PhoneticSearchNoFtTest extends BaseJpaDstu3Test {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3PhoneticSearchNoFtTest.class);
|
||||
public static final String GALE = "Gale";
|
||||
public static final String GAIL = "Gail";
|
||||
public static final String NAME_SOUNDEX_SP = "nameSoundex";
|
||||
public static final String ADDRESS_LINE_SOUNDEX_SP = "addressLineSoundex";
|
||||
private static final String BOB = "BOB";
|
||||
private static final String ADDRESS = "123 Nohili St";
|
||||
private static final String ADDRESS_CLOSE = "123 Nohily St";
|
||||
private static final String ADDRESS_FAR = "123 College St";
|
||||
|
||||
@Autowired
|
||||
ISearchParamRegistry mySearchParamRegistry;
|
||||
|
||||
@Before
|
||||
public void beforeDisableResultReuse() {
|
||||
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.DISABLED);
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
|
||||
myDaoConfig.setFetchSizeDefaultMaximum(new DaoConfig().getFetchSizeDefaultMaximum());
|
||||
|
||||
createSoundexSearchParameter(NAME_SOUNDEX_SP, PhoneticEncoderEnum.SOUNDEX, "Patient.name");
|
||||
createSoundexSearchParameter(ADDRESS_LINE_SOUNDEX_SP, PhoneticEncoderEnum.SOUNDEX, "Patient.address.line");
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
mySearchParamRegistry.setPhoneticEncoder(new ApacheEncoder(PhoneticEncoderEnum.SOUNDEX.name(), new Soundex()));
|
||||
}
|
||||
|
||||
@After
|
||||
public void resetStringEncoder() {
|
||||
mySearchParamRegistry.setPhoneticEncoder(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSoundex() {
|
||||
Soundex soundex = new Soundex();
|
||||
assertEquals(soundex.encode(GALE), soundex.encode(GAIL));
|
||||
assertNotEquals(soundex.encode(GALE), soundex.encode(BOB));
|
||||
assertEquals(soundex.encode(ADDRESS), soundex.encode(ADDRESS_CLOSE));
|
||||
assertNotEquals(soundex.encode(ADDRESS), soundex.encode(ADDRESS_FAR));
|
||||
ourLog.info("Encoded address: {}", soundex.encode(ADDRESS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void phoneticMatch() {
|
||||
Patient patient;
|
||||
|
||||
patient = new Patient();
|
||||
patient.addName().addGiven(GALE);
|
||||
patient.addAddress().addLine(ADDRESS);
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(patient));
|
||||
|
||||
IIdType pId = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
List<ResourceIndexedSearchParamString> stringParams = myResourceIndexedSearchParamStringDao.findAll();
|
||||
|
||||
assertThat(stringParams, hasSize(6));
|
||||
List<String> stringParamNames = stringParams.stream().map(ResourceIndexedSearchParamString::getParamName).collect(Collectors.toList());
|
||||
assertThat(stringParamNames, containsInAnyOrder(Patient.SP_NAME, Patient.SP_GIVEN, Patient.SP_PHONETIC, NAME_SOUNDEX_SP, Patient.SP_ADDRESS, ADDRESS_LINE_SOUNDEX_SP));
|
||||
|
||||
assertSearchMatch(pId, Patient.SP_PHONETIC, GALE);
|
||||
assertSearchMatch(pId, Patient.SP_PHONETIC, GAIL);
|
||||
assertNoMatch(Patient.SP_PHONETIC, BOB);
|
||||
|
||||
assertSearchMatch(pId, NAME_SOUNDEX_SP, GAIL);
|
||||
assertSearchMatch(pId, NAME_SOUNDEX_SP, GALE);
|
||||
assertNoMatch(NAME_SOUNDEX_SP, BOB);
|
||||
|
||||
assertSearchMatch(pId, ADDRESS_LINE_SOUNDEX_SP, ADDRESS);
|
||||
assertSearchMatch(pId, ADDRESS_LINE_SOUNDEX_SP, ADDRESS_CLOSE);
|
||||
assertNoMatch(ADDRESS_LINE_SOUNDEX_SP, ADDRESS_FAR);
|
||||
}
|
||||
|
||||
private void assertSearchMatch(IIdType thePId1, String theSp, String theValue) {
|
||||
SearchParameterMap map;
|
||||
map = new SearchParameterMap();
|
||||
map.add(theSp, new StringParam(theValue));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), contains(toValues(thePId1)));
|
||||
}
|
||||
|
||||
private void assertNoMatch(String theSp, String theValue) {
|
||||
SearchParameterMap map;
|
||||
map = new SearchParameterMap();
|
||||
map.add(theSp, new StringParam(theValue));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), hasSize(0));
|
||||
}
|
||||
|
||||
private void createSoundexSearchParameter(String theCode, PhoneticEncoderEnum theEncoder, String theFhirPath) {
|
||||
SearchParameter searchParameter = new SearchParameter();
|
||||
searchParameter.addBase("Patient");
|
||||
searchParameter.setCode(theCode);
|
||||
searchParameter.setType(Enumerations.SearchParamType.STRING);
|
||||
searchParameter.setTitle("Test Soundex");
|
||||
searchParameter.setExpression(theFhirPath);
|
||||
// Maybe use in the future? RuntimeSearchParam doesn't store this...
|
||||
// searchParameter.setXpathUsage(SearchParameter.XPathUsageType.PHONETIC);
|
||||
searchParameter.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
searchParameter.addExtension()
|
||||
.setUrl(JpaConstants.EXT_SEARCHPARAM_PHONETIC_ENCODER)
|
||||
.setValue(new StringType(theEncoder.name()));
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(searchParameter));
|
||||
mySearchParameterDao.create(searchParameter, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -36,6 +36,7 @@ import org.hl7.fhir.r4.model.CodeSystem;
|
|||
import org.hl7.fhir.r4.model.Coding;
|
||||
import org.hl7.fhir.r4.model.Condition;
|
||||
import org.hl7.fhir.r4.model.DateTimeType;
|
||||
import org.hl7.fhir.r4.model.Enumerations;
|
||||
import org.hl7.fhir.r4.model.Group;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Narrative;
|
||||
|
@ -1291,6 +1292,27 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
|
|||
assertThat(encoded, containsString("No issues detected"));
|
||||
}
|
||||
|
||||
/**
|
||||
* See #1780
|
||||
*/
|
||||
@Test
|
||||
public void testExpand() {
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
vs.setUrl("test.com/testValueSet");
|
||||
vs.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
vs.getCompose()
|
||||
.addInclude().setSystem("http://hl7.org/fhir/action-cardinality-behavior");
|
||||
IIdType id = myValueSetDao.create(vs).getId().toUnqualifiedVersionless();
|
||||
|
||||
myTermReadSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||
|
||||
ValueSet expansion = myValueSetDao.expand(id, null, 0, 10000, mySrd);
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expansion));
|
||||
|
||||
assertEquals(2, expansion.getExpansion().getContains().size());
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
|
|
|
@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.dao.r4;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
|
||||
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
|
@ -401,6 +402,11 @@ public class SearchParamExtractorR4Test {
|
|||
public Collection<RuntimeSearchParam> getSearchParamsByResourceType(RuntimeResourceDefinition theResourceDef) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPhoneticEncoder(IPhoneticEncoder thePhoneticEncoder) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>6.0.5</version>
|
||||
<version>8.0.16</version>
|
||||
</dependency>
|
||||
<!--
|
||||
<dependency>
|
||||
|
|
|
@ -187,10 +187,15 @@ public class JpaConstants {
|
|||
*/
|
||||
public static final String PARAM_EXPORT_TYPE_FILTER = "_typeFilter";
|
||||
/**
|
||||
* Placed in system-generated extensions
|
||||
* URL for extension on a SearchParameter indicating that text values should not be indexed
|
||||
*/
|
||||
public static final String EXTENSION_EXT_SYSTEMDEFINED = JpaConstants.class.getName() + "_EXTENSION_EXT_SYSTEMDEFINED";
|
||||
|
||||
/**
|
||||
* URL for extension on a Phonetic String SearchParameter indicating that text values should be phonetically indexed with the named encoder
|
||||
*/
|
||||
public static final String EXT_SEARCHPARAM_PHONETIC_ENCODER = "http://hapifhir.io/fhir/StructureDefinition/searchparameter-phonetic-encoder";
|
||||
|
||||
/**
|
||||
* Non-instantiable
|
||||
*/
|
||||
|
|
|
@ -33,6 +33,7 @@ import ca.uhn.fhir.jpa.searchparam.matcher.IndexedSearchParamExtractor;
|
|||
import ca.uhn.fhir.jpa.searchparam.matcher.SearchParamMatcher;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryImpl;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.SearchParameterCanonicalizer;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -81,6 +82,12 @@ public class SearchParamConfig {
|
|||
return new SearchParamExtractorService();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Lazy
|
||||
public SearchParameterCanonicalizer searchParameterCanonicalizer(FhirContext theFhirContext) {
|
||||
return new SearchParameterCanonicalizer(theFhirContext);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IndexedSearchParamExtractor indexedSearchParamExtractor() {
|
||||
return new IndexedSearchParamExtractor();
|
||||
|
|
|
@ -81,8 +81,8 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
import static org.apache.commons.lang3.StringUtils.trim;
|
||||
|
||||
public abstract class BaseSearchParamExtractor implements ISearchParamExtractor {
|
||||
private static final Pattern SPLIT = Pattern.compile("\\||( or )");
|
||||
|
||||
private static final Pattern SPLIT = Pattern.compile("\\||( or )");
|
||||
private static final Pattern SPLIT_R4 = Pattern.compile("\\|");
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseSearchParamExtractor.class);
|
||||
@Autowired
|
||||
|
@ -95,6 +95,7 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
|||
private ModelConfig myModelConfig;
|
||||
@Autowired
|
||||
private PartitionSettings myPartitionSettings;
|
||||
|
||||
private Set<String> myIgnoredForSearchDatatypes;
|
||||
private BaseRuntimeChildDefinition myQuantityValueValueChild;
|
||||
private BaseRuntimeChildDefinition myQuantitySystemValueChild;
|
||||
|
@ -252,7 +253,7 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
|||
@Override
|
||||
public List<String> extractParamValuesAsStrings(RuntimeSearchParam theSearchParam, IBaseResource theResource) {
|
||||
IExtractor extractor;
|
||||
switch(theSearchParam.getParamType()) {
|
||||
switch (theSearchParam.getParamType()) {
|
||||
case DATE:
|
||||
extractor = createDateExtractor(theResource);
|
||||
break;
|
||||
|
@ -972,12 +973,10 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
|||
for (String next : families) {
|
||||
createStringIndexIfNotBlank(theResourceType, theParams, theSearchParam, next);
|
||||
}
|
||||
|
||||
List<String> givens = extractValuesAsStrings(myHumanNameGivenValueChild, theValue);
|
||||
for (String next : givens) {
|
||||
createStringIndexIfNotBlank(theResourceType, theParams, theSearchParam, next);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void addString_Quantity(String theResourceType, Set<ResourceIndexedSearchParamString> theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
|
||||
|
@ -1099,11 +1098,13 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
|||
|
||||
String searchParamName = theSearchParam.getName();
|
||||
String valueNormalized = StringUtil.normalizeStringForSearchIndexing(value);
|
||||
if (valueNormalized.length() > ResourceIndexedSearchParamString.MAX_LENGTH) {
|
||||
valueNormalized = valueNormalized.substring(0, ResourceIndexedSearchParamString.MAX_LENGTH);
|
||||
String valueEncoded = theSearchParam.encode(valueNormalized);
|
||||
|
||||
if (valueEncoded.length() > ResourceIndexedSearchParamString.MAX_LENGTH) {
|
||||
valueEncoded = valueEncoded.substring(0, ResourceIndexedSearchParamString.MAX_LENGTH);
|
||||
}
|
||||
|
||||
ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(myPartitionSettings, getModelConfig(), theResourceType, searchParamName, valueNormalized, value);
|
||||
ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(myPartitionSettings, getModelConfig(), theResourceType, searchParamName, valueEncoded, value);
|
||||
|
||||
Set params = theParams;
|
||||
params.add(nextEntity);
|
||||
|
|
|
@ -85,6 +85,7 @@ public class SearchParamExtractorService {
|
|||
@Autowired(required = false)
|
||||
private IResourceLinkResolver myResourceLinkResolver;
|
||||
|
||||
|
||||
/**
|
||||
* This method is responsible for scanning a resource for all of the search parameter instances. I.e. for all search parameters defined for
|
||||
* a given resource type, it extracts the associated indexes and populates {@literal theParams}.
|
||||
|
|
|
@ -22,6 +22,7 @@ package ca.uhn.fhir.jpa.searchparam.registry;
|
|||
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
|
||||
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
||||
|
||||
import java.util.Collection;
|
||||
|
@ -59,4 +60,12 @@ public interface ISearchParamRegistry {
|
|||
RuntimeSearchParam getSearchParamByName(RuntimeResourceDefinition theResourceDef, String theParamName);
|
||||
|
||||
Collection<RuntimeSearchParam> getSearchParamsByResourceType(RuntimeResourceDefinition theResourceDef);
|
||||
|
||||
/**
|
||||
* When indexing a HumanName, if a StringEncoder is set in the context, then the "phonetic" search parameter will normalize
|
||||
* the String using this encoder.
|
||||
*
|
||||
* @since 5.1.0
|
||||
*/
|
||||
void setPhoneticEncoder(IPhoneticEncoder thePhoneticEncoder);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.jpa.searchparam.registry;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
|
||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
|
@ -34,8 +35,6 @@ import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
|||
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.searchparam.retry.Retrier;
|
||||
import ca.uhn.fhir.model.api.ExtensionDt;
|
||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
|
@ -43,24 +42,26 @@ import ca.uhn.fhir.util.DatatypeUtil;
|
|||
import ca.uhn.fhir.util.HapiExtensions;
|
||||
import ca.uhn.fhir.util.SearchParameterUtil;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hl7.fhir.dstu3.model.Extension;
|
||||
import org.hl7.fhir.dstu3.model.SearchParameter;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class SearchParamRegistryImpl implements ISearchParamRegistry {
|
||||
|
||||
|
@ -76,8 +77,12 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry {
|
|||
private FhirContext myFhirContext;
|
||||
@Autowired
|
||||
private ISchedulerService mySchedulerService;
|
||||
@Autowired
|
||||
private SearchParameterCanonicalizer mySearchParameterCanonicalizer;
|
||||
|
||||
private Map<String, Map<String, RuntimeSearchParam>> myBuiltInSearchParams;
|
||||
private IPhoneticEncoder myPhoneticEncoder;
|
||||
|
||||
private volatile Map<String, List<JpaRuntimeSearchParam>> myActiveUniqueSearchParams = Collections.emptyMap();
|
||||
private volatile Map<String, Map<Set<String>, List<JpaRuntimeSearchParam>>> myActiveParamNamesToUniqueSearchParams = Collections.emptyMap();
|
||||
private volatile Map<String, Map<String, RuntimeSearchParam>> myActiveSearchParams;
|
||||
|
@ -175,6 +180,8 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry {
|
|||
uniqueSearchParams.add(nextCandidateCasted);
|
||||
}
|
||||
}
|
||||
|
||||
setPhoneticEncoder(nextCandidate);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -228,21 +235,11 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry {
|
|||
myActiveParamNamesToUniqueSearchParams = activeParamNamesToUniqueSearchParams;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setFhirContextForUnitTest(FhirContext theFhirContext) {
|
||||
myFhirContext = theFhirContext;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
myBuiltInSearchParams = createBuiltInSearchParamMap(myFhirContext);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void setSearchParamProviderForUnitTest(ISearchParamProvider theSearchParamProvider) {
|
||||
mySearchParamProvider = theSearchParamProvider;
|
||||
}
|
||||
|
||||
public int doRefresh(long theRefreshInterval) {
|
||||
if (System.currentTimeMillis() - theRefreshInterval > myLastRefresh) {
|
||||
StopWatch sw = new StopWatch();
|
||||
|
@ -280,7 +277,7 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry {
|
|||
continue;
|
||||
}
|
||||
|
||||
RuntimeSearchParam runtimeSp = canonicalizeSearchParameter(nextSp);
|
||||
RuntimeSearchParam runtimeSp = mySearchParameterCanonicalizer.canonicalizeSearchParameter(nextSp);
|
||||
if (runtimeSp == null) {
|
||||
continue;
|
||||
}
|
||||
|
@ -337,361 +334,6 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry {
|
|||
}
|
||||
}
|
||||
|
||||
protected RuntimeSearchParam canonicalizeSearchParameter(IBaseResource theSearchParameter) {
|
||||
switch (myFhirContext.getVersion().getVersion()) {
|
||||
case DSTU2:
|
||||
return canonicalizeSearchParameterDstu2((ca.uhn.fhir.model.dstu2.resource.SearchParameter) theSearchParameter);
|
||||
case DSTU3:
|
||||
return canonicalizeSearchParameterDstu3((org.hl7.fhir.dstu3.model.SearchParameter) theSearchParameter);
|
||||
case R4:
|
||||
return canonicalizeSearchParameterR4((org.hl7.fhir.r4.model.SearchParameter) theSearchParameter);
|
||||
case DSTU2_HL7ORG:
|
||||
case DSTU2_1:
|
||||
// Non-supported - these won't happen so just fall through
|
||||
case R5:
|
||||
default:
|
||||
return canonicalizeSearchParameterR5((org.hl7.fhir.r5.model.SearchParameter) theSearchParameter);
|
||||
}
|
||||
}
|
||||
|
||||
private RuntimeSearchParam canonicalizeSearchParameterDstu2(ca.uhn.fhir.model.dstu2.resource.SearchParameter theNextSp) {
|
||||
String name = theNextSp.getCode();
|
||||
String description = theNextSp.getDescription();
|
||||
String path = theNextSp.getXpath();
|
||||
RestSearchParameterTypeEnum paramType = null;
|
||||
RuntimeSearchParam.RuntimeSearchParamStatusEnum status = null;
|
||||
switch (theNextSp.getTypeElement().getValueAsEnum()) {
|
||||
case COMPOSITE:
|
||||
paramType = RestSearchParameterTypeEnum.COMPOSITE;
|
||||
break;
|
||||
case DATE_DATETIME:
|
||||
paramType = RestSearchParameterTypeEnum.DATE;
|
||||
break;
|
||||
case NUMBER:
|
||||
paramType = RestSearchParameterTypeEnum.NUMBER;
|
||||
break;
|
||||
case QUANTITY:
|
||||
paramType = RestSearchParameterTypeEnum.QUANTITY;
|
||||
break;
|
||||
case REFERENCE:
|
||||
paramType = RestSearchParameterTypeEnum.REFERENCE;
|
||||
break;
|
||||
case STRING:
|
||||
paramType = RestSearchParameterTypeEnum.STRING;
|
||||
break;
|
||||
case TOKEN:
|
||||
paramType = RestSearchParameterTypeEnum.TOKEN;
|
||||
break;
|
||||
case URI:
|
||||
paramType = RestSearchParameterTypeEnum.URI;
|
||||
break;
|
||||
}
|
||||
if (theNextSp.getStatus() != null) {
|
||||
switch (theNextSp.getStatusElement().getValueAsEnum()) {
|
||||
case ACTIVE:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE;
|
||||
break;
|
||||
case DRAFT:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.DRAFT;
|
||||
break;
|
||||
case RETIRED:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.RETIRED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Set<String> providesMembershipInCompartments = Collections.emptySet();
|
||||
Set<String> targets = DatatypeUtil.toStringSet(theNextSp.getTarget());
|
||||
|
||||
if (isBlank(name) || isBlank(path)) {
|
||||
if (paramType != RestSearchParameterTypeEnum.COMPOSITE) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
IIdType id = theNextSp.getIdElement();
|
||||
String uri = "";
|
||||
boolean unique = false;
|
||||
|
||||
List<ExtensionDt> uniqueExts = theNextSp.getUndeclaredExtensionsByUrl(HapiExtensions.EXT_SP_UNIQUE);
|
||||
if (uniqueExts.size() > 0) {
|
||||
IPrimitiveType<?> uniqueExtsValuePrimitive = uniqueExts.get(0).getValueAsPrimitive();
|
||||
if (uniqueExtsValuePrimitive != null) {
|
||||
if ("true".equalsIgnoreCase(uniqueExtsValuePrimitive.getValueAsString())) {
|
||||
unique = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<JpaRuntimeSearchParam.Component> components = Collections.emptyList();
|
||||
Collection<? extends IPrimitiveType<String>> base = Collections.singletonList(theNextSp.getBaseElement());
|
||||
JpaRuntimeSearchParam retVal = new JpaRuntimeSearchParam(id, uri, name, description, path, paramType, providesMembershipInCompartments, targets, status, unique, components, base);
|
||||
extractExtensions(theNextSp, retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private RuntimeSearchParam canonicalizeSearchParameterDstu3(org.hl7.fhir.dstu3.model.SearchParameter theNextSp) {
|
||||
String name = theNextSp.getCode();
|
||||
String description = theNextSp.getDescription();
|
||||
String path = theNextSp.getExpression();
|
||||
RestSearchParameterTypeEnum paramType = null;
|
||||
RuntimeSearchParam.RuntimeSearchParamStatusEnum status = null;
|
||||
switch (theNextSp.getType()) {
|
||||
case COMPOSITE:
|
||||
paramType = RestSearchParameterTypeEnum.COMPOSITE;
|
||||
break;
|
||||
case DATE:
|
||||
paramType = RestSearchParameterTypeEnum.DATE;
|
||||
break;
|
||||
case NUMBER:
|
||||
paramType = RestSearchParameterTypeEnum.NUMBER;
|
||||
break;
|
||||
case QUANTITY:
|
||||
paramType = RestSearchParameterTypeEnum.QUANTITY;
|
||||
break;
|
||||
case REFERENCE:
|
||||
paramType = RestSearchParameterTypeEnum.REFERENCE;
|
||||
break;
|
||||
case STRING:
|
||||
paramType = RestSearchParameterTypeEnum.STRING;
|
||||
break;
|
||||
case TOKEN:
|
||||
paramType = RestSearchParameterTypeEnum.TOKEN;
|
||||
break;
|
||||
case URI:
|
||||
paramType = RestSearchParameterTypeEnum.URI;
|
||||
break;
|
||||
case NULL:
|
||||
break;
|
||||
}
|
||||
if (theNextSp.getStatus() != null) {
|
||||
switch (theNextSp.getStatus()) {
|
||||
case ACTIVE:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE;
|
||||
break;
|
||||
case DRAFT:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.DRAFT;
|
||||
break;
|
||||
case RETIRED:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.RETIRED;
|
||||
break;
|
||||
case UNKNOWN:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.UNKNOWN;
|
||||
break;
|
||||
case NULL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
Set<String> providesMembershipInCompartments = Collections.emptySet();
|
||||
Set<String> targets = DatatypeUtil.toStringSet(theNextSp.getTarget());
|
||||
|
||||
if (isBlank(name) || isBlank(path) || paramType == null) {
|
||||
if (paramType != RestSearchParameterTypeEnum.COMPOSITE) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
IIdType id = theNextSp.getIdElement();
|
||||
String uri = "";
|
||||
boolean unique = false;
|
||||
|
||||
List<Extension> uniqueExts = theNextSp.getExtensionsByUrl(HapiExtensions.EXT_SP_UNIQUE);
|
||||
if (uniqueExts.size() > 0) {
|
||||
IPrimitiveType<?> uniqueExtsValuePrimitive = uniqueExts.get(0).getValueAsPrimitive();
|
||||
if (uniqueExtsValuePrimitive != null) {
|
||||
if ("true".equalsIgnoreCase(uniqueExtsValuePrimitive.getValueAsString())) {
|
||||
unique = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<JpaRuntimeSearchParam.Component> components = new ArrayList<>();
|
||||
for (SearchParameter.SearchParameterComponentComponent next : theNextSp.getComponent()) {
|
||||
components.add(new JpaRuntimeSearchParam.Component(next.getExpression(), next.getDefinition()));
|
||||
}
|
||||
|
||||
JpaRuntimeSearchParam retVal = new JpaRuntimeSearchParam(id, uri, name, description, path, paramType, providesMembershipInCompartments, targets, status, unique, components, theNextSp.getBase());
|
||||
extractExtensions(theNextSp, retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private RuntimeSearchParam canonicalizeSearchParameterR4(org.hl7.fhir.r4.model.SearchParameter theNextSp) {
|
||||
String name = theNextSp.getCode();
|
||||
String description = theNextSp.getDescription();
|
||||
String path = theNextSp.getExpression();
|
||||
RestSearchParameterTypeEnum paramType = null;
|
||||
RuntimeSearchParam.RuntimeSearchParamStatusEnum status = null;
|
||||
switch (theNextSp.getType()) {
|
||||
case COMPOSITE:
|
||||
paramType = RestSearchParameterTypeEnum.COMPOSITE;
|
||||
break;
|
||||
case DATE:
|
||||
paramType = RestSearchParameterTypeEnum.DATE;
|
||||
break;
|
||||
case NUMBER:
|
||||
paramType = RestSearchParameterTypeEnum.NUMBER;
|
||||
break;
|
||||
case QUANTITY:
|
||||
paramType = RestSearchParameterTypeEnum.QUANTITY;
|
||||
break;
|
||||
case REFERENCE:
|
||||
paramType = RestSearchParameterTypeEnum.REFERENCE;
|
||||
break;
|
||||
case STRING:
|
||||
paramType = RestSearchParameterTypeEnum.STRING;
|
||||
break;
|
||||
case TOKEN:
|
||||
paramType = RestSearchParameterTypeEnum.TOKEN;
|
||||
break;
|
||||
case URI:
|
||||
paramType = RestSearchParameterTypeEnum.URI;
|
||||
break;
|
||||
case SPECIAL:
|
||||
paramType = RestSearchParameterTypeEnum.SPECIAL;
|
||||
break;
|
||||
case NULL:
|
||||
break;
|
||||
}
|
||||
if (theNextSp.getStatus() != null) {
|
||||
switch (theNextSp.getStatus()) {
|
||||
case ACTIVE:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE;
|
||||
break;
|
||||
case DRAFT:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.DRAFT;
|
||||
break;
|
||||
case RETIRED:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.RETIRED;
|
||||
break;
|
||||
case UNKNOWN:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.UNKNOWN;
|
||||
break;
|
||||
case NULL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
Set<String> providesMembershipInCompartments = Collections.emptySet();
|
||||
Set<String> targets = DatatypeUtil.toStringSet(theNextSp.getTarget());
|
||||
|
||||
if (isBlank(name) || isBlank(path) || paramType == null) {
|
||||
if (paramType != RestSearchParameterTypeEnum.COMPOSITE) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
IIdType id = theNextSp.getIdElement();
|
||||
String uri = "";
|
||||
boolean unique = false;
|
||||
|
||||
List<org.hl7.fhir.r4.model.Extension> uniqueExts = theNextSp.getExtensionsByUrl(HapiExtensions.EXT_SP_UNIQUE);
|
||||
if (uniqueExts.size() > 0) {
|
||||
IPrimitiveType<?> uniqueExtsValuePrimitive = uniqueExts.get(0).getValueAsPrimitive();
|
||||
if (uniqueExtsValuePrimitive != null) {
|
||||
if ("true".equalsIgnoreCase(uniqueExtsValuePrimitive.getValueAsString())) {
|
||||
unique = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<JpaRuntimeSearchParam.Component> components = new ArrayList<>();
|
||||
for (org.hl7.fhir.r4.model.SearchParameter.SearchParameterComponentComponent next : theNextSp.getComponent()) {
|
||||
components.add(new JpaRuntimeSearchParam.Component(next.getExpression(), new Reference(next.getDefinition())));
|
||||
}
|
||||
|
||||
JpaRuntimeSearchParam retVal = new JpaRuntimeSearchParam(id, uri, name, description, path, paramType, providesMembershipInCompartments, targets, status, unique, components, theNextSp.getBase());
|
||||
extractExtensions(theNextSp, retVal);
|
||||
return retVal;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private RuntimeSearchParam canonicalizeSearchParameterR5(org.hl7.fhir.r5.model.SearchParameter theNextSp) {
|
||||
String name = theNextSp.getCode();
|
||||
String description = theNextSp.getDescription();
|
||||
String path = theNextSp.getExpression();
|
||||
RestSearchParameterTypeEnum paramType = null;
|
||||
RuntimeSearchParam.RuntimeSearchParamStatusEnum status = null;
|
||||
switch (theNextSp.getType()) {
|
||||
case COMPOSITE:
|
||||
paramType = RestSearchParameterTypeEnum.COMPOSITE;
|
||||
break;
|
||||
case DATE:
|
||||
paramType = RestSearchParameterTypeEnum.DATE;
|
||||
break;
|
||||
case NUMBER:
|
||||
paramType = RestSearchParameterTypeEnum.NUMBER;
|
||||
break;
|
||||
case QUANTITY:
|
||||
paramType = RestSearchParameterTypeEnum.QUANTITY;
|
||||
break;
|
||||
case REFERENCE:
|
||||
paramType = RestSearchParameterTypeEnum.REFERENCE;
|
||||
break;
|
||||
case STRING:
|
||||
paramType = RestSearchParameterTypeEnum.STRING;
|
||||
break;
|
||||
case TOKEN:
|
||||
paramType = RestSearchParameterTypeEnum.TOKEN;
|
||||
break;
|
||||
case URI:
|
||||
paramType = RestSearchParameterTypeEnum.URI;
|
||||
break;
|
||||
case SPECIAL:
|
||||
paramType = RestSearchParameterTypeEnum.SPECIAL;
|
||||
break;
|
||||
case NULL:
|
||||
break;
|
||||
}
|
||||
if (theNextSp.getStatus() != null) {
|
||||
switch (theNextSp.getStatus()) {
|
||||
case ACTIVE:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE;
|
||||
break;
|
||||
case DRAFT:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.DRAFT;
|
||||
break;
|
||||
case RETIRED:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.RETIRED;
|
||||
break;
|
||||
case UNKNOWN:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.UNKNOWN;
|
||||
break;
|
||||
case NULL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
Set<String> providesMembershipInCompartments = Collections.emptySet();
|
||||
Set<String> targets = DatatypeUtil.toStringSet(theNextSp.getTarget());
|
||||
|
||||
if (isBlank(name) || isBlank(path) || paramType == null) {
|
||||
if (paramType != RestSearchParameterTypeEnum.COMPOSITE) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
IIdType id = theNextSp.getIdElement();
|
||||
String uri = "";
|
||||
boolean unique = false;
|
||||
|
||||
List<org.hl7.fhir.r5.model.Extension> uniqueExts = theNextSp.getExtensionsByUrl(HapiExtensions.EXT_SP_UNIQUE);
|
||||
if (uniqueExts.size() > 0) {
|
||||
IPrimitiveType<?> uniqueExtsValuePrimitive = uniqueExts.get(0).getValueAsPrimitive();
|
||||
if (uniqueExtsValuePrimitive != null) {
|
||||
if ("true".equalsIgnoreCase(uniqueExtsValuePrimitive.getValueAsString())) {
|
||||
unique = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<JpaRuntimeSearchParam.Component> components = new ArrayList<>();
|
||||
for (org.hl7.fhir.r5.model.SearchParameter.SearchParameterComponentComponent next : theNextSp.getComponent()) {
|
||||
components.add(new JpaRuntimeSearchParam.Component(next.getExpression(), new org.hl7.fhir.r5.model.Reference(next.getDefinition())));
|
||||
}
|
||||
|
||||
JpaRuntimeSearchParam retVal = new JpaRuntimeSearchParam(id, uri, name, description, path, paramType, providesMembershipInCompartments, targets, status, unique, components, theNextSp.getBase());
|
||||
extractExtensions(theNextSp, retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RuntimeSearchParam getSearchParamByName(RuntimeResourceDefinition theResourceDef, String theParamName) {
|
||||
|
@ -760,26 +402,6 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry {
|
|||
return Collections.unmodifiableMap(myActiveSearchParams);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setSchedulerServiceForUnitTest(ISchedulerService theSchedulerService) {
|
||||
mySchedulerService = theSchedulerService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts any extensions from the resource and populates an extension field in the
|
||||
*/
|
||||
protected void extractExtensions(IBaseResource theSearchParamResource, JpaRuntimeSearchParam theRuntimeSearchParam) {
|
||||
if (theSearchParamResource instanceof IBaseHasExtensions) {
|
||||
List<? extends IBaseExtension<?, ?>> extensions = ((IBaseHasExtensions) theSearchParamResource).getExtension();
|
||||
for (IBaseExtension<?, ?> next : extensions) {
|
||||
String nextUrl = next.getUrl();
|
||||
if (isNotBlank(nextUrl)) {
|
||||
theRuntimeSearchParam.addExtension(nextUrl, next);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<String, Map<String, RuntimeSearchParam>> createBuiltInSearchParamMap(FhirContext theFhirContext) {
|
||||
Map<String, Map<String, RuntimeSearchParam>> resourceNameToSearchParams = new HashMap<>();
|
||||
|
||||
|
@ -797,4 +419,31 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry {
|
|||
}
|
||||
return Collections.unmodifiableMap(resourceNameToSearchParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* All SearchParameters with the name "phonetic" encode the normalized index value using this phonetic encoder.
|
||||
*
|
||||
* @since 5.1.0
|
||||
*/
|
||||
|
||||
public void setPhoneticEncoder(IPhoneticEncoder thePhoneticEncoder) {
|
||||
myPhoneticEncoder = thePhoneticEncoder;
|
||||
|
||||
if (myActiveSearchParams == null) {
|
||||
return;
|
||||
}
|
||||
for (Map<String, RuntimeSearchParam> activeUniqueSearchParams : myActiveSearchParams.values()) {
|
||||
for (RuntimeSearchParam searchParam : activeUniqueSearchParams.values()) {
|
||||
setPhoneticEncoder(searchParam);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setPhoneticEncoder(RuntimeSearchParam searchParam) {
|
||||
if ("phonetic".equals(searchParam.getName())) {
|
||||
ourLog.debug("Setting search param {} on {} phonetic encoder to {}",
|
||||
searchParam.getName(), searchParam.getPath(), myPhoneticEncoder == null ? "null" : myPhoneticEncoder.name());
|
||||
searchParam.setPhoneticEncoder(myPhoneticEncoder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,451 @@
|
|||
package ca.uhn.fhir.jpa.searchparam.registry;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Search Parameters
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2020 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.phonetic.PhoneticEncoderEnum;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
||||
import ca.uhn.fhir.model.api.ExtensionDt;
|
||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.util.DatatypeUtil;
|
||||
import ca.uhn.fhir.util.HapiExtensions;
|
||||
import org.apache.commons.lang3.EnumUtils;
|
||||
import org.hl7.fhir.dstu3.model.Extension;
|
||||
import org.hl7.fhir.dstu3.model.SearchParameter;
|
||||
import org.hl7.fhir.instance.model.api.IBaseDatatype;
|
||||
import org.hl7.fhir.instance.model.api.IBaseExtension;
|
||||
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
@Service
|
||||
public class SearchParameterCanonicalizer {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(SearchParameterCanonicalizer.class);
|
||||
|
||||
private final FhirContext myFhirContext;
|
||||
|
||||
@Autowired
|
||||
public SearchParameterCanonicalizer(FhirContext theFhirContext) {
|
||||
myFhirContext = theFhirContext;
|
||||
}
|
||||
|
||||
protected RuntimeSearchParam canonicalizeSearchParameter(IBaseResource theSearchParameter) {
|
||||
JpaRuntimeSearchParam retVal;
|
||||
switch (myFhirContext.getVersion().getVersion()) {
|
||||
case DSTU2:
|
||||
retVal = canonicalizeSearchParameterDstu2((ca.uhn.fhir.model.dstu2.resource.SearchParameter) theSearchParameter);
|
||||
break;
|
||||
case DSTU3:
|
||||
retVal = canonicalizeSearchParameterDstu3((org.hl7.fhir.dstu3.model.SearchParameter) theSearchParameter);
|
||||
break;
|
||||
case R4:
|
||||
retVal = canonicalizeSearchParameterR4((org.hl7.fhir.r4.model.SearchParameter) theSearchParameter);
|
||||
break;
|
||||
case R5:
|
||||
retVal = canonicalizeSearchParameterR5((org.hl7.fhir.r5.model.SearchParameter) theSearchParameter);
|
||||
break;
|
||||
case DSTU2_HL7ORG:
|
||||
case DSTU2_1:
|
||||
// Non-supported - these won't happen so just fall through
|
||||
default:
|
||||
throw new InternalErrorException("SearchParameter canonicalization not supported for FHIR version" + myFhirContext.getVersion().getVersion());
|
||||
}
|
||||
extractExtensions(theSearchParameter, retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private JpaRuntimeSearchParam canonicalizeSearchParameterDstu2(ca.uhn.fhir.model.dstu2.resource.SearchParameter theNextSp) {
|
||||
String name = theNextSp.getCode();
|
||||
String description = theNextSp.getDescription();
|
||||
String path = theNextSp.getXpath();
|
||||
RestSearchParameterTypeEnum paramType = null;
|
||||
RuntimeSearchParam.RuntimeSearchParamStatusEnum status = null;
|
||||
switch (theNextSp.getTypeElement().getValueAsEnum()) {
|
||||
case COMPOSITE:
|
||||
paramType = RestSearchParameterTypeEnum.COMPOSITE;
|
||||
break;
|
||||
case DATE_DATETIME:
|
||||
paramType = RestSearchParameterTypeEnum.DATE;
|
||||
break;
|
||||
case NUMBER:
|
||||
paramType = RestSearchParameterTypeEnum.NUMBER;
|
||||
break;
|
||||
case QUANTITY:
|
||||
paramType = RestSearchParameterTypeEnum.QUANTITY;
|
||||
break;
|
||||
case REFERENCE:
|
||||
paramType = RestSearchParameterTypeEnum.REFERENCE;
|
||||
break;
|
||||
case STRING:
|
||||
paramType = RestSearchParameterTypeEnum.STRING;
|
||||
break;
|
||||
case TOKEN:
|
||||
paramType = RestSearchParameterTypeEnum.TOKEN;
|
||||
break;
|
||||
case URI:
|
||||
paramType = RestSearchParameterTypeEnum.URI;
|
||||
break;
|
||||
}
|
||||
if (theNextSp.getStatus() != null) {
|
||||
switch (theNextSp.getStatusElement().getValueAsEnum()) {
|
||||
case ACTIVE:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE;
|
||||
break;
|
||||
case DRAFT:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.DRAFT;
|
||||
break;
|
||||
case RETIRED:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.RETIRED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Set<String> providesMembershipInCompartments = Collections.emptySet();
|
||||
Set<String> targets = DatatypeUtil.toStringSet(theNextSp.getTarget());
|
||||
|
||||
if (isBlank(name) || isBlank(path)) {
|
||||
if (paramType != RestSearchParameterTypeEnum.COMPOSITE) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
IIdType id = theNextSp.getIdElement();
|
||||
String uri = "";
|
||||
boolean unique = false;
|
||||
|
||||
List<ExtensionDt> uniqueExts = theNextSp.getUndeclaredExtensionsByUrl(HapiExtensions.EXT_SP_UNIQUE);
|
||||
if (uniqueExts.size() > 0) {
|
||||
IPrimitiveType<?> uniqueExtsValuePrimitive = uniqueExts.get(0).getValueAsPrimitive();
|
||||
if (uniqueExtsValuePrimitive != null) {
|
||||
if ("true".equalsIgnoreCase(uniqueExtsValuePrimitive.getValueAsString())) {
|
||||
unique = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<JpaRuntimeSearchParam.Component> components = Collections.emptyList();
|
||||
Collection<? extends IPrimitiveType<String>> base = Collections.singletonList(theNextSp.getBaseElement());
|
||||
return new JpaRuntimeSearchParam(id, uri, name, description, path, paramType, providesMembershipInCompartments, targets, status, unique, components, base);
|
||||
}
|
||||
|
||||
private JpaRuntimeSearchParam canonicalizeSearchParameterDstu3(org.hl7.fhir.dstu3.model.SearchParameter theNextSp) {
|
||||
String name = theNextSp.getCode();
|
||||
String description = theNextSp.getDescription();
|
||||
String path = theNextSp.getExpression();
|
||||
RestSearchParameterTypeEnum paramType = null;
|
||||
RuntimeSearchParam.RuntimeSearchParamStatusEnum status = null;
|
||||
switch (theNextSp.getType()) {
|
||||
case COMPOSITE:
|
||||
paramType = RestSearchParameterTypeEnum.COMPOSITE;
|
||||
break;
|
||||
case DATE:
|
||||
paramType = RestSearchParameterTypeEnum.DATE;
|
||||
break;
|
||||
case NUMBER:
|
||||
paramType = RestSearchParameterTypeEnum.NUMBER;
|
||||
break;
|
||||
case QUANTITY:
|
||||
paramType = RestSearchParameterTypeEnum.QUANTITY;
|
||||
break;
|
||||
case REFERENCE:
|
||||
paramType = RestSearchParameterTypeEnum.REFERENCE;
|
||||
break;
|
||||
case STRING:
|
||||
paramType = RestSearchParameterTypeEnum.STRING;
|
||||
break;
|
||||
case TOKEN:
|
||||
paramType = RestSearchParameterTypeEnum.TOKEN;
|
||||
break;
|
||||
case URI:
|
||||
paramType = RestSearchParameterTypeEnum.URI;
|
||||
break;
|
||||
case NULL:
|
||||
break;
|
||||
}
|
||||
if (theNextSp.getStatus() != null) {
|
||||
switch (theNextSp.getStatus()) {
|
||||
case ACTIVE:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE;
|
||||
break;
|
||||
case DRAFT:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.DRAFT;
|
||||
break;
|
||||
case RETIRED:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.RETIRED;
|
||||
break;
|
||||
case UNKNOWN:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.UNKNOWN;
|
||||
break;
|
||||
case NULL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
Set<String> providesMembershipInCompartments = Collections.emptySet();
|
||||
Set<String> targets = DatatypeUtil.toStringSet(theNextSp.getTarget());
|
||||
|
||||
if (isBlank(name) || isBlank(path) || paramType == null) {
|
||||
if (paramType != RestSearchParameterTypeEnum.COMPOSITE) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
IIdType id = theNextSp.getIdElement();
|
||||
String uri = "";
|
||||
boolean unique = false;
|
||||
|
||||
List<Extension> uniqueExts = theNextSp.getExtensionsByUrl(HapiExtensions.EXT_SP_UNIQUE);
|
||||
if (uniqueExts.size() > 0) {
|
||||
IPrimitiveType<?> uniqueExtsValuePrimitive = uniqueExts.get(0).getValueAsPrimitive();
|
||||
if (uniqueExtsValuePrimitive != null) {
|
||||
if ("true".equalsIgnoreCase(uniqueExtsValuePrimitive.getValueAsString())) {
|
||||
unique = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<JpaRuntimeSearchParam.Component> components = new ArrayList<>();
|
||||
for (SearchParameter.SearchParameterComponentComponent next : theNextSp.getComponent()) {
|
||||
components.add(new JpaRuntimeSearchParam.Component(next.getExpression(), next.getDefinition()));
|
||||
}
|
||||
|
||||
return new JpaRuntimeSearchParam(id, uri, name, description, path, paramType, providesMembershipInCompartments, targets, status, unique, components, theNextSp.getBase());
|
||||
}
|
||||
|
||||
private JpaRuntimeSearchParam canonicalizeSearchParameterR4(org.hl7.fhir.r4.model.SearchParameter theNextSp) {
|
||||
String name = theNextSp.getCode();
|
||||
String description = theNextSp.getDescription();
|
||||
String path = theNextSp.getExpression();
|
||||
RestSearchParameterTypeEnum paramType = null;
|
||||
RuntimeSearchParam.RuntimeSearchParamStatusEnum status = null;
|
||||
switch (theNextSp.getType()) {
|
||||
case COMPOSITE:
|
||||
paramType = RestSearchParameterTypeEnum.COMPOSITE;
|
||||
break;
|
||||
case DATE:
|
||||
paramType = RestSearchParameterTypeEnum.DATE;
|
||||
break;
|
||||
case NUMBER:
|
||||
paramType = RestSearchParameterTypeEnum.NUMBER;
|
||||
break;
|
||||
case QUANTITY:
|
||||
paramType = RestSearchParameterTypeEnum.QUANTITY;
|
||||
break;
|
||||
case REFERENCE:
|
||||
paramType = RestSearchParameterTypeEnum.REFERENCE;
|
||||
break;
|
||||
case STRING:
|
||||
paramType = RestSearchParameterTypeEnum.STRING;
|
||||
break;
|
||||
case TOKEN:
|
||||
paramType = RestSearchParameterTypeEnum.TOKEN;
|
||||
break;
|
||||
case URI:
|
||||
paramType = RestSearchParameterTypeEnum.URI;
|
||||
break;
|
||||
case SPECIAL:
|
||||
paramType = RestSearchParameterTypeEnum.SPECIAL;
|
||||
break;
|
||||
case NULL:
|
||||
break;
|
||||
}
|
||||
if (theNextSp.getStatus() != null) {
|
||||
switch (theNextSp.getStatus()) {
|
||||
case ACTIVE:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE;
|
||||
break;
|
||||
case DRAFT:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.DRAFT;
|
||||
break;
|
||||
case RETIRED:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.RETIRED;
|
||||
break;
|
||||
case UNKNOWN:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.UNKNOWN;
|
||||
break;
|
||||
case NULL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
Set<String> providesMembershipInCompartments = Collections.emptySet();
|
||||
Set<String> targets = DatatypeUtil.toStringSet(theNextSp.getTarget());
|
||||
|
||||
if (isBlank(name) || isBlank(path) || paramType == null) {
|
||||
if (paramType != RestSearchParameterTypeEnum.COMPOSITE) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
IIdType id = theNextSp.getIdElement();
|
||||
String uri = "";
|
||||
boolean unique = false;
|
||||
|
||||
List<org.hl7.fhir.r4.model.Extension> uniqueExts = theNextSp.getExtensionsByUrl(HapiExtensions.EXT_SP_UNIQUE);
|
||||
if (uniqueExts.size() > 0) {
|
||||
IPrimitiveType<?> uniqueExtsValuePrimitive = uniqueExts.get(0).getValueAsPrimitive();
|
||||
if (uniqueExtsValuePrimitive != null) {
|
||||
if ("true".equalsIgnoreCase(uniqueExtsValuePrimitive.getValueAsString())) {
|
||||
unique = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<JpaRuntimeSearchParam.Component> components = new ArrayList<>();
|
||||
for (org.hl7.fhir.r4.model.SearchParameter.SearchParameterComponentComponent next : theNextSp.getComponent()) {
|
||||
components.add(new JpaRuntimeSearchParam.Component(next.getExpression(), new Reference(next.getDefinition())));
|
||||
}
|
||||
|
||||
return new JpaRuntimeSearchParam(id, uri, name, description, path, paramType, providesMembershipInCompartments, targets, status, unique, components, theNextSp.getBase());
|
||||
}
|
||||
|
||||
private JpaRuntimeSearchParam canonicalizeSearchParameterR5(org.hl7.fhir.r5.model.SearchParameter theNextSp) {
|
||||
String name = theNextSp.getCode();
|
||||
String description = theNextSp.getDescription();
|
||||
String path = theNextSp.getExpression();
|
||||
RestSearchParameterTypeEnum paramType = null;
|
||||
RuntimeSearchParam.RuntimeSearchParamStatusEnum status = null;
|
||||
switch (theNextSp.getType()) {
|
||||
case COMPOSITE:
|
||||
paramType = RestSearchParameterTypeEnum.COMPOSITE;
|
||||
break;
|
||||
case DATE:
|
||||
paramType = RestSearchParameterTypeEnum.DATE;
|
||||
break;
|
||||
case NUMBER:
|
||||
paramType = RestSearchParameterTypeEnum.NUMBER;
|
||||
break;
|
||||
case QUANTITY:
|
||||
paramType = RestSearchParameterTypeEnum.QUANTITY;
|
||||
break;
|
||||
case REFERENCE:
|
||||
paramType = RestSearchParameterTypeEnum.REFERENCE;
|
||||
break;
|
||||
case STRING:
|
||||
paramType = RestSearchParameterTypeEnum.STRING;
|
||||
break;
|
||||
case TOKEN:
|
||||
paramType = RestSearchParameterTypeEnum.TOKEN;
|
||||
break;
|
||||
case URI:
|
||||
paramType = RestSearchParameterTypeEnum.URI;
|
||||
break;
|
||||
case SPECIAL:
|
||||
paramType = RestSearchParameterTypeEnum.SPECIAL;
|
||||
break;
|
||||
case NULL:
|
||||
break;
|
||||
}
|
||||
if (theNextSp.getStatus() != null) {
|
||||
switch (theNextSp.getStatus()) {
|
||||
case ACTIVE:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE;
|
||||
break;
|
||||
case DRAFT:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.DRAFT;
|
||||
break;
|
||||
case RETIRED:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.RETIRED;
|
||||
break;
|
||||
case UNKNOWN:
|
||||
status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.UNKNOWN;
|
||||
break;
|
||||
case NULL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
Set<String> providesMembershipInCompartments = Collections.emptySet();
|
||||
Set<String> targets = DatatypeUtil.toStringSet(theNextSp.getTarget());
|
||||
|
||||
if (isBlank(name) || isBlank(path) || paramType == null) {
|
||||
if (paramType != RestSearchParameterTypeEnum.COMPOSITE) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
IIdType id = theNextSp.getIdElement();
|
||||
String uri = "";
|
||||
boolean unique = false;
|
||||
|
||||
List<org.hl7.fhir.r5.model.Extension> uniqueExts = theNextSp.getExtensionsByUrl(HapiExtensions.EXT_SP_UNIQUE);
|
||||
if (uniqueExts.size() > 0) {
|
||||
IPrimitiveType<?> uniqueExtsValuePrimitive = uniqueExts.get(0).getValueAsPrimitive();
|
||||
if (uniqueExtsValuePrimitive != null) {
|
||||
if ("true".equalsIgnoreCase(uniqueExtsValuePrimitive.getValueAsString())) {
|
||||
unique = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<JpaRuntimeSearchParam.Component> components = new ArrayList<>();
|
||||
for (org.hl7.fhir.r5.model.SearchParameter.SearchParameterComponentComponent next : theNextSp.getComponent()) {
|
||||
components.add(new JpaRuntimeSearchParam.Component(next.getExpression(), new org.hl7.fhir.r5.model.Reference(next.getDefinition())));
|
||||
}
|
||||
|
||||
return new JpaRuntimeSearchParam(id, uri, name, description, path, paramType, providesMembershipInCompartments, targets, status, unique, components, theNextSp.getBase());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extracts any extensions from the resource and populates an extension field in the
|
||||
*/
|
||||
protected void extractExtensions(IBaseResource theSearchParamResource, JpaRuntimeSearchParam theRuntimeSearchParam) {
|
||||
if (theSearchParamResource instanceof IBaseHasExtensions) {
|
||||
List<? extends IBaseExtension<?, ?>> extensions = ((IBaseHasExtensions) theSearchParamResource).getExtension();
|
||||
for (IBaseExtension<?, ?> next : extensions) {
|
||||
String nextUrl = next.getUrl();
|
||||
if (isNotBlank(nextUrl)) {
|
||||
theRuntimeSearchParam.addExtension(nextUrl, next);
|
||||
if (JpaConstants.EXT_SEARCHPARAM_PHONETIC_ENCODER.equals(nextUrl)) {
|
||||
setEncoder(theRuntimeSearchParam, next.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setEncoder(JpaRuntimeSearchParam theRuntimeSearchParam, IBaseDatatype theValue) {
|
||||
if (theValue instanceof IPrimitiveType) {
|
||||
String stringValue = ((IPrimitiveType<?>) theValue).getValueAsString();
|
||||
PhoneticEncoderEnum encoderEnum = EnumUtils.getEnum(PhoneticEncoderEnum.class, stringValue);
|
||||
if (encoderEnum != null) {
|
||||
theRuntimeSearchParam.setPhoneticEncoder(encoderEnum.getPhoneticEncoder());
|
||||
} else {
|
||||
ourLog.error("Invalid PhoneticEncoderEnum value '" + stringValue + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.searchparam.extractor;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
|
||||
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
|
@ -291,6 +292,11 @@ public class SearchParamExtractorDstu3Test {
|
|||
public Collection<RuntimeSearchParam> getSearchParamsByResourceType(RuntimeResourceDefinition theResourceDef) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPhoneticEncoder(IPhoneticEncoder thePhoneticEncoder) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
|
|
@ -16,6 +16,7 @@ import ca.uhn.fhir.context.RuntimePrimitiveDatatypeNarrativeDefinition;
|
|||
import ca.uhn.fhir.context.RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
|
||||
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
|
@ -300,6 +301,11 @@ public class SearchParamExtractorMegaTest {
|
|||
public Collection<RuntimeSearchParam> getSearchParamsByResourceType(RuntimeResourceDefinition theResourceDef) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPhoneticEncoder(IPhoneticEncoder thePhoneticEncoder) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package ca.uhn.fhir.jpa.searchparam.registry;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.sched.ISchedulerService;
|
||||
import ca.uhn.fhir.rest.server.SimpleBundleProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
|
@ -13,25 +15,50 @@ import org.hl7.fhir.r4.model.StringType;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
@RunWith(SpringRunner.class)
|
||||
public class SearchParamRegistryImplTest {
|
||||
@Autowired
|
||||
SearchParamRegistryImpl mySearchParamRegistry;
|
||||
|
||||
@Mock
|
||||
@MockBean
|
||||
private ISchedulerService mySchedulerService;
|
||||
@Mock
|
||||
@MockBean
|
||||
private ISearchParamProvider mySearchParamProvider;
|
||||
private int myAnswerCount = 0;
|
||||
@MockBean
|
||||
private ModelConfig myModelConfig;
|
||||
@MockBean
|
||||
private IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
|
||||
@Configuration
|
||||
static class SpringConfig {
|
||||
@Bean
|
||||
FhirContext fhirContext() { return FhirContext.forR4(); }
|
||||
@Bean
|
||||
ISearchParamRegistry searchParamRegistry() { return new SearchParamRegistryImpl(); }
|
||||
@Bean
|
||||
SearchParameterCanonicalizer searchParameterCanonicalizer(FhirContext theFhirContext) {
|
||||
return new SearchParameterCanonicalizer(theFhirContext);
|
||||
}
|
||||
}
|
||||
|
||||
private int myAnswerCount = 0;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
|
@ -42,56 +69,40 @@ public class SearchParamRegistryImplTest {
|
|||
public void testRefreshAfterExpiry() {
|
||||
when(mySearchParamProvider.search(any())).thenReturn(new SimpleBundleProvider());
|
||||
|
||||
SearchParamRegistryImpl registry = new SearchParamRegistryImpl();
|
||||
registry.setSchedulerServiceForUnitTest(mySchedulerService);
|
||||
registry.setFhirContextForUnitTest(FhirContext.forR4());
|
||||
registry.setSearchParamProviderForUnitTest(mySearchParamProvider);
|
||||
registry.postConstruct();
|
||||
|
||||
registry.requestRefresh();
|
||||
assertEquals(146, registry.doRefresh(100000));
|
||||
mySearchParamRegistry.requestRefresh();
|
||||
assertEquals(146, mySearchParamRegistry.doRefresh(100000));
|
||||
|
||||
// Second time we don't need to run because we ran recently
|
||||
assertEquals(0, registry.doRefresh(100000));
|
||||
assertEquals(0, mySearchParamRegistry.doRefresh(100000));
|
||||
|
||||
assertEquals(146, registry.getActiveSearchParams().size());
|
||||
assertEquals(146, mySearchParamRegistry.getActiveSearchParams().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshCacheIfNecessary() {
|
||||
SearchParamRegistryImpl registry = new SearchParamRegistryImpl();
|
||||
|
||||
when(mySearchParamProvider.search(any())).thenReturn(new SimpleBundleProvider());
|
||||
when(mySearchParamProvider.refreshCache(any(), anyLong())).thenAnswer(t -> {
|
||||
registry.doRefresh(t.getArgument(1, Long.class));
|
||||
mySearchParamRegistry.doRefresh(t.getArgument(1, Long.class));
|
||||
return 0;
|
||||
});
|
||||
|
||||
registry.setSchedulerServiceForUnitTest(mySchedulerService);
|
||||
registry.setFhirContextForUnitTest(FhirContext.forR4());
|
||||
registry.setSearchParamProviderForUnitTest(mySearchParamProvider);
|
||||
registry.postConstruct();
|
||||
registry.requestRefresh();
|
||||
mySearchParamRegistry.requestRefresh();
|
||||
|
||||
assertTrue(registry.refreshCacheIfNecessary());
|
||||
assertFalse(registry.refreshCacheIfNecessary());
|
||||
assertTrue(mySearchParamRegistry.refreshCacheIfNecessary());
|
||||
assertFalse(mySearchParamRegistry.refreshCacheIfNecessary());
|
||||
|
||||
registry.requestRefresh();
|
||||
assertTrue(registry.refreshCacheIfNecessary());
|
||||
mySearchParamRegistry.requestRefresh();
|
||||
assertTrue(mySearchParamRegistry.refreshCacheIfNecessary());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetActiveUniqueSearchParams_Empty() {
|
||||
SearchParamRegistryImpl registry = new SearchParamRegistryImpl();
|
||||
assertThat(registry.getActiveUniqueSearchParams("Patient"), Matchers.empty());
|
||||
assertThat(mySearchParamRegistry.getActiveUniqueSearchParams("Patient"), Matchers.empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetActiveSearchParams() {
|
||||
SearchParamRegistryImpl registry = new SearchParamRegistryImpl();
|
||||
registry.setFhirContextForUnitTest(FhirContext.forR4());
|
||||
registry.postConstruct();
|
||||
|
||||
when(mySearchParamProvider.search(any())).thenReturn(new SimpleBundleProvider());
|
||||
when(mySearchParamProvider.refreshCache(any(), anyLong())).thenAnswer(t -> {
|
||||
if (myAnswerCount == 0) {
|
||||
|
@ -99,21 +110,16 @@ public class SearchParamRegistryImplTest {
|
|||
throw new InternalErrorException("this is an error!");
|
||||
}
|
||||
|
||||
registry.doRefresh(0);
|
||||
mySearchParamRegistry.doRefresh(0);
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
registry.setSearchParamProviderForUnitTest(mySearchParamProvider);
|
||||
Map<String, RuntimeSearchParam> outcome = registry.getActiveSearchParams("Patient");
|
||||
Map<String, RuntimeSearchParam> outcome = mySearchParamRegistry.getActiveSearchParams("Patient");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractExtensions() {
|
||||
SearchParamRegistryImpl registry = new SearchParamRegistryImpl();
|
||||
registry.setFhirContextForUnitTest(FhirContext.forR4());
|
||||
registry.postConstruct();
|
||||
|
||||
SearchParameter searchParameter = new SearchParameter();
|
||||
searchParameter.setCode("foo");
|
||||
searchParameter.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
|
@ -129,12 +135,12 @@ public class SearchParamRegistryImplTest {
|
|||
|
||||
when(mySearchParamProvider.search(any())).thenReturn(new SimpleBundleProvider(searchParameter));
|
||||
when(mySearchParamProvider.refreshCache(any(), anyLong())).thenAnswer(t -> {
|
||||
registry.doRefresh(0);
|
||||
mySearchParamRegistry.doRefresh(0);
|
||||
return 0;
|
||||
});
|
||||
|
||||
registry.setSearchParamProviderForUnitTest(mySearchParamProvider);
|
||||
Map<String, RuntimeSearchParam> outcome = registry.getActiveSearchParams("Patient");
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
Map<String, RuntimeSearchParam> outcome = mySearchParamRegistry.getActiveSearchParams("Patient");
|
||||
|
||||
RuntimeSearchParam converted = outcome.get("foo");
|
||||
assertNotNull(converted);
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.springframework.context.annotation.Bean;
|
|||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
|
@ -93,8 +94,9 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Primary
|
||||
@Bean
|
||||
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
|
||||
public JpaTransactionManager hapiTransactionManager(EntityManagerFactory entityManagerFactory) {
|
||||
JpaTransactionManager retVal = new JpaTransactionManager();
|
||||
retVal.setEntityManagerFactory(entityManagerFactory);
|
||||
return retVal;
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.springframework.context.annotation.Bean;
|
|||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
|
@ -161,7 +162,8 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
|||
// }
|
||||
|
||||
@Bean
|
||||
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
|
||||
@Primary
|
||||
public JpaTransactionManager hapiTransactionManager(EntityManagerFactory entityManagerFactory) {
|
||||
JpaTransactionManager retVal = new JpaTransactionManager();
|
||||
retVal.setEntityManagerFactory(entityManagerFactory);
|
||||
return retVal;
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.springframework.context.annotation.Bean;
|
|||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
|
@ -155,7 +156,8 @@ public class TestR4Config extends BaseJavaConfigR4 {
|
|||
}
|
||||
|
||||
@Bean
|
||||
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
|
||||
@Primary
|
||||
public JpaTransactionManager hapiTransactionManager(EntityManagerFactory entityManagerFactory) {
|
||||
JpaTransactionManager retVal = new JpaTransactionManager();
|
||||
retVal.setEntityManagerFactory(entityManagerFactory);
|
||||
return retVal;
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.springframework.context.annotation.Bean;
|
|||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
|
@ -155,7 +156,8 @@ public class TestR5Config extends BaseJavaConfigR5 {
|
|||
}
|
||||
|
||||
@Bean
|
||||
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
|
||||
@Primary
|
||||
public JpaTransactionManager hapiTransactionManager(EntityManagerFactory entityManagerFactory) {
|
||||
JpaTransactionManager retVal = new JpaTransactionManager();
|
||||
retVal.setEntityManagerFactory(entityManagerFactory);
|
||||
return retVal;
|
||||
|
|
|
@ -21,14 +21,13 @@ package ca.uhn.fhir.empi.rules.metric;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.empi.rules.metric.matcher.DoubleMetaphoneStringMatcher;
|
||||
import ca.uhn.fhir.context.phonetic.PhoneticEncoderEnum;
|
||||
import ca.uhn.fhir.empi.rules.metric.matcher.EmpiPersonNameMatchModeEnum;
|
||||
import ca.uhn.fhir.empi.rules.metric.matcher.HapiDateMatcher;
|
||||
import ca.uhn.fhir.empi.rules.metric.matcher.HapiStringMatcher;
|
||||
import ca.uhn.fhir.empi.rules.metric.matcher.IEmpiFieldMatcher;
|
||||
import ca.uhn.fhir.empi.rules.metric.matcher.MetaphoneStringMatcher;
|
||||
import ca.uhn.fhir.empi.rules.metric.matcher.NameMatcher;
|
||||
import ca.uhn.fhir.empi.rules.metric.matcher.StringEncoderMatcher;
|
||||
import ca.uhn.fhir.empi.rules.metric.matcher.PhoneticEncoderMatcher;
|
||||
import ca.uhn.fhir.empi.rules.metric.matcher.SubstringStringMatcher;
|
||||
import ca.uhn.fhir.empi.rules.metric.similarity.HapiStringSimilarity;
|
||||
import ca.uhn.fhir.empi.rules.metric.similarity.IEmpiFieldSimilarity;
|
||||
|
@ -37,9 +36,6 @@ import info.debatty.java.stringsimilarity.Jaccard;
|
|||
import info.debatty.java.stringsimilarity.JaroWinkler;
|
||||
import info.debatty.java.stringsimilarity.NormalizedLevenshtein;
|
||||
import info.debatty.java.stringsimilarity.SorensenDice;
|
||||
import org.apache.commons.codec.language.Caverphone1;
|
||||
import org.apache.commons.codec.language.Caverphone2;
|
||||
import org.apache.commons.codec.language.Soundex;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -49,13 +45,19 @@ import javax.annotation.Nullable;
|
|||
* calculating differences between strings (https://en.wikipedia.org/wiki/String_metric)
|
||||
*/
|
||||
public enum EmpiMetricEnum {
|
||||
CAVERPHONE1(new HapiStringMatcher(new PhoneticEncoderMatcher(PhoneticEncoderEnum.CAVERPHONE1))),
|
||||
CAVERPHONE2(new HapiStringMatcher(new PhoneticEncoderMatcher(PhoneticEncoderEnum.CAVERPHONE2))),
|
||||
COLOGNE(new HapiStringMatcher(new PhoneticEncoderMatcher(PhoneticEncoderEnum.COLOGNE))),
|
||||
DOUBLE_METAPHONE(new HapiStringMatcher(new PhoneticEncoderMatcher(PhoneticEncoderEnum.DOUBLE_METAPHONE))),
|
||||
MATCH_RATING_APPROACH(new HapiStringMatcher(new PhoneticEncoderMatcher(PhoneticEncoderEnum.MATCH_RATING_APPROACH))),
|
||||
METAPHONE(new HapiStringMatcher(new PhoneticEncoderMatcher(PhoneticEncoderEnum.METAPHONE))),
|
||||
NYSIIS(new HapiStringMatcher(new PhoneticEncoderMatcher(PhoneticEncoderEnum.NYSIIS))),
|
||||
REFINED_SOUNDEX(new HapiStringMatcher(new PhoneticEncoderMatcher(PhoneticEncoderEnum.REFINED_SOUNDEX))),
|
||||
SOUNDEX(new HapiStringMatcher(new PhoneticEncoderMatcher(PhoneticEncoderEnum.SOUNDEX))),
|
||||
|
||||
STRING(new HapiStringMatcher()),
|
||||
SUBSTRING(new HapiStringMatcher(new SubstringStringMatcher())),
|
||||
METAPHONE(new HapiStringMatcher(new MetaphoneStringMatcher())),
|
||||
DOUBLE_METAPHONE(new HapiStringMatcher(new DoubleMetaphoneStringMatcher())),
|
||||
SOUNDEX(new HapiStringMatcher(new StringEncoderMatcher(new Soundex()))),
|
||||
CAVERPHONE1(new HapiStringMatcher(new StringEncoderMatcher(new Caverphone1()))),
|
||||
CAVERPHONE2(new HapiStringMatcher(new StringEncoderMatcher(new Caverphone2()))),
|
||||
|
||||
DATE(new HapiDateMatcher()),
|
||||
JARO_WINKLER(new HapiStringSimilarity(new JaroWinkler())),
|
||||
COSINE(new HapiStringSimilarity(new Cosine())),
|
||||
|
|
|
@ -20,11 +20,22 @@ package ca.uhn.fhir.empi.rules.metric.matcher;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import org.apache.commons.codec.language.DoubleMetaphone;
|
||||
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
|
||||
import ca.uhn.fhir.context.phonetic.PhoneticEncoderEnum;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class PhoneticEncoderMatcher implements IEmpiStringMatcher {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(PhoneticEncoderMatcher.class);
|
||||
|
||||
private final IPhoneticEncoder myStringEncoder;
|
||||
|
||||
public PhoneticEncoderMatcher(PhoneticEncoderEnum thePhoneticEnum) {
|
||||
myStringEncoder = thePhoneticEnum.getPhoneticEncoder();
|
||||
}
|
||||
|
||||
public class DoubleMetaphoneStringMatcher implements IEmpiStringMatcher {
|
||||
@Override
|
||||
public boolean matches(String theLeftString, String theRightString) {
|
||||
return new DoubleMetaphone().isDoubleMetaphoneEqual(theLeftString, theRightString);
|
||||
return myStringEncoder.encode(theLeftString).equals(myStringEncoder.encode(theRightString));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue