Merge branch 'master' into batch-empi-job
This commit is contained in:
commit
19f3b7b121
|
@ -0,0 +1,51 @@
|
||||||
|
name: "Code scanning - action"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 8 * * 1'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
CodeQL-Build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
# We must fetch at least the immediate parents so that if this is
|
||||||
|
# a pull request then we can checkout the head.
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
# If this run was triggered by a pull request event, then checkout
|
||||||
|
# the head of the pull request instead of the merge commit.
|
||||||
|
- run: git checkout HEAD^2
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v1
|
||||||
|
# Override language selection by uncommenting this and choosing your languages
|
||||||
|
# with:
|
||||||
|
# languages: go, javascript, csharp, python, cpp, java
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v1
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 https://git.io/JvXDl
|
||||||
|
|
||||||
|
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||||
|
# and modify them (or add more) to build your code if your project
|
||||||
|
# uses a compiled language
|
||||||
|
|
||||||
|
#- run: |
|
||||||
|
# make bootstrap
|
||||||
|
# make release
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v1
|
|
@ -44,7 +44,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>mysql</groupId>
|
<groupId>mysql</groupId>
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
<version>6.0.5</version>
|
<version>8.0.16</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- This dependency includes the core HAPI-FHIR classes -->
|
<!-- This dependency includes the core HAPI-FHIR classes -->
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
<groupId>mysql</groupId>
|
<groupId>mysql</groupId>
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
<!-- <version>6.0.5</version>-->
|
<!-- <version>6.0.5</version>-->
|
||||||
<version>5.1.40</version>
|
<version>8.0.16</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!--
|
<!--
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -21,13 +21,32 @@ package ca.uhn.fhir.context;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam.RuntimeSearchParamStatusEnum;
|
import ca.uhn.fhir.context.RuntimeSearchParam.RuntimeSearchParamStatusEnum;
|
||||||
import ca.uhn.fhir.model.api.*;
|
import ca.uhn.fhir.model.api.BaseIdentifiableElement;
|
||||||
import ca.uhn.fhir.model.api.annotation.*;
|
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.BoundCodeDt;
|
||||||
import ca.uhn.fhir.model.primitive.XhtmlDt;
|
import ca.uhn.fhir.model.primitive.XhtmlDt;
|
||||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||||
import ca.uhn.fhir.util.ReflectionUtil;
|
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 javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -37,8 +56,18 @@ import java.lang.reflect.AnnotatedElement;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
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.Map.Entry;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
|
||||||
|
@ -390,7 +419,7 @@ class ModelScanner {
|
||||||
for (String nextName : searchParam.compositeOf()) {
|
for (String nextName : searchParam.compositeOf()) {
|
||||||
RuntimeSearchParam param = nameToParam.get(nextName);
|
RuntimeSearchParam param = nameToParam.get(nextName);
|
||||||
if (param == null) {
|
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());
|
theResourceDef.getName(), searchParam.name(), nextName, nameToParam.keySet());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,13 @@ package ca.uhn.fhir.context;
|
||||||
* #L%
|
* #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.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
@ -28,15 +35,6 @@ import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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> {
|
public class RuntimeResourceDefinition extends BaseRuntimeElementCompositeDefinition<IBaseResource> {
|
||||||
|
|
||||||
private Class<? extends IBaseResource> myBaseType;
|
private Class<? extends IBaseResource> myBaseType;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package ca.uhn.fhir.context;
|
package ca.uhn.fhir.context;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
|
||||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||||
|
@ -55,6 +56,7 @@ public class RuntimeSearchParam {
|
||||||
private final RuntimeSearchParamStatusEnum myStatus;
|
private final RuntimeSearchParamStatusEnum myStatus;
|
||||||
private final String myUri;
|
private final String myUri;
|
||||||
private final Map<String, List<IBaseExtension<?, ?>>> myExtensions = new HashMap<>();
|
private final Map<String, List<IBaseExtension<?, ?>>> myExtensions = new HashMap<>();
|
||||||
|
private IPhoneticEncoder myPhoneticEncoder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -245,7 +247,6 @@ public class RuntimeSearchParam {
|
||||||
return myProvidesMembershipInCompartments;
|
return myProvidesMembershipInCompartments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public enum RuntimeSearchParamStatusEnum {
|
public enum RuntimeSearchParamStatusEnum {
|
||||||
ACTIVE,
|
ACTIVE,
|
||||||
DRAFT,
|
DRAFT,
|
||||||
|
@ -253,4 +254,15 @@ public class RuntimeSearchParam {
|
||||||
UNKNOWN
|
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
|
* #%L
|
||||||
* HAPI FHIR - Enterprise Master Patient Index
|
* HAPI FHIR - Core Library
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2014 - 2020 University Health Network
|
* Copyright (C) 2014 - 2020 University Health Network
|
||||||
* %%
|
* %%
|
||||||
|
@ -25,22 +25,29 @@ import org.apache.commons.codec.StringEncoder;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class StringEncoderMatcher implements IEmpiStringMatcher {
|
public class ApacheEncoder implements IPhoneticEncoder {
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(StringEncoderMatcher.class);
|
private static final Logger ourLog = LoggerFactory.getLogger(ApacheEncoder.class);
|
||||||
|
|
||||||
|
private final String myName;
|
||||||
private final StringEncoder myStringEncoder;
|
private final StringEncoder myStringEncoder;
|
||||||
|
|
||||||
public StringEncoderMatcher(StringEncoder theStringEncoder) {
|
public ApacheEncoder(String theName, StringEncoder theStringEncoder) {
|
||||||
|
myName = theName;
|
||||||
myStringEncoder = theStringEncoder;
|
myStringEncoder = theStringEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(String theLeftString, String theRightString) {
|
public String name() {
|
||||||
|
return myName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String encode(String theString) {
|
||||||
try {
|
try {
|
||||||
return myStringEncoder.encode(theLeftString).equals(myStringEncoder.encode(theRightString));
|
return myStringEncoder.encode(theString);
|
||||||
} catch (EncoderException e) {
|
} 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
|
* #%L
|
||||||
* HAPI FHIR - Enterprise Master Patient Index
|
* HAPI FHIR - Core Library
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2014 - 2020 University Health Network
|
* Copyright (C) 2014 - 2020 University Health Network
|
||||||
* %%
|
* %%
|
||||||
|
@ -20,11 +20,13 @@ package ca.uhn.fhir.empi.rules.metric.matcher;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import org.apache.commons.codec.language.Metaphone;
|
public interface IPhoneticEncoder {
|
||||||
|
String name();
|
||||||
|
|
||||||
public class MetaphoneStringMatcher implements IEmpiStringMatcher {
|
/**
|
||||||
@Override
|
* Encode the provided string using a phonetic encoder like Soundex
|
||||||
public boolean matches(String theLeftString, String theRightString) {
|
* @param theString
|
||||||
return new Metaphone().isMetaphoneEqual(theLeftString, theRightString);
|
* @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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -252,15 +252,6 @@ public class Constants {
|
||||||
* Operation name for the $lastn operation
|
* Operation name for the $lastn operation
|
||||||
*/
|
*/
|
||||||
public static final String OPERATION_LASTN = "$lastn";
|
public static final String OPERATION_LASTN = "$lastn";
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* This extension represents the equivalent of the
|
|
||||||
* <code>Resource.meta.source</code> field within R4+ resources, and is for
|
|
||||||
* use in DSTU3 resources. It should contain a value of type <code>uri</code>
|
|
||||||
* and will be located on the Resource.meta
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public static final String EXT_META_SOURCE = "http://hapifhir.io/fhir/StructureDefinition/resource-meta-source";
|
|
||||||
public static final String PARAM_FHIRPATH = "_fhirpath";
|
public static final String PARAM_FHIRPATH = "_fhirpath";
|
||||||
public static final String PARAM_TYPE = "_type";
|
public static final String PARAM_TYPE = "_type";
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.IntegerDt;
|
import ca.uhn.fhir.model.primitive.IntegerDt;
|
||||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.QualifiedParamList;
|
import ca.uhn.fhir.rest.api.QualifiedParamList;
|
||||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||||
import ca.uhn.fhir.rest.param.binder.QueryParameterAndBinder;
|
import ca.uhn.fhir.rest.param.binder.QueryParameterAndBinder;
|
||||||
|
@ -386,4 +387,10 @@ public class ParameterUtil {
|
||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the value is :iterate or :recurse (the former name of :iterate) for an _include parameter
|
||||||
|
*/
|
||||||
|
public static boolean isIncludeIterate(String theQualifier) {
|
||||||
|
return Constants.PARAM_INCLUDE_QUALIFIER_RECURSE.equals(theQualifier) || Constants.PARAM_INCLUDE_QUALIFIER_ITERATE.equals(theQualifier);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
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 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* This extension should be of type <code>string</code> and should be
|
||||||
|
* placed on the <code>Subscription.channel</code> element
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public static final String EXT_SUBSCRIPTION_SUBJECT_TEMPLATE = "http://hapifhir.io/fhir/StructureDefinition/subscription-email-subject-template";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This extension URL indicates whether a REST HOOK delivery should
|
||||||
|
* include the version ID when delivering.
|
||||||
|
* <p>
|
||||||
|
* This extension should be of type <code>boolean</code> and should be
|
||||||
|
* placed on the <code>Subscription.channel</code> element.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public static final String EXT_SUBSCRIPTION_RESTHOOK_STRIP_VERSION_IDS = "http://hapifhir.io/fhir/StructureDefinition/subscription-resthook-strip-version-ids";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This extension URL indicates whether a REST HOOK delivery should
|
||||||
|
* reload the resource and deliver the latest version always. This
|
||||||
|
* could be useful for example if a resource which triggers a
|
||||||
|
* subscription gets updated many times in short succession and there
|
||||||
|
* is no value in delivering the older versions.
|
||||||
|
* <p>
|
||||||
|
* Note that if the resource is now deleted, this may cause
|
||||||
|
* the delivery to be cancelled altogether.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This extension should be of type <code>boolean</code> and should be
|
||||||
|
* placed on the <code>Subscription.channel</code> element.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public static final String EXT_SUBSCRIPTION_RESTHOOK_DELIVER_LATEST_VERSION = "http://hapifhir.io/fhir/StructureDefinition/subscription-resthook-deliver-latest-version";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate which strategy will be used to match this subscription
|
||||||
|
*/
|
||||||
|
public static final String EXT_SUBSCRIPTION_MATCHING_STRATEGY = "http://hapifhir.io/fhir/StructureDefinition/subscription-matching-strategy";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* This extension should be of type <code>string</code> and should be
|
||||||
|
* placed on the <code>Subscription.channel</code> element
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public static final String EXT_SUBSCRIPTION_EMAIL_FROM = "http://hapifhir.io/fhir/StructureDefinition/subscription-email-from";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension ID for external binary references
|
||||||
|
*/
|
||||||
|
public static final String EXT_EXTERNALIZED_BINARY_ID = "http://hapifhir.io/fhir/StructureDefinition/externalized-binary-id";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For subscription, deliver a bundle containing a search result instead of just a single resource
|
||||||
|
*/
|
||||||
|
public static final String EXT_SUBSCRIPTION_PAYLOAD_SEARCH_CRITERIA = "http://hapifhir.io/fhir/StructureDefinition/subscription-payload-search-criteria";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message added to expansion valueset
|
||||||
|
*/
|
||||||
|
public static final String EXT_VALUESET_EXPANSION_MESSAGE = "http://hapifhir.io/fhir/StructureDefinition/valueset-expansion-message";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension URL for extension on a SearchParameter indicating that text values should not be indexed
|
||||||
|
*/
|
||||||
|
public static final String EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING = "http://hapifhir.io/fhir/StructureDefinition/searchparameter-token-suppress-text-index";
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* This extension represents the equivalent of the
|
||||||
|
* <code>Resource.meta.source</code> field within R4+ resources, and is for
|
||||||
|
* use in DSTU3 resources. It should contain a value of type <code>uri</code>
|
||||||
|
* and will be located on the Resource.meta
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public static final String EXT_META_SOURCE = "http://hapifhir.io/fhir/StructureDefinition/resource-meta-source";
|
||||||
|
public static final String EXT_SP_UNIQUE = "http://hapifhir.io/fhir/StructureDefinition/sp-unique";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Non instantiable
|
||||||
|
*/
|
||||||
|
private HapiExtensions() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -24,7 +24,6 @@ import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
||||||
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
|
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBase;
|
import org.hl7.fhir.instance.model.api.IBase;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseExtension;
|
import org.hl7.fhir.instance.model.api.IBaseExtension;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
|
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
|
||||||
|
@ -58,7 +57,7 @@ public class MetaUtil {
|
||||||
IBaseHasExtensions metaWithExtensions = theMeta;
|
IBaseHasExtensions metaWithExtensions = theMeta;
|
||||||
List<? extends IBaseExtension<?, ?>> extensions = metaWithExtensions.getExtension();
|
List<? extends IBaseExtension<?, ?>> extensions = metaWithExtensions.getExtension();
|
||||||
for (IBaseExtension extension : extensions) {
|
for (IBaseExtension extension : extensions) {
|
||||||
if (Constants.EXT_META_SOURCE.equals(extension.getUrl())) {
|
if (HapiExtensions.EXT_META_SOURCE.equals(extension.getUrl())) {
|
||||||
IPrimitiveType<String> value = (IPrimitiveType<String>) extension.getValue();
|
IPrimitiveType<String> value = (IPrimitiveType<String>) extension.getValue();
|
||||||
return value.getValueAsString();
|
return value.getValueAsString();
|
||||||
}
|
}
|
||||||
|
@ -96,7 +95,7 @@ public class MetaUtil {
|
||||||
MetaUtil.setSource(theContext, theResource.getMeta(), theValue);
|
MetaUtil.setSource(theContext, theResource.getMeta(), theValue);
|
||||||
} else if (theContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) {
|
} else if (theContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) {
|
||||||
IBaseExtension<?, ?> sourceExtension = ((IBaseHasExtensions) theResource.getMeta()).addExtension();
|
IBaseExtension<?, ?> sourceExtension = ((IBaseHasExtensions) theResource.getMeta()).addExtension();
|
||||||
sourceExtension.setUrl(Constants.EXT_META_SOURCE);
|
sourceExtension.setUrl(HapiExtensions.EXT_META_SOURCE);
|
||||||
IPrimitiveType<String> value = (IPrimitiveType<String>) theContext.getElementDefinition("uri").newInstance();
|
IPrimitiveType<String> value = (IPrimitiveType<String>) theContext.getElementDefinition("uri").newInstance();
|
||||||
value.setValue(theValue);
|
value.setValue(theValue);
|
||||||
sourceExtension.setValue(value);
|
sourceExtension.setValue(value);
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
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;
|
||||||
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBase;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
import org.thymeleaf.util.Validate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class can be used to build a Bundle resource to be used as a FHIR transaction.
|
||||||
|
*
|
||||||
|
* This is not yet complete, and doesn't support all FHIR features. <b>USE WITH CAUTION</b> as the API
|
||||||
|
* may change.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*/
|
||||||
|
public class TransactionBuilder {
|
||||||
|
|
||||||
|
private final FhirContext myContext;
|
||||||
|
private final IBaseBundle myBundle;
|
||||||
|
private final RuntimeResourceDefinition myBundleDef;
|
||||||
|
private final BaseRuntimeChildDefinition myEntryChild;
|
||||||
|
private final BaseRuntimeElementDefinition<?> myEntryDef;
|
||||||
|
private final BaseRuntimeChildDefinition myEntryResourceChild;
|
||||||
|
private final BaseRuntimeChildDefinition myEntryFullUrlChild;
|
||||||
|
private final BaseRuntimeChildDefinition myEntryRequestChild;
|
||||||
|
private final BaseRuntimeElementDefinition<?> myEntryRequestDef;
|
||||||
|
private final BaseRuntimeChildDefinition myEntryRequestUrlChild;
|
||||||
|
private final BaseRuntimeChildDefinition myEntryRequestMethodChild;
|
||||||
|
private final BaseRuntimeElementDefinition<?> myEntryRequestMethodDef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public TransactionBuilder(FhirContext theContext) {
|
||||||
|
myContext = theContext;
|
||||||
|
|
||||||
|
myBundleDef = myContext.getResourceDefinition("Bundle");
|
||||||
|
myBundle = (IBaseBundle) myBundleDef.newInstance();
|
||||||
|
|
||||||
|
BaseRuntimeChildDefinition typeChild = myBundleDef.getChildByName("type");
|
||||||
|
IPrimitiveType<?> type = (IPrimitiveType<?>) typeChild.getChildByName("type").newInstance(typeChild.getInstanceConstructorArguments());
|
||||||
|
type.setValueAsString("transaction");
|
||||||
|
typeChild.getMutator().setValue(myBundle, type);
|
||||||
|
|
||||||
|
myEntryChild = myBundleDef.getChildByName("entry");
|
||||||
|
myEntryDef = myEntryChild.getChildByName("entry");
|
||||||
|
|
||||||
|
myEntryResourceChild = myEntryDef.getChildByName("resource");
|
||||||
|
myEntryFullUrlChild = myEntryDef.getChildByName("fullUrl");
|
||||||
|
|
||||||
|
myEntryRequestChild = myEntryDef.getChildByName("request");
|
||||||
|
myEntryRequestDef = myEntryRequestChild.getChildByName("request");
|
||||||
|
|
||||||
|
myEntryRequestUrlChild = myEntryRequestDef.getChildByName("url");
|
||||||
|
|
||||||
|
myEntryRequestMethodChild = myEntryRequestDef.getChildByName("method");
|
||||||
|
myEntryRequestMethodDef = myEntryRequestMethodChild.getChildByName("method");
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an entry containing an update (PUT) request
|
||||||
|
*
|
||||||
|
* @param theResource The resource to update
|
||||||
|
*/
|
||||||
|
public TransactionBuilder addUpdateEntry(IBaseResource theResource) {
|
||||||
|
Validate.notNull(theResource, "theResource must not be null");
|
||||||
|
Validate.notEmpty(theResource.getIdElement().getValue(), "theResource must have an ID");
|
||||||
|
|
||||||
|
IBase entry = myEntryDef.newInstance();
|
||||||
|
myEntryChild.getMutator().addValue(myBundle, entry);
|
||||||
|
|
||||||
|
// Bundle.entry.fullUrl
|
||||||
|
IPrimitiveType<?> fullUrl = (IPrimitiveType<?>) myContext.getElementDefinition("uri").newInstance();
|
||||||
|
fullUrl.setValueAsString(theResource.getIdElement().getValue());
|
||||||
|
myEntryFullUrlChild.getMutator().setValue(entry, fullUrl);
|
||||||
|
|
||||||
|
// Bundle.entry.resource
|
||||||
|
myEntryResourceChild.getMutator().setValue(entry, theResource);
|
||||||
|
|
||||||
|
// Bundle.entry.request
|
||||||
|
IBase request = myEntryRequestDef.newInstance();
|
||||||
|
myEntryRequestChild.getMutator().setValue(entry, request);
|
||||||
|
|
||||||
|
// Bundle.entry.request.url
|
||||||
|
IPrimitiveType<?> url = (IPrimitiveType<?>) myContext.getElementDefinition("uri").newInstance();
|
||||||
|
url.setValueAsString(theResource.getIdElement().toUnqualifiedVersionless().getValue());
|
||||||
|
myEntryRequestUrlChild.getMutator().setValue(request, url);
|
||||||
|
|
||||||
|
// Bundle.entry.request.url
|
||||||
|
IPrimitiveType<?> method = (IPrimitiveType<?>) myEntryRequestMethodDef.newInstance(myEntryRequestMethodChild.getInstanceConstructorArguments());
|
||||||
|
method.setValueAsString("PUT");
|
||||||
|
myEntryRequestMethodChild.getMutator().setValue(request, method);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public IBaseBundle getBundle() {
|
||||||
|
return myBundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 1936
|
||||||
|
title: "Phonetic name search is now supported via ISearchParamRegistry.setStringEncoder()."
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 1951
|
||||||
|
title: "REST Hook subscriptions may now specify a search expression to be used to fetch a collection of
|
||||||
|
resources to deliver when a subscription matches."
|
|
@ -158,46 +158,6 @@ The following metrics are currently supported:
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<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>
|
<tr>
|
||||||
<td>CAVERPHONE1</td>
|
<td>CAVERPHONE1</td>
|
||||||
<td>matcher</td>
|
<td>matcher</td>
|
||||||
|
@ -214,6 +174,78 @@ The following metrics are currently supported:
|
||||||
</td>
|
</td>
|
||||||
<td>Gail = Gael, Gail = Gale, Thomas != Tom</td>
|
<td>Gail = Gael, Gail = Gale, Thomas != Tom</td>
|
||||||
</tr>
|
</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>
|
<tr>
|
||||||
<td>DATE</td>
|
<td>DATE</td>
|
||||||
<td>matcher</td>
|
<td>matcher</td>
|
||||||
|
|
|
@ -4,8 +4,8 @@ import ca.uhn.fhir.jpa.api.model.WarmCacheEntry;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceEncodingEnum;
|
import ca.uhn.fhir.jpa.model.entity.ResourceEncodingEnum;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
|
|
||||||
import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
|
import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
|
@ -1417,7 +1417,7 @@ public class DaoConfig {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If set to <code>true</code> (default is <code>true</code>), indexes will be
|
* If set to <code>true</code> (default is <code>true</code>), indexes will be
|
||||||
* created for search parameters marked as {@link SearchParamConstants#EXT_SP_UNIQUE}.
|
* created for search parameters marked as {@link HapiExtensions#EXT_SP_UNIQUE}.
|
||||||
* This is a HAPI FHIR specific extension which can be used to specify that no more than one
|
* This is a HAPI FHIR specific extension which can be used to specify that no more than one
|
||||||
* resource can exist which matches a given criteria, using a database constraint to
|
* resource can exist which matches a given criteria, using a database constraint to
|
||||||
* enforce this.
|
* enforce this.
|
||||||
|
@ -1428,7 +1428,7 @@ public class DaoConfig {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If set to <code>true</code> (default is <code>true</code>), indexes will be
|
* If set to <code>true</code> (default is <code>true</code>), indexes will be
|
||||||
* created for search parameters marked as {@link SearchParamConstants#EXT_SP_UNIQUE}.
|
* created for search parameters marked as {@link HapiExtensions#EXT_SP_UNIQUE}.
|
||||||
* This is a HAPI FHIR specific extension which can be used to specify that no more than one
|
* This is a HAPI FHIR specific extension which can be used to specify that no more than one
|
||||||
* resource can exist which matches a given criteria, using a database constraint to
|
* resource can exist which matches a given criteria, using a database constraint to
|
||||||
* enforce this.
|
* enforce this.
|
||||||
|
|
|
@ -37,6 +37,7 @@ import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
import ca.uhn.fhir.util.AttachmentUtil;
|
import ca.uhn.fhir.util.AttachmentUtil;
|
||||||
import ca.uhn.fhir.util.BinaryUtil;
|
import ca.uhn.fhir.util.BinaryUtil;
|
||||||
import ca.uhn.fhir.util.DateUtils;
|
import ca.uhn.fhir.util.DateUtils;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
|
@ -209,11 +210,11 @@ public class BinaryAccessProvider {
|
||||||
theTarget
|
theTarget
|
||||||
.getTarget()
|
.getTarget()
|
||||||
.getExtension()
|
.getExtension()
|
||||||
.removeIf(t -> JpaConstants.EXT_EXTERNALIZED_BINARY_ID.equals(t.getUrl()));
|
.removeIf(t -> HapiExtensions.EXT_EXTERNALIZED_BINARY_ID.equals(t.getUrl()));
|
||||||
theTarget.setData(null);
|
theTarget.setData(null);
|
||||||
|
|
||||||
IBaseExtension<?, ?> ext = theTarget.getTarget().addExtension();
|
IBaseExtension<?, ?> ext = theTarget.getTarget().addExtension();
|
||||||
ext.setUrl(JpaConstants.EXT_EXTERNALIZED_BINARY_ID);
|
ext.setUrl(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID);
|
||||||
ext.setUserData(JpaConstants.EXTENSION_EXT_SYSTEMDEFINED, Boolean.TRUE);
|
ext.setUserData(JpaConstants.EXTENSION_EXT_SYSTEMDEFINED, Boolean.TRUE);
|
||||||
IPrimitiveType<String> blobIdString = (IPrimitiveType<String>) myCtx.getElementDefinition("string").newInstance();
|
IPrimitiveType<String> blobIdString = (IPrimitiveType<String>) myCtx.getElementDefinition("string").newInstance();
|
||||||
blobIdString.setValueAsString(theBlobId);
|
blobIdString.setValueAsString(theBlobId);
|
||||||
|
|
|
@ -31,6 +31,7 @@ import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||||
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
||||||
import ca.uhn.fhir.rest.api.server.IPreResourceShowDetails;
|
import ca.uhn.fhir.rest.api.server.IPreResourceShowDetails;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import ca.uhn.fhir.util.IModelVisitor2;
|
import ca.uhn.fhir.util.IModelVisitor2;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.hl7.fhir.instance.model.api.IBase;
|
import org.hl7.fhir.instance.model.api.IBase;
|
||||||
|
@ -56,7 +57,7 @@ import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static ca.uhn.fhir.jpa.model.util.JpaConstants.EXT_EXTERNALIZED_BINARY_ID;
|
import static ca.uhn.fhir.util.HapiExtensions.EXT_EXTERNALIZED_BINARY_ID;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
@Interceptor
|
@Interceptor
|
||||||
|
@ -106,7 +107,7 @@ public class BinaryStorageInterceptor {
|
||||||
List<String> attachmentIds = binaryElements
|
List<String> attachmentIds = binaryElements
|
||||||
.stream()
|
.stream()
|
||||||
.flatMap(t -> ((IBaseHasExtensions) t).getExtension().stream())
|
.flatMap(t -> ((IBaseHasExtensions) t).getExtension().stream())
|
||||||
.filter(t -> JpaConstants.EXT_EXTERNALIZED_BINARY_ID.equals(t.getUrl()))
|
.filter(t -> HapiExtensions.EXT_EXTERNALIZED_BINARY_ID.equals(t.getUrl()))
|
||||||
.map(t -> ((IPrimitiveType<?>) t.getValue()).getValueAsString())
|
.map(t -> ((IPrimitiveType<?>) t.getValue()).getValueAsString())
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ package ca.uhn.fhir.jpa.binstore;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
|
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ interface IBinaryTarget {
|
||||||
return getTarget()
|
return getTarget()
|
||||||
.getExtension()
|
.getExtension()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(t -> JpaConstants.EXT_EXTERNALIZED_BINARY_ID.equals(t.getUrl()))
|
.filter(t -> HapiExtensions.EXT_EXTERNALIZED_BINARY_ID.equals(t.getUrl()))
|
||||||
.filter(t -> t.getValue() instanceof IPrimitiveType)
|
.filter(t -> t.getValue() instanceof IPrimitiveType)
|
||||||
.map(t -> (IPrimitiveType<String>) t.getValue())
|
.map(t -> (IPrimitiveType<String>) t.getValue())
|
||||||
.map(t -> t.getValue())
|
.map(t -> t.getValue())
|
||||||
|
|
|
@ -83,6 +83,7 @@ import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
import ca.uhn.fhir.util.CoverageIgnore;
|
import ca.uhn.fhir.util.CoverageIgnore;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import ca.uhn.fhir.util.MetaUtil;
|
import ca.uhn.fhir.util.MetaUtil;
|
||||||
import ca.uhn.fhir.util.XmlUtil;
|
import ca.uhn.fhir.util.XmlUtil;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
@ -1130,7 +1131,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
||||||
source = ((IBaseHasExtensions) theResource.getMeta())
|
source = ((IBaseHasExtensions) theResource.getMeta())
|
||||||
.getExtension()
|
.getExtension()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(t -> Constants.EXT_META_SOURCE.equals(t.getUrl()))
|
.filter(t -> HapiExtensions.EXT_META_SOURCE.equals(t.getUrl()))
|
||||||
.filter(t -> t.getValue() instanceof IPrimitiveType)
|
.filter(t -> t.getValue() instanceof IPrimitiveType)
|
||||||
.map(t -> ((IPrimitiveType<?>) t.getValue()).getValueAsString())
|
.map(t -> ((IPrimitiveType<?>) t.getValue()).getValueAsString())
|
||||||
.findFirst()
|
.findFirst()
|
||||||
|
|
|
@ -21,7 +21,6 @@ package ca.uhn.fhir.jpa.dao.dstu3;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDaoObservation;
|
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDaoObservation;
|
||||||
import ca.uhn.fhir.jpa.dao.ObservationLastNIndexPersistSvc;
|
|
||||||
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
|
@ -32,16 +31,12 @@ import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.dstu3.model.Observation;
|
import org.hl7.fhir.dstu3.model.Observation;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
public class FhirResourceDaoObservationDstu3 extends BaseHapiFhirResourceDaoObservation<Observation> {
|
public class FhirResourceDaoObservationDstu3 extends BaseHapiFhirResourceDaoObservation<Observation> {
|
||||||
|
|
||||||
@Autowired
|
|
||||||
ObservationLastNIndexPersistSvc myObservationLastNIndexPersistSvc;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBundleProvider observationsLastN(SearchParameterMap theSearchParameterMap, RequestDetails theRequestDetails, HttpServletResponse theServletResponse) {
|
public IBundleProvider observationsLastN(SearchParameterMap theSearchParameterMap, RequestDetails theRequestDetails, HttpServletResponse theServletResponse) {
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.dao.predicate;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ import java.util.List;
|
||||||
public interface IPredicateBuilder {
|
public interface IPredicateBuilder {
|
||||||
@Nullable
|
@Nullable
|
||||||
Predicate addPredicate(String theResourceName,
|
Predicate addPredicate(String theResourceName,
|
||||||
String theParamName,
|
RuntimeSearchParam theSearchParam,
|
||||||
List<? extends IQueryParameterType> theList,
|
List<? extends IQueryParameterType> theList,
|
||||||
SearchFilterParser.CompareOperation operation,
|
SearchFilterParser.CompareOperation operation,
|
||||||
RequestPartitionId theRequestPartitionId);
|
RequestPartitionId theRequestPartitionId);
|
||||||
|
|
|
@ -20,13 +20,22 @@ package ca.uhn.fhir.jpa.dao.predicate;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
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.model.api.IQueryParameterType;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
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.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -56,40 +65,40 @@ public class PredicateBuilder {
|
||||||
myPredicateBuilderUri = thePredicateBuilderFactory.newPredicateBuilderUri(theSearchBuilder);
|
myPredicateBuilderUri = thePredicateBuilderFactory.newPredicateBuilderUri(theSearchBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addPredicateCoords(String theResourceName, String theParamName, List<? extends IQueryParameterType> theNextAnd, RequestPartitionId theRequestPartitionId) {
|
void addPredicateCoords(String theResourceName, RuntimeSearchParam theSearchParam, List<? extends IQueryParameterType> theNextAnd, RequestPartitionId theRequestPartitionId) {
|
||||||
myPredicateBuilderCoords.addPredicate(theResourceName, theParamName, theNextAnd, null, theRequestPartitionId);
|
myPredicateBuilderCoords.addPredicate(theResourceName, theSearchParam, theNextAnd, null, theRequestPartitionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Predicate addPredicateDate(String theResourceName, String theParamName, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
Predicate addPredicateDate(String theResourceName, RuntimeSearchParam theSearchParam, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||||
return myPredicateBuilderDate.addPredicate(theResourceName, theParamName, theNextAnd, theOperation, theRequestPartitionId);
|
return myPredicateBuilderDate.addPredicate(theResourceName, theSearchParam, theNextAnd, theOperation, theRequestPartitionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Predicate addPredicateNumber(String theResourceName, String theParamName, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
Predicate addPredicateNumber(String theResourceName, RuntimeSearchParam theSearchParam, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||||
return myPredicateBuilderNumber.addPredicate(theResourceName, theParamName, theNextAnd, theOperation, theRequestPartitionId);
|
return myPredicateBuilderNumber.addPredicate(theResourceName, theSearchParam, theNextAnd, theOperation, theRequestPartitionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Predicate addPredicateQuantity(String theResourceName, String theParamName, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
Predicate addPredicateQuantity(String theResourceName, RuntimeSearchParam theSearchParam, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||||
return myPredicateBuilderQuantity.addPredicate(theResourceName, theParamName, theNextAnd, theOperation, theRequestPartitionId);
|
return myPredicateBuilderQuantity.addPredicate(theResourceName, theSearchParam, theNextAnd, theOperation, theRequestPartitionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addPredicateString(String theResourceName, String theParamName, List<? extends IQueryParameterType> theNextAnd, RequestPartitionId theRequestPartitionId) {
|
void addPredicateString(String theResourceName, RuntimeSearchParam theSearchParam, List<? extends IQueryParameterType> theNextAnd, RequestPartitionId theRequestPartitionId) {
|
||||||
myPredicateBuilderString.addPredicate(theResourceName, theParamName, theNextAnd, SearchFilterParser.CompareOperation.sw, 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) {
|
Predicate addPredicateString(String theResourceName,RuntimeSearchParam theSearchParam, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||||
return myPredicateBuilderString.addPredicate(theResourceName, theParamName, theNextAnd, theOperation, theRequestPartitionId);
|
return myPredicateBuilderString.addPredicate(theResourceName, theSearchParam, theNextAnd, theOperation, theRequestPartitionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addPredicateTag(List<List<IQueryParameterType>> theAndOrParams, String theParamName, RequestPartitionId theRequestPartitionId) {
|
void addPredicateTag(List<List<IQueryParameterType>> theAndOrParams, String theParamName, RequestPartitionId theRequestPartitionId) {
|
||||||
myPredicateBuilderTag.addPredicateTag(theAndOrParams, theParamName, theRequestPartitionId);
|
myPredicateBuilderTag.addPredicateTag(theAndOrParams, theParamName, theRequestPartitionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Predicate addPredicateToken(String theResourceName, String theParamName, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
Predicate addPredicateToken(String theResourceName, RuntimeSearchParam theSearchParam, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||||
return myPredicateBuilderToken.addPredicate(theResourceName, theParamName, theNextAnd, theOperation, theRequestPartitionId);
|
return myPredicateBuilderToken.addPredicate(theResourceName, theSearchParam, theNextAnd, theOperation, theRequestPartitionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Predicate addPredicateUri(String theResourceName, String theName, List<? extends IQueryParameterType> theSingletonList, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
Predicate addPredicateUri(String theResourceName, RuntimeSearchParam theSearchParam, List<? extends IQueryParameterType> theSingletonList, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||||
return myPredicateBuilderUri.addPredicate(theResourceName, theName, theSingletonList, theOperation, theRequestPartitionId);
|
return myPredicateBuilderUri.addPredicate(theResourceName, theSearchParam, theSingletonList, theOperation, theRequestPartitionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void searchForIdsWithAndOr(String theResourceName, String theNextParamName, List<List<IQueryParameterType>> theAndOrParams, RequestDetails theRequest, RequestPartitionId 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);
|
return myPredicateBuilderResourceId.addPredicateResourceId(theValues, theResourceName, theOperation, theRequestPartitionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Predicate createPredicateString(IQueryParameterType theLeftValue, String theResourceName, String theName, CriteriaBuilder theBuilder, From<ResourceIndexedSearchParamString, ResourceIndexedSearchParamString> theStringJoin, RequestPartitionId theRequestPartitionId) {
|
Predicate createPredicateString(IQueryParameterType theLeftValue, String theResourceName, RuntimeSearchParam theSearchParam, CriteriaBuilder theBuilder, From<ResourceIndexedSearchParamString, ResourceIndexedSearchParamString> theStringJoin, RequestPartitionId theRequestPartitionId) {
|
||||||
return myPredicateBuilderString.createPredicateString(theLeftValue, theResourceName, theName, theBuilder, theStringJoin, 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) {
|
Collection<Predicate> createPredicateToken(List<IQueryParameterType> theTokens, String theResourceName, RuntimeSearchParam theSearchParam, CriteriaBuilder theBuilder, From<ResourceIndexedSearchParamToken, ResourceIndexedSearchParamToken> theTokenJoin, RequestPartitionId theRequestPartitionId) {
|
||||||
return myPredicateBuilderToken.createPredicateToken(theTokens, theResourceName, theName, theBuilder, theTokenJoin, 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) {
|
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%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords;
|
||||||
|
@ -55,7 +56,7 @@ public class PredicateBuilderCoords extends BasePredicateBuilder implements IPre
|
||||||
|
|
||||||
private Predicate createPredicateCoords(IQueryParameterType theParam,
|
private Predicate createPredicateCoords(IQueryParameterType theParam,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theParamName,
|
RuntimeSearchParam theSearchParam,
|
||||||
CriteriaBuilder theBuilder,
|
CriteriaBuilder theBuilder,
|
||||||
From<?, ResourceIndexedSearchParamCoords> theFrom,
|
From<?, ResourceIndexedSearchParamCoords> theFrom,
|
||||||
RequestPartitionId theRequestPartitionId) {
|
RequestPartitionId theRequestPartitionId) {
|
||||||
|
@ -119,7 +120,7 @@ public class PredicateBuilderCoords extends BasePredicateBuilder implements IPre
|
||||||
longitudePredicate = longitudePredicateFromBox(theBuilder, theFrom, box);
|
longitudePredicate = longitudePredicateFromBox(theBuilder, theFrom, box);
|
||||||
}
|
}
|
||||||
Predicate singleCode = theBuilder.and(latitudePredicate, longitudePredicate);
|
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) {
|
private Predicate latitudePredicateFromBox(CriteriaBuilder theBuilder, From<?, ResourceIndexedSearchParamCoords> theFrom, SearchBox theBox) {
|
||||||
|
@ -145,14 +146,14 @@ public class PredicateBuilderCoords extends BasePredicateBuilder implements IPre
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Predicate addPredicate(String theResourceName,
|
public Predicate addPredicate(String theResourceName,
|
||||||
String theParamName,
|
RuntimeSearchParam theSearchParam,
|
||||||
List<? extends IQueryParameterType> theList,
|
List<? extends IQueryParameterType> theList,
|
||||||
SearchFilterParser.CompareOperation theOperation,
|
SearchFilterParser.CompareOperation theOperation,
|
||||||
RequestPartitionId theRequestPartitionId) {
|
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) {
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +164,7 @@ public class PredicateBuilderCoords extends BasePredicateBuilder implements IPre
|
||||||
|
|
||||||
Predicate singleCode = createPredicateCoords(nextOr,
|
Predicate singleCode = createPredicateCoords(nextOr,
|
||||||
theResourceName,
|
theResourceName,
|
||||||
theParamName,
|
theSearchParam,
|
||||||
myCriteriaBuilder,
|
myCriteriaBuilder,
|
||||||
join,
|
join,
|
||||||
theRequestPartitionId);
|
theRequestPartitionId);
|
||||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.dao.predicate;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||||
|
@ -56,27 +57,28 @@ public class PredicateBuilderDate extends BasePredicateBuilder implements IPredi
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Predicate addPredicate(String theResourceName,
|
public Predicate addPredicate(String theResourceName,
|
||||||
String theParamName,
|
RuntimeSearchParam theSearchParam,
|
||||||
List<? extends IQueryParameterType> theList,
|
List<? extends IQueryParameterType> theList,
|
||||||
SearchFilterParser.CompareOperation operation,
|
SearchFilterParser.CompareOperation operation,
|
||||||
RequestPartitionId theRequestPartitionId) {
|
RequestPartitionId theRequestPartitionId) {
|
||||||
|
|
||||||
|
String paramName = theSearchParam.getName();
|
||||||
boolean newJoin = false;
|
boolean newJoin = false;
|
||||||
if (myJoinMap == null) {
|
if (myJoinMap == null) {
|
||||||
myJoinMap = new HashMap<>();
|
myJoinMap = new HashMap<>();
|
||||||
}
|
}
|
||||||
String key = theResourceName + " " + theParamName;
|
String key = theResourceName + " " + paramName;
|
||||||
|
|
||||||
From<?, ResourceIndexedSearchParamDate> join = myJoinMap.get(key);
|
From<?, ResourceIndexedSearchParamDate> join = myJoinMap.get(key);
|
||||||
if (join == null) {
|
if (join == null) {
|
||||||
join = myQueryStack.createJoin(SearchBuilderJoinEnum.DATE, theParamName);
|
join = myQueryStack.createJoin(SearchBuilderJoinEnum.DATE, paramName);
|
||||||
myJoinMap.put(key, join);
|
myJoinMap.put(key, join);
|
||||||
newJoin = true;
|
newJoin = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theList.get(0).getMissing() != null) {
|
if (theList.get(0).getMissing() != null) {
|
||||||
Boolean missing = theList.get(0).getMissing();
|
Boolean missing = theList.get(0).getMissing();
|
||||||
addPredicateParamMissingForNonReference(theResourceName, theParamName, missing, join, theRequestPartitionId);
|
addPredicateParamMissingForNonReference(theResourceName, paramName, missing, join, theRequestPartitionId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +96,7 @@ public class PredicateBuilderDate extends BasePredicateBuilder implements IPredi
|
||||||
Predicate orPredicates = myCriteriaBuilder.or(toArray(codePredicates));
|
Predicate orPredicates = myCriteriaBuilder.or(toArray(codePredicates));
|
||||||
|
|
||||||
if (newJoin) {
|
if (newJoin) {
|
||||||
Predicate identityAndValuePredicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, join, orPredicates, theRequestPartitionId);
|
Predicate identityAndValuePredicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, paramName, join, orPredicates, theRequestPartitionId);
|
||||||
myQueryStack.addPredicateWithImplicitTypeSelection(identityAndValuePredicate);
|
myQueryStack.addPredicateWithImplicitTypeSelection(identityAndValuePredicate);
|
||||||
} else {
|
} else {
|
||||||
myQueryStack.addPredicateWithImplicitTypeSelection(orPredicates);
|
myQueryStack.addPredicateWithImplicitTypeSelection(orPredicates);
|
||||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.dao.predicate;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
||||||
|
@ -51,15 +52,15 @@ class PredicateBuilderNumber extends BasePredicateBuilder implements IPredicateB
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Predicate addPredicate(String theResourceName,
|
public Predicate addPredicate(String theResourceName,
|
||||||
String theParamName,
|
RuntimeSearchParam theSearchParam,
|
||||||
List<? extends IQueryParameterType> theList,
|
List<? extends IQueryParameterType> theList,
|
||||||
SearchFilterParser.CompareOperation operation,
|
SearchFilterParser.CompareOperation operation,
|
||||||
RequestPartitionId theRequestPartitionId) {
|
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) {
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,8 +98,8 @@ class PredicateBuilderNumber extends BasePredicateBuilder implements IPredicateB
|
||||||
|
|
||||||
String invalidMessageName = "invalidNumberPrefix";
|
String invalidMessageName = "invalidNumberPrefix";
|
||||||
|
|
||||||
Predicate predicateNumeric = createPredicateNumeric(theResourceName, theParamName, join, myCriteriaBuilder, nextOr, prefix, value, fromObj, invalidMessageName, theRequestPartitionId);
|
Predicate predicateNumeric = createPredicateNumeric(theResourceName, theSearchParam.getName(), join, myCriteriaBuilder, nextOr, prefix, value, fromObj, invalidMessageName, theRequestPartitionId);
|
||||||
Predicate predicateOuter = combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, join, predicateNumeric, theRequestPartitionId);
|
Predicate predicateOuter = combineParamIndexPredicateWithParamNamePredicate(theResourceName, theSearchParam.getName(), join, predicateNumeric, theRequestPartitionId);
|
||||||
codePredicates.add(predicateOuter);
|
codePredicates.add(predicateOuter);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.dao.predicate;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
||||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||||
|
@ -52,15 +53,15 @@ class PredicateBuilderQuantity extends BasePredicateBuilder implements IPredicat
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Predicate addPredicate(String theResourceName,
|
public Predicate addPredicate(String theResourceName,
|
||||||
String theParamName,
|
RuntimeSearchParam theSearchParam,
|
||||||
List<? extends IQueryParameterType> theList,
|
List<? extends IQueryParameterType> theList,
|
||||||
SearchFilterParser.CompareOperation theOperation,
|
SearchFilterParser.CompareOperation theOperation,
|
||||||
RequestPartitionId theRequestPartitionId) {
|
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) {
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +69,7 @@ class PredicateBuilderQuantity extends BasePredicateBuilder implements IPredicat
|
||||||
addPartitionIdPredicate(theRequestPartitionId, join, codePredicates);
|
addPartitionIdPredicate(theRequestPartitionId, join, codePredicates);
|
||||||
|
|
||||||
for (IQueryParameterType nextOr : theList) {
|
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);
|
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.api.server.storage.ResourcePersistentId;
|
||||||
import ca.uhn.fhir.rest.param.CompositeParam;
|
import ca.uhn.fhir.rest.param.CompositeParam;
|
||||||
import ca.uhn.fhir.rest.param.DateParam;
|
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.HasParam;
|
||||||
import ca.uhn.fhir.rest.param.NumberParam;
|
import ca.uhn.fhir.rest.param.NumberParam;
|
||||||
import ca.uhn.fhir.rest.param.ParameterUtil;
|
import ca.uhn.fhir.rest.param.ParameterUtil;
|
||||||
|
@ -599,12 +598,12 @@ class PredicateBuilderReference extends BasePredicateBuilder {
|
||||||
switch (nextParamDef.getParamType()) {
|
switch (nextParamDef.getParamType()) {
|
||||||
case DATE:
|
case DATE:
|
||||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||||
myPredicateBuilder.addPredicateDate(theResourceName, theParamName, nextAnd, null, theRequestPartitionId);
|
myPredicateBuilder.addPredicateDate(theResourceName, nextParamDef, nextAnd, null, theRequestPartitionId);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case QUANTITY:
|
case QUANTITY:
|
||||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||||
myPredicateBuilder.addPredicateQuantity(theResourceName, theParamName, nextAnd, null, theRequestPartitionId);
|
myPredicateBuilder.addPredicateQuantity(theResourceName, nextParamDef, nextAnd, null, theRequestPartitionId);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case REFERENCE:
|
case REFERENCE:
|
||||||
|
@ -614,21 +613,21 @@ class PredicateBuilderReference extends BasePredicateBuilder {
|
||||||
break;
|
break;
|
||||||
case STRING:
|
case STRING:
|
||||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
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;
|
break;
|
||||||
case TOKEN:
|
case TOKEN:
|
||||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||||
if ("Location.position".equals(nextParamDef.getPath())) {
|
if ("Location.position".equals(nextParamDef.getPath())) {
|
||||||
myPredicateBuilder.addPredicateCoords(theResourceName, theParamName, nextAnd, theRequestPartitionId);
|
myPredicateBuilder.addPredicateCoords(theResourceName, nextParamDef, nextAnd, theRequestPartitionId);
|
||||||
} else {
|
} else {
|
||||||
myPredicateBuilder.addPredicateToken(theResourceName, theParamName, nextAnd, null, theRequestPartitionId);
|
myPredicateBuilder.addPredicateToken(theResourceName, nextParamDef, nextAnd, null, theRequestPartitionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NUMBER:
|
case NUMBER:
|
||||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||||
myPredicateBuilder.addPredicateNumber(theResourceName, theParamName, nextAnd, null, theRequestPartitionId);
|
myPredicateBuilder.addPredicateNumber(theResourceName, nextParamDef, nextAnd, null, theRequestPartitionId);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case COMPOSITE:
|
case COMPOSITE:
|
||||||
|
@ -638,14 +637,14 @@ class PredicateBuilderReference extends BasePredicateBuilder {
|
||||||
break;
|
break;
|
||||||
case URI:
|
case URI:
|
||||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
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;
|
break;
|
||||||
case HAS:
|
case HAS:
|
||||||
case SPECIAL:
|
case SPECIAL:
|
||||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||||
if ("Location.position".equals(nextParamDef.getPath())) {
|
if ("Location.position".equals(nextParamDef.getPath())) {
|
||||||
myPredicateBuilder.addPredicateCoords(theResourceName, theParamName, nextAnd, theRequestPartitionId);
|
myPredicateBuilder.addPredicateCoords(theResourceName, nextParamDef, nextAnd, theRequestPartitionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -755,13 +754,13 @@ class PredicateBuilderReference extends BasePredicateBuilder {
|
||||||
} else {
|
} else {
|
||||||
RestSearchParameterTypeEnum typeEnum = searchParam.getParamType();
|
RestSearchParameterTypeEnum typeEnum = searchParam.getParamType();
|
||||||
if (typeEnum == RestSearchParameterTypeEnum.URI) {
|
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) {
|
} 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) {
|
} 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) {
|
} 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) {
|
} else if (typeEnum == RestSearchParameterTypeEnum.REFERENCE) {
|
||||||
String paramName = theFilter.getParamPath().getName();
|
String paramName = theFilter.getParamPath().getName();
|
||||||
SearchFilterParser.CompareOperation operation = theFilter.getOperation();
|
SearchFilterParser.CompareOperation operation = theFilter.getOperation();
|
||||||
|
@ -771,7 +770,7 @@ class PredicateBuilderReference extends BasePredicateBuilder {
|
||||||
ReferenceParam referenceParam = new ReferenceParam(resourceType, chain, value);
|
ReferenceParam referenceParam = new ReferenceParam(resourceType, chain, value);
|
||||||
return addPredicate(theResourceName, paramName, Collections.singletonList(referenceParam), operation, theRequest, theRequestPartitionId);
|
return addPredicate(theResourceName, paramName, Collections.singletonList(referenceParam), operation, theRequest, theRequestPartitionId);
|
||||||
} else if (typeEnum == RestSearchParameterTypeEnum.QUANTITY) {
|
} 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) {
|
} else if (typeEnum == RestSearchParameterTypeEnum.COMPOSITE) {
|
||||||
throw new InvalidRequestException("Composite search parameters not currently supported with _filter clauses");
|
throw new InvalidRequestException("Composite search parameters not currently supported with _filter clauses");
|
||||||
} else if (typeEnum == RestSearchParameterTypeEnum.TOKEN) {
|
} else if (typeEnum == RestSearchParameterTypeEnum.TOKEN) {
|
||||||
|
@ -780,7 +779,7 @@ class PredicateBuilderReference extends BasePredicateBuilder {
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
theFilter.getValue());
|
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;
|
return null;
|
||||||
|
@ -1033,13 +1032,13 @@ class PredicateBuilderReference extends BasePredicateBuilder {
|
||||||
switch (theParam.getParamType()) {
|
switch (theParam.getParamType()) {
|
||||||
case STRING: {
|
case STRING: {
|
||||||
From<ResourceIndexedSearchParamString, ResourceIndexedSearchParamString> stringJoin = theRoot.join("myParamsString", JoinType.INNER);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case TOKEN: {
|
case TOKEN: {
|
||||||
From<ResourceIndexedSearchParamToken, ResourceIndexedSearchParamToken> tokenJoin = theRoot.join("myParamsToken", JoinType.INNER);
|
From<ResourceIndexedSearchParamToken, ResourceIndexedSearchParamToken> tokenJoin = theRoot.join("myParamsToken", JoinType.INNER);
|
||||||
List<IQueryParameterType> tokens = Collections.singletonList(leftValue);
|
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]));
|
retVal = myCriteriaBuilder.and(tokenPredicates.toArray(new Predicate[0]));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,8 @@ package ca.uhn.fhir.jpa.dao.predicate;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
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.dao.SearchBuilder;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||||
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
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.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
||||||
import ca.uhn.fhir.util.StringUtil;
|
import ca.uhn.fhir.util.StringUtil;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@ -44,25 +43,21 @@ import java.util.List;
|
||||||
@Component
|
@Component
|
||||||
@Scope("prototype")
|
@Scope("prototype")
|
||||||
class PredicateBuilderString extends BasePredicateBuilder implements IPredicateBuilder {
|
class PredicateBuilderString extends BasePredicateBuilder implements IPredicateBuilder {
|
||||||
|
|
||||||
@Autowired
|
|
||||||
DaoConfig myDaoConfig;
|
|
||||||
|
|
||||||
PredicateBuilderString(SearchBuilder theSearchBuilder) {
|
PredicateBuilderString(SearchBuilder theSearchBuilder) {
|
||||||
super(theSearchBuilder);
|
super(theSearchBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Predicate addPredicate(String theResourceName,
|
public Predicate addPredicate(String theResourceName,
|
||||||
String theParamName,
|
RuntimeSearchParam theSearchParam,
|
||||||
List<? extends IQueryParameterType> theList,
|
List<? extends IQueryParameterType> theList,
|
||||||
SearchFilterParser.CompareOperation theOperation,
|
SearchFilterParser.CompareOperation theOperation,
|
||||||
RequestPartitionId theRequestPartitionId) {
|
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) {
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +65,7 @@ class PredicateBuilderString extends BasePredicateBuilder implements IPredicateB
|
||||||
addPartitionIdPredicate(theRequestPartitionId, join, codePredicates);
|
addPartitionIdPredicate(theRequestPartitionId, join, codePredicates);
|
||||||
|
|
||||||
for (IQueryParameterType nextOr : theList) {
|
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);
|
codePredicates.add(singleCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,13 +78,13 @@ class PredicateBuilderString extends BasePredicateBuilder implements IPredicateB
|
||||||
|
|
||||||
public Predicate createPredicateString(IQueryParameterType theParameter,
|
public Predicate createPredicateString(IQueryParameterType theParameter,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theParamName,
|
RuntimeSearchParam theSearchParam,
|
||||||
CriteriaBuilder theBuilder,
|
CriteriaBuilder theBuilder,
|
||||||
From<?, ResourceIndexedSearchParamString> theFrom,
|
From<?, ResourceIndexedSearchParamString> theFrom,
|
||||||
RequestPartitionId theRequestPartitionId) {
|
RequestPartitionId theRequestPartitionId) {
|
||||||
return createPredicateString(theParameter,
|
return createPredicateString(theParameter,
|
||||||
theResourceName,
|
theResourceName,
|
||||||
theParamName,
|
theSearchParam,
|
||||||
theBuilder,
|
theBuilder,
|
||||||
theFrom,
|
theFrom,
|
||||||
null,
|
null,
|
||||||
|
@ -98,12 +93,13 @@ class PredicateBuilderString extends BasePredicateBuilder implements IPredicateB
|
||||||
|
|
||||||
private Predicate createPredicateString(IQueryParameterType theParameter,
|
private Predicate createPredicateString(IQueryParameterType theParameter,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theParamName,
|
RuntimeSearchParam theSearchParam,
|
||||||
CriteriaBuilder theBuilder,
|
CriteriaBuilder theBuilder,
|
||||||
From<?, ResourceIndexedSearchParamString> theFrom,
|
From<?, ResourceIndexedSearchParamString> theFrom,
|
||||||
SearchFilterParser.CompareOperation operation,
|
SearchFilterParser.CompareOperation operation,
|
||||||
RequestPartitionId theRequestPartitionId) {
|
RequestPartitionId theRequestPartitionId) {
|
||||||
String rawSearchTerm;
|
String rawSearchTerm;
|
||||||
|
String paramName = theSearchParam.getName();
|
||||||
if (theParameter instanceof TokenParam) {
|
if (theParameter instanceof TokenParam) {
|
||||||
TokenParam id = (TokenParam) theParameter;
|
TokenParam id = (TokenParam) theParameter;
|
||||||
if (!id.isText()) {
|
if (!id.isText()) {
|
||||||
|
@ -117,6 +113,8 @@ class PredicateBuilderString extends BasePredicateBuilder implements IPredicateB
|
||||||
if (!myDaoConfig.isAllowContainsSearches()) {
|
if (!myDaoConfig.isAllowContainsSearches()) {
|
||||||
throw new MethodNotAllowedException(":contains modifier is disabled on this server");
|
throw new MethodNotAllowedException(":contains modifier is disabled on this server");
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
rawSearchTerm = theSearchParam.encode(rawSearchTerm);
|
||||||
}
|
}
|
||||||
} else if (theParameter instanceof IPrimitiveDatatype<?>) {
|
} else if (theParameter instanceof IPrimitiveDatatype<?>) {
|
||||||
IPrimitiveDatatype<?> id = (IPrimitiveDatatype<?>) theParameter;
|
IPrimitiveDatatype<?> id = (IPrimitiveDatatype<?>) theParameter;
|
||||||
|
@ -126,7 +124,7 @@ class PredicateBuilderString extends BasePredicateBuilder implements IPredicateB
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rawSearchTerm.length() > ResourceIndexedSearchParamString.MAX_LENGTH) {
|
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);
|
+ ResourceIndexedSearchParamString.MAX_LENGTH + "): " + rawSearchTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,12 +150,12 @@ class PredicateBuilderString extends BasePredicateBuilder implements IPredicateB
|
||||||
singleCode = theBuilder.and(singleCode, exactCode);
|
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();
|
boolean exactMatch = theParameter instanceof StringParam && ((StringParam) theParameter).isExact();
|
||||||
if (exactMatch) {
|
if (exactMatch) {
|
||||||
// Exact match
|
// 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);
|
return theBuilder.equal(theFrom.get("myHashExact").as(Long.class), hash);
|
||||||
} else {
|
} else {
|
||||||
// Normalized Match
|
// Normalized Match
|
||||||
|
@ -185,34 +183,34 @@ class PredicateBuilderString extends BasePredicateBuilder implements IPredicateB
|
||||||
Predicate predicate;
|
Predicate predicate;
|
||||||
if ((operation == null) ||
|
if ((operation == null) ||
|
||||||
(operation == SearchFilterParser.CompareOperation.sw)) {
|
(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 hashCode = theBuilder.equal(theFrom.get("myHashNormalizedPrefix").as(Long.class), hash);
|
||||||
Predicate singleCode = theBuilder.like(theFrom.get("myValueNormalized").as(String.class), likeExpression);
|
Predicate singleCode = theBuilder.like(theFrom.get("myValueNormalized").as(String.class), likeExpression);
|
||||||
predicate = theBuilder.and(hashCode, singleCode);
|
predicate = theBuilder.and(hashCode, singleCode);
|
||||||
} else if ((operation == SearchFilterParser.CompareOperation.ew) ||
|
} else if ((operation == SearchFilterParser.CompareOperation.ew) ||
|
||||||
(operation == SearchFilterParser.CompareOperation.co)) {
|
(operation == SearchFilterParser.CompareOperation.co)) {
|
||||||
Predicate singleCode = theBuilder.like(theFrom.get("myValueNormalized").as(String.class), likeExpression);
|
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) {
|
} 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 hashCode = theBuilder.equal(theFrom.get("myHashNormalizedPrefix").as(Long.class), hash);
|
||||||
Predicate singleCode = theBuilder.like(theFrom.get("myValueNormalized").as(String.class), normalizedString);
|
Predicate singleCode = theBuilder.like(theFrom.get("myValueNormalized").as(String.class), normalizedString);
|
||||||
predicate = theBuilder.and(hashCode, singleCode);
|
predicate = theBuilder.and(hashCode, singleCode);
|
||||||
} else if (operation == SearchFilterParser.CompareOperation.ne) {
|
} else if (operation == SearchFilterParser.CompareOperation.ne) {
|
||||||
Predicate singleCode = theBuilder.notEqual(theFrom.get("myValueNormalized").as(String.class), likeExpression);
|
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) {
|
} else if (operation == SearchFilterParser.CompareOperation.gt) {
|
||||||
Predicate singleCode = theBuilder.greaterThan(theFrom.get("myValueNormalized").as(String.class), likeExpression);
|
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) {
|
} else if (operation == SearchFilterParser.CompareOperation.lt) {
|
||||||
Predicate singleCode = theBuilder.lessThan(theFrom.get("myValueNormalized").as(String.class), likeExpression);
|
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) {
|
} else if (operation == SearchFilterParser.CompareOperation.ge) {
|
||||||
Predicate singleCode = theBuilder.greaterThanOrEqualTo(theFrom.get("myValueNormalized").as(String.class), likeExpression);
|
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) {
|
} else if (operation == SearchFilterParser.CompareOperation.le) {
|
||||||
Predicate singleCode = theBuilder.lessThanOrEqualTo(theFrom.get("myValueNormalized").as(String.class), likeExpression);
|
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 {
|
} else {
|
||||||
throw new IllegalArgumentException("Don't yet know how to handle operation " + operation + " on a string");
|
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.BaseRuntimeChildDefinition;
|
||||||
import ca.uhn.fhir.context.BaseRuntimeDeclaredChildDefinition;
|
import ca.uhn.fhir.context.BaseRuntimeDeclaredChildDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
|
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
|
||||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
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.ModelConfig;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
||||||
import ca.uhn.fhir.jpa.searchparam.extractor.BaseSearchParamExtractor;
|
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.jpa.term.api.ITermReadSvc;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
||||||
|
@ -72,8 +70,6 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
||||||
@Autowired
|
@Autowired
|
||||||
private ITermReadSvc myTerminologySvc;
|
private ITermReadSvc myTerminologySvc;
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISearchParamRegistry mySearchParamRegistry;
|
|
||||||
@Autowired
|
|
||||||
private ModelConfig myModelConfig;
|
private ModelConfig myModelConfig;
|
||||||
|
|
||||||
PredicateBuilderToken(SearchBuilder theSearchBuilder, PredicateBuilder thePredicateBuilder) {
|
PredicateBuilderToken(SearchBuilder theSearchBuilder, PredicateBuilder thePredicateBuilder) {
|
||||||
|
@ -83,14 +79,14 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Predicate addPredicate(String theResourceName,
|
public Predicate addPredicate(String theResourceName,
|
||||||
String theParamName,
|
RuntimeSearchParam theSearchParam,
|
||||||
List<? extends IQueryParameterType> theList,
|
List<? extends IQueryParameterType> theList,
|
||||||
SearchFilterParser.CompareOperation theOperation,
|
SearchFilterParser.CompareOperation theOperation,
|
||||||
RequestPartitionId theRequestPartitionId) {
|
RequestPartitionId theRequestPartitionId) {
|
||||||
|
|
||||||
if (theList.get(0).getMissing() != null) {
|
if (theList.get(0).getMissing() != null) {
|
||||||
From<?, ResourceIndexedSearchParamToken> join = myQueryStack.createJoin(SearchBuilderJoinEnum.TOKEN, theParamName);
|
From<?, ResourceIndexedSearchParamToken> join = myQueryStack.createJoin(SearchBuilderJoinEnum.TOKEN, theSearchParam.getName());
|
||||||
addPredicateParamMissingForNonReference(theResourceName, theParamName, theList.get(0).getMissing(), join, theRequestPartitionId);
|
addPredicateParamMissingForNonReference(theResourceName, theSearchParam.getName(), theList.get(0).getMissing(), join, theRequestPartitionId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,8 +100,7 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
||||||
if (id.isText()) {
|
if (id.isText()) {
|
||||||
|
|
||||||
// Check whether the :text modifier is actually enabled here
|
// Check whether the :text modifier is actually enabled here
|
||||||
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam(theResourceName, theParamName);
|
boolean tokenTextIndexingEnabled = BaseSearchParamExtractor.tokenTextIndexingEnabledForSearchParam(myModelConfig, theSearchParam);
|
||||||
boolean tokenTextIndexingEnabled = BaseSearchParamExtractor.tokenTextIndexingEnabledForSearchParam(myModelConfig, param);
|
|
||||||
if (!tokenTextIndexingEnabled) {
|
if (!tokenTextIndexingEnabled) {
|
||||||
String msg;
|
String msg;
|
||||||
if (myModelConfig.isSuppressStringIndexingInTokens()) {
|
if (myModelConfig.isSuppressStringIndexingInTokens()) {
|
||||||
|
@ -116,7 +111,7 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
||||||
throw new MethodNotAllowedException(msg);
|
throw new MethodNotAllowedException(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
myPredicateBuilder.addPredicateString(theResourceName, theParamName, theList, theRequestPartitionId);
|
myPredicateBuilder.addPredicateString(theResourceName, theSearchParam, theList, theRequestPartitionId);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,10 +123,10 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
From<?, ResourceIndexedSearchParamToken> join = myQueryStack.createJoin(SearchBuilderJoinEnum.TOKEN, theParamName);
|
From<?, ResourceIndexedSearchParamToken> join = myQueryStack.createJoin(SearchBuilderJoinEnum.TOKEN, theSearchParam.getName());
|
||||||
addPartitionIdPredicate(theRequestPartitionId, join, codePredicates);
|
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;
|
assert singleCode != null;
|
||||||
codePredicates.addAll(singleCode);
|
codePredicates.addAll(singleCode);
|
||||||
|
|
||||||
|
@ -144,14 +139,14 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
||||||
|
|
||||||
public Collection<Predicate> createPredicateToken(Collection<IQueryParameterType> theParameters,
|
public Collection<Predicate> createPredicateToken(Collection<IQueryParameterType> theParameters,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theParamName,
|
RuntimeSearchParam theSearchParam,
|
||||||
CriteriaBuilder theBuilder,
|
CriteriaBuilder theBuilder,
|
||||||
From<?, ResourceIndexedSearchParamToken> theFrom,
|
From<?, ResourceIndexedSearchParamToken> theFrom,
|
||||||
RequestPartitionId theRequestPartitionId) {
|
RequestPartitionId theRequestPartitionId) {
|
||||||
return createPredicateToken(
|
return createPredicateToken(
|
||||||
theParameters,
|
theParameters,
|
||||||
theResourceName,
|
theResourceName,
|
||||||
theParamName,
|
theSearchParam,
|
||||||
theBuilder,
|
theBuilder,
|
||||||
theFrom,
|
theFrom,
|
||||||
null,
|
null,
|
||||||
|
@ -160,12 +155,13 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
||||||
|
|
||||||
private Collection<Predicate> createPredicateToken(Collection<IQueryParameterType> theParameters,
|
private Collection<Predicate> createPredicateToken(Collection<IQueryParameterType> theParameters,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theParamName,
|
RuntimeSearchParam theSearchParam,
|
||||||
CriteriaBuilder theBuilder,
|
CriteriaBuilder theBuilder,
|
||||||
From<?, ResourceIndexedSearchParamToken> theFrom,
|
From<?, ResourceIndexedSearchParamToken> theFrom,
|
||||||
SearchFilterParser.CompareOperation operation,
|
SearchFilterParser.CompareOperation operation,
|
||||||
RequestPartitionId theRequestPartitionId) {
|
RequestPartitionId theRequestPartitionId) {
|
||||||
final List<VersionIndependentConcept> codes = new ArrayList<>();
|
final List<VersionIndependentConcept> codes = new ArrayList<>();
|
||||||
|
String paramName = theSearchParam.getName();
|
||||||
|
|
||||||
TokenParamModifier modifier = null;
|
TokenParamModifier modifier = null;
|
||||||
for (IQueryParameterType nextParameter : theParameters) {
|
for (IQueryParameterType nextParameter : theParameters) {
|
||||||
|
@ -195,12 +191,12 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
||||||
|
|
||||||
if (system != null && system.length() > ResourceIndexedSearchParamToken.MAX_LENGTH) {
|
if (system != null && system.length() > ResourceIndexedSearchParamToken.MAX_LENGTH) {
|
||||||
throw new InvalidRequestException(
|
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) {
|
if (code != null && code.length() > ResourceIndexedSearchParamToken.MAX_LENGTH) {
|
||||||
throw new InvalidRequestException(
|
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) {
|
if (modifier == TokenParamModifier.IN) {
|
||||||
codes.addAll(myTerminologySvc.expandValueSet(null, code));
|
codes.addAll(myTerminologySvc.expandValueSet(null, code));
|
||||||
} else if (modifier == TokenParamModifier.ABOVE) {
|
} else if (modifier == TokenParamModifier.ABOVE) {
|
||||||
system = determineSystemIfMissing(theParamName, code, system);
|
system = determineSystemIfMissing(theSearchParam, code, system);
|
||||||
validateHaveSystemAndCodeForToken(theParamName, code, system);
|
validateHaveSystemAndCodeForToken(paramName, code, system);
|
||||||
codes.addAll(myTerminologySvc.findCodesAbove(system, code));
|
codes.addAll(myTerminologySvc.findCodesAbove(system, code));
|
||||||
} else if (modifier == TokenParamModifier.BELOW) {
|
} else if (modifier == TokenParamModifier.BELOW) {
|
||||||
system = determineSystemIfMissing(theParamName, code, system);
|
system = determineSystemIfMissing(theSearchParam, code, system);
|
||||||
validateHaveSystemAndCodeForToken(theParamName, code, system);
|
validateHaveSystemAndCodeForToken(paramName, code, system);
|
||||||
codes.addAll(myTerminologySvc.findCodesBelow(system, code));
|
codes.addAll(myTerminologySvc.findCodesBelow(system, code));
|
||||||
} else {
|
} else {
|
||||||
codes.add(new VersionIndependentConcept(system, code));
|
codes.add(new VersionIndependentConcept(system, code));
|
||||||
|
@ -240,32 +236,30 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
||||||
// System only
|
// System only
|
||||||
List<VersionIndependentConcept> systemOnlyCodes = sortedCodesList.stream().filter(t -> isBlank(t.getCode())).collect(Collectors.toList());
|
List<VersionIndependentConcept> systemOnlyCodes = sortedCodesList.stream().filter(t -> isBlank(t.getCode())).collect(Collectors.toList());
|
||||||
if (!systemOnlyCodes.isEmpty()) {
|
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
|
// Code only
|
||||||
List<VersionIndependentConcept> codeOnlyCodes = sortedCodesList.stream().filter(t -> t.getSystem() == null).collect(Collectors.toList());
|
List<VersionIndependentConcept> codeOnlyCodes = sortedCodesList.stream().filter(t -> t.getSystem() == null).collect(Collectors.toList());
|
||||||
if (!codeOnlyCodes.isEmpty()) {
|
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
|
// System and code
|
||||||
List<VersionIndependentConcept> systemAndCodeCodes = sortedCodesList.stream().filter(t -> isNotBlank(t.getCode()) && t.getSystem() != null).collect(Collectors.toList());
|
List<VersionIndependentConcept> systemAndCodeCodes = sortedCodesList.stream().filter(t -> isNotBlank(t.getCode()) && t.getSystem() != null).collect(Collectors.toList());
|
||||||
if (!systemAndCodeCodes.isEmpty()) {
|
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;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String determineSystemIfMissing(String theParamName, String code, String theSystem) {
|
private String determineSystemIfMissing(RuntimeSearchParam theSearchParam, String code, String theSystem) {
|
||||||
String retVal = theSystem;
|
String retVal = theSystem;
|
||||||
if (retVal == null) {
|
if (retVal == null) {
|
||||||
RuntimeResourceDefinition resourceDef = myContext.getResourceDefinition(myResourceName);
|
if (theSearchParam != null) {
|
||||||
RuntimeSearchParam param = mySearchParamRegistry.getSearchParamByName(resourceDef, theParamName);
|
|
||||||
if (param != null) {
|
|
||||||
Set<String> valueSetUris = Sets.newHashSet();
|
Set<String> valueSetUris = Sets.newHashSet();
|
||||||
for (String nextPath : param.getPathsSplit()) {
|
for (String nextPath : theSearchParam.getPathsSplit()) {
|
||||||
BaseRuntimeChildDefinition def = myContext.newTerser().getDefinition(myResourceType, nextPath);
|
BaseRuntimeChildDefinition def = myContext.newTerser().getDefinition(myResourceType, nextPath);
|
||||||
if (def instanceof BaseRuntimeDeclaredChildDefinition) {
|
if (def instanceof BaseRuntimeDeclaredChildDefinition) {
|
||||||
String valueSet = ((BaseRuntimeDeclaredChildDefinition) def).getBindingValueSet();
|
String valueSet = ((BaseRuntimeDeclaredChildDefinition) def).getBindingValueSet();
|
||||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.dao.predicate;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao;
|
||||||
|
@ -53,15 +54,16 @@ class PredicateBuilderUri extends BasePredicateBuilder implements IPredicateBuil
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Predicate addPredicate(String theResourceName,
|
public Predicate addPredicate(String theResourceName,
|
||||||
String theParamName,
|
RuntimeSearchParam theSearchParam,
|
||||||
List<? extends IQueryParameterType> theList,
|
List<? extends IQueryParameterType> theList,
|
||||||
SearchFilterParser.CompareOperation operation,
|
SearchFilterParser.CompareOperation operation,
|
||||||
RequestPartitionId theRequestPartitionId) {
|
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) {
|
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;
|
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.
|
* 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);
|
ourLog.info("Searching for candidate URI:above parameters for Resource[{}] param[{}]", myResourceName, paramName);
|
||||||
Collection<String> candidates = myResourceIndexedSearchParamUriDao.findAllByResourceTypeAndParamName(myResourceName, theParamName);
|
Collection<String> candidates = myResourceIndexedSearchParamUriDao.findAllByResourceTypeAndParamName(myResourceName, paramName);
|
||||||
List<String> toFind = new ArrayList<>();
|
List<String> toFind = new ArrayList<>();
|
||||||
for (String next : candidates) {
|
for (String next : candidates) {
|
||||||
if (value.length() >= next.length()) {
|
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 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);
|
codePredicates.add(hashAndUriPredicate);
|
||||||
|
|
||||||
} else if (param.getQualifier() == UriParamQualifierEnum.BELOW) {
|
} else if (param.getQualifier() == UriParamQualifierEnum.BELOW) {
|
||||||
|
|
||||||
Predicate uriPredicate = myCriteriaBuilder.like(join.get("myUri").as(String.class), createLeftMatchLikeExpression(value));
|
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);
|
codePredicates.add(hashAndUriPredicate);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -124,7 +126,7 @@ class PredicateBuilderUri extends BasePredicateBuilder implements IPredicateBuil
|
||||||
|
|
||||||
Predicate uriPredicate = null;
|
Predicate uriPredicate = null;
|
||||||
if (operation == null || operation == SearchFilterParser.CompareOperation.eq) {
|
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);
|
Predicate hashPredicate = myCriteriaBuilder.equal(join.get("myHashUri"), hashUri);
|
||||||
codePredicates.add(hashPredicate);
|
codePredicates.add(hashPredicate);
|
||||||
} else if (operation == SearchFilterParser.CompareOperation.ne) {
|
} else if (operation == SearchFilterParser.CompareOperation.ne) {
|
||||||
|
@ -149,7 +151,7 @@ class PredicateBuilderUri extends BasePredicateBuilder implements IPredicateBuil
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uriPredicate != null) {
|
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);
|
Predicate hashIdentityPredicate = myCriteriaBuilder.equal(join.get("myHashIdentity"), hashIdentity);
|
||||||
codePredicates.add(myCriteriaBuilder.and(hashIdentityPredicate, uriPredicate));
|
codePredicates.add(myCriteriaBuilder.and(hashIdentityPredicate, uriPredicate));
|
||||||
}
|
}
|
||||||
|
@ -175,7 +177,7 @@ class PredicateBuilderUri extends BasePredicateBuilder implements IPredicateBuil
|
||||||
Predicate orPredicate = myCriteriaBuilder.or(toArray(codePredicates));
|
Predicate orPredicate = myCriteriaBuilder.or(toArray(codePredicates));
|
||||||
|
|
||||||
Predicate outerPredicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName,
|
Predicate outerPredicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName,
|
||||||
theParamName,
|
paramName,
|
||||||
join,
|
join,
|
||||||
orPredicate,
|
orPredicate,
|
||||||
theRequestPartitionId);
|
theRequestPartitionId);
|
||||||
|
|
|
@ -21,7 +21,6 @@ package ca.uhn.fhir.jpa.dao.r4;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDaoObservation;
|
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDaoObservation;
|
||||||
import ca.uhn.fhir.jpa.dao.ObservationLastNIndexPersistSvc;
|
|
||||||
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
|
@ -32,7 +31,6 @@ import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.r4.model.Observation;
|
import org.hl7.fhir.r4.model.Observation;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.PersistenceContext;
|
import javax.persistence.PersistenceContext;
|
||||||
|
@ -46,9 +44,6 @@ public class FhirResourceDaoObservationR4 extends BaseHapiFhirResourceDaoObserva
|
||||||
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
||||||
protected EntityManager myEntityManager;
|
protected EntityManager myEntityManager;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
ObservationLastNIndexPersistSvc myObservationLastNIndexPersistSvc;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBundleProvider observationsLastN(SearchParameterMap theSearchParameterMap, RequestDetails theRequestDetails, HttpServletResponse theServletResponse) {
|
public IBundleProvider observationsLastN(SearchParameterMap theSearchParameterMap, RequestDetails theRequestDetails, HttpServletResponse theServletResponse) {
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ package ca.uhn.fhir.jpa.dao.r5;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDaoObservation;
|
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDaoObservation;
|
||||||
import ca.uhn.fhir.jpa.dao.ObservationLastNIndexPersistSvc;
|
|
||||||
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
|
@ -32,16 +31,12 @@ import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.r5.model.Observation;
|
import org.hl7.fhir.r5.model.Observation;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
public class FhirResourceDaoObservationR5 extends BaseHapiFhirResourceDaoObservation<Observation> {
|
public class FhirResourceDaoObservationR5 extends BaseHapiFhirResourceDaoObservation<Observation> {
|
||||||
|
|
||||||
@Autowired
|
|
||||||
ObservationLastNIndexPersistSvc myObservationLastNIndexPersistSvc;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBundleProvider observationsLastN(SearchParameterMap theSearchParameterMap, RequestDetails theRequestDetails, HttpServletResponse theServletResponse) {
|
public IBundleProvider observationsLastN(SearchParameterMap theSearchParameterMap, RequestDetails theRequestDetails, HttpServletResponse theServletResponse) {
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ package ca.uhn.fhir.jpa.term;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemDao;
|
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemDao;
|
||||||
|
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemVersionDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.ITermConceptDao;
|
import ca.uhn.fhir.jpa.dao.data.ITermConceptDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.ITermConceptParentChildLinkDao;
|
import ca.uhn.fhir.jpa.dao.data.ITermConceptParentChildLinkDao;
|
||||||
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
||||||
|
@ -62,6 +63,8 @@ public class TermDeferredStorageSvcImpl implements ITermDeferredStorageSvc {
|
||||||
@Autowired
|
@Autowired
|
||||||
protected ITermCodeSystemDao myCodeSystemDao;
|
protected ITermCodeSystemDao myCodeSystemDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
protected ITermCodeSystemVersionDao myCodeSystemVersionDao;
|
||||||
|
@Autowired
|
||||||
protected PlatformTransactionManager myTransactionMgr;
|
protected PlatformTransactionManager myTransactionMgr;
|
||||||
private boolean myProcessDeferred = true;
|
private boolean myProcessDeferred = true;
|
||||||
private List<TermCodeSystem> myDefferedCodeSystemsDeletions = Collections.synchronizedList(new ArrayList<>());
|
private List<TermCodeSystem> myDefferedCodeSystemsDeletions = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
@ -142,7 +145,12 @@ public class TermDeferredStorageSvcImpl implements ITermDeferredStorageSvc {
|
||||||
ourLog.info("Saving {} deferred concepts...", count);
|
ourLog.info("Saving {} deferred concepts...", count);
|
||||||
while (codeCount < count && myDeferredConcepts.size() > 0) {
|
while (codeCount < count && myDeferredConcepts.size() > 0) {
|
||||||
TermConcept next = myDeferredConcepts.remove(0);
|
TermConcept next = myDeferredConcepts.remove(0);
|
||||||
codeCount += myCodeSystemStorageSvc.saveConcept(next);
|
if(myCodeSystemVersionDao.findById(next.getCodeSystemVersion().getPid()).isPresent()) {
|
||||||
|
codeCount += myCodeSystemStorageSvc.saveConcept(next);
|
||||||
|
} else {
|
||||||
|
ourLog.warn("Unable to save deferred TermConcept {} because Code System {} version PID {} is no longer valid. Code system may have since been replaced.",
|
||||||
|
next.getCode(), next.getCodeSystemVersion().getCodeSystemDisplayName(), next.getCodeSystemVersion().getPid());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (codeCount > 0) {
|
if (codeCount > 0) {
|
||||||
|
@ -340,4 +348,9 @@ public class TermDeferredStorageSvcImpl implements ITermDeferredStorageSvc {
|
||||||
void setConceptDaoForUnitTest(ITermConceptDao theConceptDao) {
|
void setConceptDaoForUnitTest(ITermConceptDao theConceptDao) {
|
||||||
myConceptDao = theConceptDao;
|
myConceptDao = theConceptDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void setCodeSystemVersionDaoForUnitTest(ITermCodeSystemVersionDao theCodeSystemVersionDao) {
|
||||||
|
myCodeSystemVersionDao = theCodeSystemVersionDao;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,10 @@ package ca.uhn.fhir.jpa.term;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConceptDesignation;
|
import ca.uhn.fhir.jpa.entity.TermConceptDesignation;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
|
||||||
import ca.uhn.fhir.jpa.term.ex.ExpansionTooCostlyException;
|
import ca.uhn.fhir.jpa.term.ex.ExpansionTooCostlyException;
|
||||||
import ca.uhn.fhir.model.api.annotation.Block;
|
import ca.uhn.fhir.model.api.annotation.Block;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import org.hl7.fhir.r4.model.StringType;
|
import org.hl7.fhir.r4.model.StringType;
|
||||||
import org.hl7.fhir.r4.model.ValueSet;
|
import org.hl7.fhir.r4.model.ValueSet;
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.V
|
||||||
@Override
|
@Override
|
||||||
public void addMessage(String theMessage) {
|
public void addMessage(String theMessage) {
|
||||||
addExtension()
|
addExtension()
|
||||||
.setUrl(JpaConstants.EXT_VALUESET_EXPANSION_MESSAGE)
|
.setUrl(HapiExtensions.EXT_VALUESET_EXPANSION_MESSAGE)
|
||||||
.setValue(new StringType(theMessage));
|
.setValue(new StringType(theMessage));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ import ca.uhn.fhir.rest.param.TokenOrListParam;
|
||||||
import ca.uhn.fhir.rest.param.TokenParam;
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import org.apache.commons.text.RandomStringGenerator;
|
import org.apache.commons.text.RandomStringGenerator;
|
||||||
import org.hl7.fhir.dstu3.model.Patient;
|
import org.hl7.fhir.dstu3.model.Patient;
|
||||||
import org.hl7.fhir.dstu3.model.StringType;
|
import org.hl7.fhir.dstu3.model.StringType;
|
||||||
|
@ -45,12 +46,12 @@ public class FhirResourceDaoDstu3SourceTest extends BaseJpaDstu3Test {
|
||||||
|
|
||||||
when(mySrd.getRequestId()).thenReturn(requestId);
|
when(mySrd.getRequestId()).thenReturn(requestId);
|
||||||
Patient pt0 = new Patient();
|
Patient pt0 = new Patient();
|
||||||
pt0.getMeta().addExtension(Constants.EXT_META_SOURCE, new StringType("urn:source:0"));
|
pt0.getMeta().addExtension(HapiExtensions.EXT_META_SOURCE, new StringType("urn:source:0"));
|
||||||
pt0.setActive(true);
|
pt0.setActive(true);
|
||||||
IIdType pt0id = myPatientDao.create(pt0, mySrd).getId().toUnqualifiedVersionless();
|
IIdType pt0id = myPatientDao.create(pt0, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
Patient pt1 = new Patient();
|
Patient pt1 = new Patient();
|
||||||
pt1.getMeta().addExtension(Constants.EXT_META_SOURCE, new StringType("urn:source:1"));
|
pt1.getMeta().addExtension(HapiExtensions.EXT_META_SOURCE, new StringType("urn:source:1"));
|
||||||
pt1.setActive(true);
|
pt1.setActive(true);
|
||||||
IIdType pt1id = myPatientDao.create(pt1, mySrd).getId().toUnqualifiedVersionless();
|
IIdType pt1id = myPatientDao.create(pt1, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
@ -61,7 +62,7 @@ public class FhirResourceDaoDstu3SourceTest extends BaseJpaDstu3Test {
|
||||||
IBundleProvider result = myPatientDao.search(params);
|
IBundleProvider result = myPatientDao.search(params);
|
||||||
assertThat(toUnqualifiedVersionlessIdValues(result), containsInAnyOrder(pt0id.getValue()));
|
assertThat(toUnqualifiedVersionlessIdValues(result), containsInAnyOrder(pt0id.getValue()));
|
||||||
pt0 = (Patient) result.getResources(0, 1).get(0);
|
pt0 = (Patient) result.getResources(0, 1).get(0);
|
||||||
assertEquals("urn:source:0#a_request_id", pt0.getMeta().getExtensionString(Constants.EXT_META_SOURCE));
|
assertEquals("urn:source:0#a_request_id", pt0.getMeta().getExtensionString(HapiExtensions.EXT_META_SOURCE));
|
||||||
|
|
||||||
// Search by request ID
|
// Search by request ID
|
||||||
params = new SearchParameterMap();
|
params = new SearchParameterMap();
|
||||||
|
@ -86,17 +87,17 @@ public class FhirResourceDaoDstu3SourceTest extends BaseJpaDstu3Test {
|
||||||
|
|
||||||
when(mySrd.getRequestId()).thenReturn(requestId);
|
when(mySrd.getRequestId()).thenReturn(requestId);
|
||||||
Patient pt0 = new Patient();
|
Patient pt0 = new Patient();
|
||||||
pt0.getMeta().addExtension(Constants.EXT_META_SOURCE, new StringType("urn:source:0"));
|
pt0.getMeta().addExtension(HapiExtensions.EXT_META_SOURCE, new StringType("urn:source:0"));
|
||||||
pt0.setActive(true);
|
pt0.setActive(true);
|
||||||
IIdType pt0id = myPatientDao.create(pt0, mySrd).getId().toUnqualifiedVersionless();
|
IIdType pt0id = myPatientDao.create(pt0, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
Patient pt1 = new Patient();
|
Patient pt1 = new Patient();
|
||||||
pt1.getMeta().addExtension(Constants.EXT_META_SOURCE, new StringType("urn:source:1"));
|
pt1.getMeta().addExtension(HapiExtensions.EXT_META_SOURCE, new StringType("urn:source:1"));
|
||||||
pt1.setActive(true);
|
pt1.setActive(true);
|
||||||
IIdType pt1id = myPatientDao.create(pt1, mySrd).getId().toUnqualifiedVersionless();
|
IIdType pt1id = myPatientDao.create(pt1, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
Patient pt2 = new Patient();
|
Patient pt2 = new Patient();
|
||||||
pt2.getMeta().addExtension(Constants.EXT_META_SOURCE, new StringType("urn:source:2"));
|
pt2.getMeta().addExtension(HapiExtensions.EXT_META_SOURCE, new StringType("urn:source:2"));
|
||||||
pt2.setActive(true);
|
pt2.setActive(true);
|
||||||
myPatientDao.create(pt2, mySrd).getId().toUnqualifiedVersionless();
|
myPatientDao.create(pt2, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
@ -117,17 +118,17 @@ public class FhirResourceDaoDstu3SourceTest extends BaseJpaDstu3Test {
|
||||||
|
|
||||||
when(mySrd.getRequestId()).thenReturn(requestId);
|
when(mySrd.getRequestId()).thenReturn(requestId);
|
||||||
Patient pt0 = new Patient();
|
Patient pt0 = new Patient();
|
||||||
pt0.getMeta().addExtension(Constants.EXT_META_SOURCE, new StringType("urn:source:0"));
|
pt0.getMeta().addExtension(HapiExtensions.EXT_META_SOURCE, new StringType("urn:source:0"));
|
||||||
pt0.setActive(true);
|
pt0.setActive(true);
|
||||||
IIdType pt0id = myPatientDao.create(pt0, mySrd).getId().toUnqualifiedVersionless();
|
IIdType pt0id = myPatientDao.create(pt0, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
Patient pt1 = new Patient();
|
Patient pt1 = new Patient();
|
||||||
pt1.getMeta().addExtension(Constants.EXT_META_SOURCE, new StringType("urn:source:1"));
|
pt1.getMeta().addExtension(HapiExtensions.EXT_META_SOURCE, new StringType("urn:source:1"));
|
||||||
pt1.setActive(true);
|
pt1.setActive(true);
|
||||||
IIdType pt1id = myPatientDao.create(pt1, mySrd).getId().toUnqualifiedVersionless();
|
IIdType pt1id = myPatientDao.create(pt1, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
Patient pt2 = new Patient();
|
Patient pt2 = new Patient();
|
||||||
pt2.getMeta().addExtension(Constants.EXT_META_SOURCE, new StringType("urn:source:2"));
|
pt2.getMeta().addExtension(HapiExtensions.EXT_META_SOURCE, new StringType("urn:source:2"));
|
||||||
pt2.setActive(true);
|
pt2.setActive(true);
|
||||||
myPatientDao.create(pt2, mySrd).getId().toUnqualifiedVersionless();
|
myPatientDao.create(pt2, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
@ -147,7 +148,7 @@ public class FhirResourceDaoDstu3SourceTest extends BaseJpaDstu3Test {
|
||||||
when(mySrd.getRequestId()).thenReturn(requestId);
|
when(mySrd.getRequestId()).thenReturn(requestId);
|
||||||
|
|
||||||
Patient pt0 = new Patient();
|
Patient pt0 = new Patient();
|
||||||
pt0.getMeta().addExtension(Constants.EXT_META_SOURCE, new StringType("urn:source:0"));
|
pt0.getMeta().addExtension(HapiExtensions.EXT_META_SOURCE, new StringType("urn:source:0"));
|
||||||
pt0.setActive(true);
|
pt0.setActive(true);
|
||||||
IIdType pt0id = myPatientDao.create(pt0, mySrd).getId().toUnqualifiedVersionless();
|
IIdType pt0id = myPatientDao.create(pt0, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
@ -165,19 +166,19 @@ public class FhirResourceDaoDstu3SourceTest extends BaseJpaDstu3Test {
|
||||||
public void testSourceNotPreservedAcrossUpdate() {
|
public void testSourceNotPreservedAcrossUpdate() {
|
||||||
|
|
||||||
Patient pt0 = new Patient();
|
Patient pt0 = new Patient();
|
||||||
pt0.getMeta().addExtension(Constants.EXT_META_SOURCE, new StringType("urn:source:0"));
|
pt0.getMeta().addExtension(HapiExtensions.EXT_META_SOURCE, new StringType("urn:source:0"));
|
||||||
pt0.setActive(true);
|
pt0.setActive(true);
|
||||||
IIdType pt0id = myPatientDao.create(pt0, mySrd).getId().toUnqualifiedVersionless();
|
IIdType pt0id = myPatientDao.create(pt0, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
pt0 = myPatientDao.read(pt0id);
|
pt0 = myPatientDao.read(pt0id);
|
||||||
assertEquals("urn:source:0", pt0.getMeta().getExtensionString(Constants.EXT_META_SOURCE));
|
assertEquals("urn:source:0", pt0.getMeta().getExtensionString(HapiExtensions.EXT_META_SOURCE));
|
||||||
|
|
||||||
pt0.getMeta().getExtension().clear();
|
pt0.getMeta().getExtension().clear();
|
||||||
pt0.setActive(false);
|
pt0.setActive(false);
|
||||||
myPatientDao.update(pt0);
|
myPatientDao.update(pt0);
|
||||||
|
|
||||||
pt0 = myPatientDao.read(pt0id.withVersion("2"));
|
pt0 = myPatientDao.read(pt0id.withVersion("2"));
|
||||||
assertEquals(null, pt0.getMeta().getExtensionString(Constants.EXT_META_SOURCE));
|
assertEquals(null, pt0.getMeta().getExtensionString(HapiExtensions.EXT_META_SOURCE));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,19 +188,19 @@ public class FhirResourceDaoDstu3SourceTest extends BaseJpaDstu3Test {
|
||||||
when(mySrd.getRequestId()).thenReturn("0000000000000000");
|
when(mySrd.getRequestId()).thenReturn("0000000000000000");
|
||||||
|
|
||||||
Patient pt0 = new Patient();
|
Patient pt0 = new Patient();
|
||||||
pt0.getMeta().addExtension(Constants.EXT_META_SOURCE, new StringType("urn:source:0"));
|
pt0.getMeta().addExtension(HapiExtensions.EXT_META_SOURCE, new StringType("urn:source:0"));
|
||||||
pt0.setActive(true);
|
pt0.setActive(true);
|
||||||
IIdType pt0id = myPatientDao.create(pt0, mySrd).getId().toUnqualifiedVersionless();
|
IIdType pt0id = myPatientDao.create(pt0, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
pt0 = myPatientDao.read(pt0id);
|
pt0 = myPatientDao.read(pt0id);
|
||||||
assertEquals(null, pt0.getMeta().getExtensionString(Constants.EXT_META_SOURCE));
|
assertEquals(null, pt0.getMeta().getExtensionString(HapiExtensions.EXT_META_SOURCE));
|
||||||
|
|
||||||
pt0.getMeta().addExtension(Constants.EXT_META_SOURCE, new StringType("urn:source:1"));
|
pt0.getMeta().addExtension(HapiExtensions.EXT_META_SOURCE, new StringType("urn:source:1"));
|
||||||
pt0.setActive(false);
|
pt0.setActive(false);
|
||||||
myPatientDao.update(pt0);
|
myPatientDao.update(pt0);
|
||||||
|
|
||||||
pt0 = myPatientDao.read(pt0id.withVersion("2"));
|
pt0 = myPatientDao.read(pt0id.withVersion("2"));
|
||||||
assertEquals(null, pt0.getMeta().getExtensionString(Constants.EXT_META_SOURCE));
|
assertEquals(null, pt0.getMeta().getExtensionString(HapiExtensions.EXT_META_SOURCE));
|
||||||
|
|
||||||
// Search without source param
|
// Search without source param
|
||||||
SearchParameterMap params = new SearchParameterMap();
|
SearchParameterMap params = new SearchParameterMap();
|
||||||
|
|
|
@ -17,7 +17,6 @@ import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
|
||||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap.EverythingModeEnum;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap.EverythingModeEnum;
|
||||||
|
@ -51,6 +50,7 @@ import ca.uhn.fhir.rest.param.UriParam;
|
||||||
import ca.uhn.fhir.rest.param.UriParamQualifierEnum;
|
import ca.uhn.fhir.rest.param.UriParamQualifierEnum;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -4842,7 +4842,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||||
sp.setCode("code");
|
sp.setCode("code");
|
||||||
sp.setExpression("Observation.code");
|
sp.setExpression("Observation.code");
|
||||||
sp.addExtension()
|
sp.addExtension()
|
||||||
.setUrl(JpaConstants.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING)
|
.setUrl(HapiExtensions.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING)
|
||||||
.setValue(new BooleanType(true));
|
.setValue(new BooleanType(true));
|
||||||
ourLog.info("SP:\n{}", myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(sp));
|
ourLog.info("SP:\n{}", myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(sp));
|
||||||
mySearchParameterDao.update(sp);
|
mySearchParameterDao.update(sp);
|
||||||
|
|
|
@ -11,7 +11,6 @@ import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
||||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||||
import ca.uhn.fhir.jpa.search.reindex.ResourceReindexingSvcImpl;
|
import ca.uhn.fhir.jpa.search.reindex.ResourceReindexingSvcImpl;
|
||||||
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
|
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||||
import ca.uhn.fhir.jpa.util.SpringObjectCaster;
|
import ca.uhn.fhir.jpa.util.SpringObjectCaster;
|
||||||
|
@ -22,6 +21,7 @@ import ca.uhn.fhir.rest.param.TokenAndListParam;
|
||||||
import ca.uhn.fhir.rest.param.TokenParam;
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.*;
|
||||||
|
@ -140,7 +140,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
.setExpression("Patient")
|
.setExpression("Patient")
|
||||||
.setDefinition("SearchParameter/patient-birthdate");
|
.setDefinition("SearchParameter/patient-birthdate");
|
||||||
sp.addExtension()
|
sp.addExtension()
|
||||||
.setUrl(SearchParamConstants.EXT_SP_UNIQUE)
|
.setUrl(HapiExtensions.EXT_SP_UNIQUE)
|
||||||
.setValue(new BooleanType(true));
|
.setValue(new BooleanType(true));
|
||||||
mySearchParameterDao.update(sp);
|
mySearchParameterDao.update(sp);
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
.setExpression("Coverage")
|
.setExpression("Coverage")
|
||||||
.setDefinition("/SearchParameter/coverage-identifier");
|
.setDefinition("/SearchParameter/coverage-identifier");
|
||||||
sp.addExtension()
|
sp.addExtension()
|
||||||
.setUrl(SearchParamConstants.EXT_SP_UNIQUE)
|
.setUrl(HapiExtensions.EXT_SP_UNIQUE)
|
||||||
.setValue(new BooleanType(true));
|
.setValue(new BooleanType(true));
|
||||||
mySearchParameterDao.update(sp);
|
mySearchParameterDao.update(sp);
|
||||||
mySearchParamRegistry.forceRefresh();
|
mySearchParamRegistry.forceRefresh();
|
||||||
|
@ -210,7 +210,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
.setExpression("Observation")
|
.setExpression("Observation")
|
||||||
.setDefinition("/SearchParameter/observation-subject");
|
.setDefinition("/SearchParameter/observation-subject");
|
||||||
sp.addExtension()
|
sp.addExtension()
|
||||||
.setUrl(SearchParamConstants.EXT_SP_UNIQUE)
|
.setUrl(HapiExtensions.EXT_SP_UNIQUE)
|
||||||
.setValue(new BooleanType(true));
|
.setValue(new BooleanType(true));
|
||||||
mySearchParameterDao.update(sp);
|
mySearchParameterDao.update(sp);
|
||||||
mySearchParamRegistry.forceRefresh();
|
mySearchParamRegistry.forceRefresh();
|
||||||
|
@ -238,7 +238,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
.setExpression("Patient")
|
.setExpression("Patient")
|
||||||
.setDefinition("/SearchParameter/patient-identifier");
|
.setDefinition("/SearchParameter/patient-identifier");
|
||||||
sp.addExtension()
|
sp.addExtension()
|
||||||
.setUrl(SearchParamConstants.EXT_SP_UNIQUE)
|
.setUrl(HapiExtensions.EXT_SP_UNIQUE)
|
||||||
.setValue(new BooleanType(true));
|
.setValue(new BooleanType(true));
|
||||||
mySearchParameterDao.update(sp);
|
mySearchParameterDao.update(sp);
|
||||||
mySearchParamRegistry.forceRefresh();
|
mySearchParamRegistry.forceRefresh();
|
||||||
|
@ -266,7 +266,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
.setExpression("Patient")
|
.setExpression("Patient")
|
||||||
.setDefinition("/SearchParameter/patient-identifier");
|
.setDefinition("/SearchParameter/patient-identifier");
|
||||||
sp.addExtension()
|
sp.addExtension()
|
||||||
.setUrl(SearchParamConstants.EXT_SP_UNIQUE)
|
.setUrl(HapiExtensions.EXT_SP_UNIQUE)
|
||||||
.setValue(new BooleanType(true));
|
.setValue(new BooleanType(true));
|
||||||
mySearchParameterDao.update(sp);
|
mySearchParameterDao.update(sp);
|
||||||
mySearchParamRegistry.forceRefresh();
|
mySearchParamRegistry.forceRefresh();
|
||||||
|
@ -303,7 +303,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
.setExpression("Patient")
|
.setExpression("Patient")
|
||||||
.setDefinition("SearchParameter/patient-organization");
|
.setDefinition("SearchParameter/patient-organization");
|
||||||
sp.addExtension()
|
sp.addExtension()
|
||||||
.setUrl(SearchParamConstants.EXT_SP_UNIQUE)
|
.setUrl(HapiExtensions.EXT_SP_UNIQUE)
|
||||||
.setValue(new BooleanType(true));
|
.setValue(new BooleanType(true));
|
||||||
mySearchParameterDao.update(sp);
|
mySearchParameterDao.update(sp);
|
||||||
|
|
||||||
|
@ -355,7 +355,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
.setExpression("Observation")
|
.setExpression("Observation")
|
||||||
.setDefinition("SearchParameter/obs-code");
|
.setDefinition("SearchParameter/obs-code");
|
||||||
sp.addExtension()
|
sp.addExtension()
|
||||||
.setUrl(SearchParamConstants.EXT_SP_UNIQUE)
|
.setUrl(HapiExtensions.EXT_SP_UNIQUE)
|
||||||
.setValue(new BooleanType(true));
|
.setValue(new BooleanType(true));
|
||||||
mySearchParameterDao.update(sp);
|
mySearchParameterDao.update(sp);
|
||||||
|
|
||||||
|
@ -487,7 +487,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
.setExpression("ServiceRequest")
|
.setExpression("ServiceRequest")
|
||||||
.setDefinition(identifierParamId); // SearchParameter?base=ServiceRequest&name=identifier
|
.setDefinition(identifierParamId); // SearchParameter?base=ServiceRequest&name=identifier
|
||||||
sp.addExtension()
|
sp.addExtension()
|
||||||
.setUrl(SearchParamConstants.EXT_SP_UNIQUE)
|
.setUrl(HapiExtensions.EXT_SP_UNIQUE)
|
||||||
.setValue(new BooleanType(true));
|
.setValue(new BooleanType(true));
|
||||||
mySearchParameterDao.create(sp);
|
mySearchParameterDao.create(sp);
|
||||||
mySearchParamRegistry.forceRefresh();
|
mySearchParamRegistry.forceRefresh();
|
||||||
|
|
|
@ -36,6 +36,7 @@ import org.hl7.fhir.r4.model.CodeSystem;
|
||||||
import org.hl7.fhir.r4.model.Coding;
|
import org.hl7.fhir.r4.model.Coding;
|
||||||
import org.hl7.fhir.r4.model.Condition;
|
import org.hl7.fhir.r4.model.Condition;
|
||||||
import org.hl7.fhir.r4.model.DateTimeType;
|
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.Group;
|
||||||
import org.hl7.fhir.r4.model.IdType;
|
import org.hl7.fhir.r4.model.IdType;
|
||||||
import org.hl7.fhir.r4.model.Narrative;
|
import org.hl7.fhir.r4.model.Narrative;
|
||||||
|
@ -1291,6 +1292,27 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
|
||||||
assertThat(encoded, containsString("No issues detected"));
|
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
|
@AfterClass
|
||||||
public static void afterClassClearContext() {
|
public static void afterClassClearContext() {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package ca.uhn.fhir.jpa.dao.r4;
|
package ca.uhn.fhir.jpa.dao.r4;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
|
||||||
import ca.uhn.fhir.interceptor.api.Hook;
|
import ca.uhn.fhir.interceptor.api.Hook;
|
||||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
import ca.uhn.fhir.interceptor.api.IAnonymousInterceptor;
|
import ca.uhn.fhir.interceptor.api.IAnonymousInterceptor;
|
||||||
|
@ -8,7 +7,6 @@ import ca.uhn.fhir.interceptor.api.Interceptor;
|
||||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
|
||||||
import ca.uhn.fhir.jpa.entity.PartitionEntity;
|
import ca.uhn.fhir.jpa.entity.PartitionEntity;
|
||||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ForcedId;
|
import ca.uhn.fhir.jpa.model.entity.ForcedId;
|
||||||
|
@ -22,7 +20,6 @@ import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTag;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTag;
|
||||||
import ca.uhn.fhir.jpa.model.entity.SearchParamPresent;
|
import ca.uhn.fhir.jpa.model.entity.SearchParamPresent;
|
||||||
import ca.uhn.fhir.jpa.partition.IPartitionLookupSvc;
|
import ca.uhn.fhir.jpa.partition.IPartitionLookupSvc;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
|
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.util.SqlQuery;
|
import ca.uhn.fhir.jpa.util.SqlQuery;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
|
@ -40,7 +37,7 @@ import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
import ca.uhn.fhir.test.utilities.ITestDataBuilder;
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
|
@ -69,7 +66,6 @@ import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collector;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast;
|
import static ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast;
|
||||||
|
@ -2418,7 +2414,7 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
|
||||||
.setExpression("Patient")
|
.setExpression("Patient")
|
||||||
.setDefinition("SearchParameter/patient-birthdate");
|
.setDefinition("SearchParameter/patient-birthdate");
|
||||||
sp.addExtension()
|
sp.addExtension()
|
||||||
.setUrl(SearchParamConstants.EXT_SP_UNIQUE)
|
.setUrl(HapiExtensions.EXT_SP_UNIQUE)
|
||||||
.setValue(new BooleanType(true));
|
.setValue(new BooleanType(true));
|
||||||
mySearchParameterDao.update(sp);
|
mySearchParameterDao.update(sp);
|
||||||
|
|
||||||
|
|
|
@ -203,9 +203,6 @@ public class PersistObservationIndexedSearchParamLastNR4IT {
|
||||||
List<ObservationJson> observationDocuments = elasticsearchSvc.executeLastNWithAllFieldsForTest(searchParameterMap, myFhirCtx);
|
List<ObservationJson> observationDocuments = elasticsearchSvc.executeLastNWithAllFieldsForTest(searchParameterMap, myFhirCtx);
|
||||||
assertEquals(100, observationDocuments.size());
|
assertEquals(100, observationDocuments.size());
|
||||||
|
|
||||||
//List<CodeJson> codeDocuments = elasticsearchSvc.queryAllIndexedObservationCodesForTest();
|
|
||||||
//assertEquals(2, codeDocuments.size());
|
|
||||||
|
|
||||||
// Check that all observations were indexed.
|
// Check that all observations were indexed.
|
||||||
searchParameterMap = new SearchParameterMap();
|
searchParameterMap = new SearchParameterMap();
|
||||||
searchParameterMap.add(Observation.SP_SUBJECT, multiSubjectParams);
|
searchParameterMap.add(Observation.SP_SUBJECT, multiSubjectParams);
|
||||||
|
|
|
@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.dao.r4;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
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.DefaultProfileValidationSupport;
|
||||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||||
|
@ -11,13 +12,13 @@ import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
|
||||||
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
||||||
import ca.uhn.fhir.jpa.searchparam.extractor.ISearchParamExtractor;
|
import ca.uhn.fhir.jpa.searchparam.extractor.ISearchParamExtractor;
|
||||||
import ca.uhn.fhir.jpa.searchparam.extractor.PathAndRef;
|
import ca.uhn.fhir.jpa.searchparam.extractor.PathAndRef;
|
||||||
import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorR4;
|
import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorR4;
|
||||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import org.hl7.fhir.r4.model.BooleanType;
|
import org.hl7.fhir.r4.model.BooleanType;
|
||||||
|
@ -123,7 +124,7 @@ public class SearchParamExtractorR4Test {
|
||||||
public void testTokenText_DisabledInSearchParam_Coding() {
|
public void testTokenText_DisabledInSearchParam_Coding() {
|
||||||
RuntimeSearchParam existingCodeSp = mySearchParamRegistry.getActiveSearchParams("Observation").get("code");
|
RuntimeSearchParam existingCodeSp = mySearchParamRegistry.getActiveSearchParams("Observation").get("code");
|
||||||
RuntimeSearchParam codeSearchParam = new RuntimeSearchParam(existingCodeSp);
|
RuntimeSearchParam codeSearchParam = new RuntimeSearchParam(existingCodeSp);
|
||||||
codeSearchParam.addExtension(JpaConstants.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING, new Extension(JpaConstants.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING, new BooleanType(true)));
|
codeSearchParam.addExtension(HapiExtensions.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING, new Extension(HapiExtensions.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING, new BooleanType(true)));
|
||||||
mySearchParamRegistry.addSearchParam(codeSearchParam);
|
mySearchParamRegistry.addSearchParam(codeSearchParam);
|
||||||
|
|
||||||
Observation obs = new Observation();
|
Observation obs = new Observation();
|
||||||
|
@ -176,7 +177,7 @@ public class SearchParamExtractorR4Test {
|
||||||
|
|
||||||
RuntimeSearchParam existingCodeSp = mySearchParamRegistry.getActiveSearchParams("Observation").get("code");
|
RuntimeSearchParam existingCodeSp = mySearchParamRegistry.getActiveSearchParams("Observation").get("code");
|
||||||
RuntimeSearchParam codeSearchParam = new RuntimeSearchParam(existingCodeSp);
|
RuntimeSearchParam codeSearchParam = new RuntimeSearchParam(existingCodeSp);
|
||||||
codeSearchParam.addExtension(JpaConstants.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING, new Extension(JpaConstants.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING, new BooleanType(false)));
|
codeSearchParam.addExtension(HapiExtensions.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING, new Extension(HapiExtensions.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING, new BooleanType(false)));
|
||||||
mySearchParamRegistry.addSearchParam(codeSearchParam);
|
mySearchParamRegistry.addSearchParam(codeSearchParam);
|
||||||
|
|
||||||
Observation obs = new Observation();
|
Observation obs = new Observation();
|
||||||
|
@ -230,7 +231,7 @@ public class SearchParamExtractorR4Test {
|
||||||
public void testTokenText_DisabledInSearchParam_Identifier() {
|
public void testTokenText_DisabledInSearchParam_Identifier() {
|
||||||
RuntimeSearchParam existingCodeSp = mySearchParamRegistry.getActiveSearchParams("Observation").get("identifier");
|
RuntimeSearchParam existingCodeSp = mySearchParamRegistry.getActiveSearchParams("Observation").get("identifier");
|
||||||
RuntimeSearchParam codeSearchParam = new RuntimeSearchParam(existingCodeSp);
|
RuntimeSearchParam codeSearchParam = new RuntimeSearchParam(existingCodeSp);
|
||||||
codeSearchParam.addExtension(JpaConstants.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING, new Extension(JpaConstants.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING, new BooleanType(true)));
|
codeSearchParam.addExtension(HapiExtensions.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING, new Extension(HapiExtensions.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING, new BooleanType(true)));
|
||||||
|
|
||||||
mySearchParamRegistry.addSearchParam(codeSearchParam);
|
mySearchParamRegistry.addSearchParam(codeSearchParam);
|
||||||
|
|
||||||
|
@ -401,6 +402,11 @@ public class SearchParamExtractorR4Test {
|
||||||
public Collection<RuntimeSearchParam> getSearchParamsByResourceType(RuntimeResourceDefinition theResourceDef) {
|
public Collection<RuntimeSearchParam> getSearchParamsByResourceType(RuntimeResourceDefinition theResourceDef) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPhoneticEncoder(IPhoneticEncoder thePhoneticEncoder) {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
|
|
|
@ -32,6 +32,7 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.BaseValidatingInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.BaseValidatingInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import ca.uhn.fhir.util.UrlUtil;
|
import ca.uhn.fhir.util.UrlUtil;
|
||||||
import ca.uhn.fhir.validation.IValidatorModule;
|
import ca.uhn.fhir.validation.IValidatorModule;
|
||||||
|
@ -4042,7 +4043,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
||||||
|
|
||||||
{
|
{
|
||||||
Patient readPatient = (Patient) ourClient.read().resource("Patient").withId(patientid).execute();
|
Patient readPatient = (Patient) ourClient.read().resource("Patient").withId(patientid).execute();
|
||||||
assertThat(readPatient.getMeta().getExtensionString(Constants.EXT_META_SOURCE), matchesPattern("#[a-zA-Z0-9]+"));
|
assertThat(readPatient.getMeta().getExtensionString(HapiExtensions.EXT_META_SOURCE), matchesPattern("#[a-zA-Z0-9]+"));
|
||||||
}
|
}
|
||||||
|
|
||||||
patient.setId(patientid);
|
patient.setId(patientid);
|
||||||
|
@ -4050,12 +4051,12 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
||||||
ourClient.update().resource(patient).execute();
|
ourClient.update().resource(patient).execute();
|
||||||
{
|
{
|
||||||
Patient readPatient = (Patient) ourClient.read().resource("Patient").withId(patientid).execute();
|
Patient readPatient = (Patient) ourClient.read().resource("Patient").withId(patientid).execute();
|
||||||
assertThat(readPatient.getMeta().getExtensionString(Constants.EXT_META_SOURCE), matchesPattern("#[a-zA-Z0-9]+"));
|
assertThat(readPatient.getMeta().getExtensionString(HapiExtensions.EXT_META_SOURCE), matchesPattern("#[a-zA-Z0-9]+"));
|
||||||
|
|
||||||
readPatient.addName().setFamily("testUpdateWithSource");
|
readPatient.addName().setFamily("testUpdateWithSource");
|
||||||
ourClient.update().resource(readPatient).execute();
|
ourClient.update().resource(readPatient).execute();
|
||||||
readPatient = (Patient) ourClient.read().resource("Patient").withId(patientid).execute();
|
readPatient = (Patient) ourClient.read().resource("Patient").withId(patientid).execute();
|
||||||
assertThat(readPatient.getMeta().getExtensionString(Constants.EXT_META_SOURCE), matchesPattern("#[a-zA-Z0-9]+"));
|
assertThat(readPatient.getMeta().getExtensionString(HapiExtensions.EXT_META_SOURCE), matchesPattern("#[a-zA-Z0-9]+"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
@ -208,7 +209,7 @@ public class BinaryAccessProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
assertEquals(15, attachment.getSize());
|
assertEquals(15, attachment.getSize());
|
||||||
assertEquals(null, attachment.getData());
|
assertEquals(null, attachment.getData());
|
||||||
assertEquals("2", ref.getMeta().getVersionId());
|
assertEquals("2", ref.getMeta().getVersionId());
|
||||||
attachmentId = attachment.getDataElement().getExtensionString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID);
|
attachmentId = attachment.getDataElement().getExtensionString(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID);
|
||||||
assertThat(attachmentId, matchesPattern("[a-zA-Z0-9]{100}"));
|
assertThat(attachmentId, matchesPattern("[a-zA-Z0-9]{100}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,7 +267,7 @@ public class BinaryAccessProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
assertEquals(15, attachment.getSize());
|
assertEquals(15, attachment.getSize());
|
||||||
assertEquals(null, attachment.getData());
|
assertEquals(null, attachment.getData());
|
||||||
assertEquals("2", ref.getMeta().getVersionId());
|
assertEquals("2", ref.getMeta().getVersionId());
|
||||||
attachmentId = attachment.getDataElement().getExtensionString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID);
|
attachmentId = attachment.getDataElement().getExtensionString(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID);
|
||||||
assertThat(attachmentId, matchesPattern("[a-zA-Z0-9]{100}"));
|
assertThat(attachmentId, matchesPattern("[a-zA-Z0-9]{100}"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -301,7 +302,7 @@ public class BinaryAccessProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
dr.addContent()
|
dr.addContent()
|
||||||
.getAttachment()
|
.getAttachment()
|
||||||
.getDataElement()
|
.getDataElement()
|
||||||
.addExtension(JpaConstants.EXT_EXTERNALIZED_BINARY_ID, new StringType("0000-1111") );
|
.addExtension(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID, new StringType("0000-1111") );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ourClient.create().resource(dr).execute();
|
ourClient.create().resource(dr).execute();
|
||||||
|
@ -347,7 +348,7 @@ public class BinaryAccessProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
assertEquals(4, attachment.getSize());
|
assertEquals(4, attachment.getSize());
|
||||||
assertArrayEquals(SOME_BYTES_2, attachment.getData());
|
assertArrayEquals(SOME_BYTES_2, attachment.getData());
|
||||||
assertEquals("2", ref.getMeta().getVersionId());
|
assertEquals("2", ref.getMeta().getVersionId());
|
||||||
attachmentId = attachment.getExtensionString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID);
|
attachmentId = attachment.getExtensionString(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID);
|
||||||
assertEquals(null, attachmentId);
|
assertEquals(null, attachmentId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -397,7 +398,7 @@ public class BinaryAccessProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
assertEquals(ContentType.IMAGE_JPEG.getMimeType(), target.getContentType());
|
assertEquals(ContentType.IMAGE_JPEG.getMimeType(), target.getContentType());
|
||||||
assertEquals(null, target.getData());
|
assertEquals(null, target.getData());
|
||||||
assertEquals("2", target.getMeta().getVersionId());
|
assertEquals("2", target.getMeta().getVersionId());
|
||||||
attachmentId = target.getDataElement().getExtensionString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID);
|
attachmentId = target.getDataElement().getExtensionString(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID);
|
||||||
assertThat(attachmentId, matchesPattern("[a-zA-Z0-9]{100}"));
|
assertThat(attachmentId, matchesPattern("[a-zA-Z0-9]{100}"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -458,7 +459,7 @@ public class BinaryAccessProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
assertEquals(ContentType.IMAGE_JPEG.getMimeType(), target.getContentType());
|
assertEquals(ContentType.IMAGE_JPEG.getMimeType(), target.getContentType());
|
||||||
assertEquals(null, target.getData());
|
assertEquals(null, target.getData());
|
||||||
assertEquals("2", target.getMeta().getVersionId());
|
assertEquals("2", target.getMeta().getVersionId());
|
||||||
attachmentId = target.getDataElement().getExtensionString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID);
|
attachmentId = target.getDataElement().getExtensionString(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID);
|
||||||
assertThat(attachmentId, matchesPattern("[a-zA-Z0-9]{100}"));
|
assertThat(attachmentId, matchesPattern("[a-zA-Z0-9]{100}"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -522,7 +523,7 @@ public class BinaryAccessProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
String response = IOUtils.toString(resp.getEntity().getContent(), Constants.CHARSET_UTF8);
|
String response = IOUtils.toString(resp.getEntity().getContent(), Constants.CHARSET_UTF8);
|
||||||
DocumentReference ref = myFhirCtx.newJsonParser().parseResource(DocumentReference.class, response);
|
DocumentReference ref = myFhirCtx.newJsonParser().parseResource(DocumentReference.class, response);
|
||||||
Attachment attachment = ref.getContentFirstRep().getAttachment();
|
Attachment attachment = ref.getContentFirstRep().getAttachment();
|
||||||
attachmentId = attachment.getDataElement().getExtensionString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID);
|
attachmentId = attachment.getDataElement().getExtensionString(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID);
|
||||||
assertThat(attachmentId, matchesPattern("[a-zA-Z0-9]{100}"));
|
assertThat(attachmentId, matchesPattern("[a-zA-Z0-9]{100}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,8 @@ import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
||||||
import ca.uhn.fhir.jpa.binstore.BinaryStorageInterceptor;
|
import ca.uhn.fhir.jpa.binstore.BinaryStorageInterceptor;
|
||||||
import ca.uhn.fhir.jpa.binstore.IBinaryStorageSvc;
|
import ca.uhn.fhir.jpa.binstore.IBinaryStorageSvc;
|
||||||
import ca.uhn.fhir.jpa.binstore.MemoryBinaryStorageSvcImpl;
|
import ca.uhn.fhir.jpa.binstore.MemoryBinaryStorageSvcImpl;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.Binary;
|
import org.hl7.fhir.r4.model.Binary;
|
||||||
import org.hl7.fhir.r4.model.DocumentReference;
|
import org.hl7.fhir.r4.model.DocumentReference;
|
||||||
|
@ -74,7 +74,7 @@ public class BinaryStorageInterceptorR4Test extends BaseResourceProviderR4Test {
|
||||||
IIdType id = outcome.getId().toUnqualifiedVersionless();
|
IIdType id = outcome.getId().toUnqualifiedVersionless();
|
||||||
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getResource());
|
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getResource());
|
||||||
ourLog.info("Encoded: {}", encoded);
|
ourLog.info("Encoded: {}", encoded);
|
||||||
assertThat(encoded, containsString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID));
|
assertThat(encoded, containsString(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID));
|
||||||
assertThat(encoded, not(containsString("\"data\"")));
|
assertThat(encoded, not(containsString("\"data\"")));
|
||||||
|
|
||||||
// Now read it back and make sure it was de-externalized
|
// Now read it back and make sure it was de-externalized
|
||||||
|
@ -98,7 +98,7 @@ public class BinaryStorageInterceptorR4Test extends BaseResourceProviderR4Test {
|
||||||
IIdType id = outcome.getId().toUnqualifiedVersionless();
|
IIdType id = outcome.getId().toUnqualifiedVersionless();
|
||||||
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getResource());
|
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getResource());
|
||||||
ourLog.info("Encoded: {}", encoded);
|
ourLog.info("Encoded: {}", encoded);
|
||||||
assertThat(encoded, containsString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID));
|
assertThat(encoded, containsString(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID));
|
||||||
assertThat(encoded, not(containsString("\"data\"")));
|
assertThat(encoded, not(containsString("\"data\"")));
|
||||||
|
|
||||||
// Now read it back and make sure it was de-externalized
|
// Now read it back and make sure it was de-externalized
|
||||||
|
@ -123,7 +123,7 @@ public class BinaryStorageInterceptorR4Test extends BaseResourceProviderR4Test {
|
||||||
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getResource());
|
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getResource());
|
||||||
ourLog.info("Encoded: {}", encoded);
|
ourLog.info("Encoded: {}", encoded);
|
||||||
assertThat(encoded, containsString("\"data\": \"BAMCAQ==\""));
|
assertThat(encoded, containsString("\"data\": \"BAMCAQ==\""));
|
||||||
assertThat(encoded, not(containsString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID)));
|
assertThat(encoded, not(containsString(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID)));
|
||||||
|
|
||||||
// Now read it back and make sure it was de-externalized
|
// Now read it back and make sure it was de-externalized
|
||||||
Binary output = myBinaryDao.read(id, mySrd);
|
Binary output = myBinaryDao.read(id, mySrd);
|
||||||
|
@ -146,14 +146,14 @@ public class BinaryStorageInterceptorR4Test extends BaseResourceProviderR4Test {
|
||||||
IIdType id = outcome.getId().toUnqualifiedVersionless();
|
IIdType id = outcome.getId().toUnqualifiedVersionless();
|
||||||
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getResource());
|
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getResource());
|
||||||
ourLog.info("Encoded: {}", encoded);
|
ourLog.info("Encoded: {}", encoded);
|
||||||
assertThat(encoded, containsString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID));
|
assertThat(encoded, containsString(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID));
|
||||||
assertThat(encoded, not(containsString("\"data\"")));
|
assertThat(encoded, not(containsString("\"data\"")));
|
||||||
|
|
||||||
// Now read it back and make sure it was de-externalized
|
// Now read it back and make sure it was de-externalized
|
||||||
Binary output = myBinaryDao.read(id, mySrd);
|
Binary output = myBinaryDao.read(id, mySrd);
|
||||||
assertEquals("application/octet-stream", output.getContentType());
|
assertEquals("application/octet-stream", output.getContentType());
|
||||||
assertArrayEquals(SOME_BYTES, output.getData());
|
assertArrayEquals(SOME_BYTES, output.getData());
|
||||||
assertNotNull(output.getDataElement().getExtensionByUrl(JpaConstants.EXT_EXTERNALIZED_BINARY_ID).getValue());
|
assertNotNull(output.getDataElement().getExtensionByUrl(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID).getValue());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ public class BinaryStorageInterceptorR4Test extends BaseResourceProviderR4Test {
|
||||||
IIdType id = outcome.getId().toUnqualifiedVersionless();
|
IIdType id = outcome.getId().toUnqualifiedVersionless();
|
||||||
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getResource());
|
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getResource());
|
||||||
ourLog.info("Encoded: {}", encoded);
|
ourLog.info("Encoded: {}", encoded);
|
||||||
assertThat(encoded, containsString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID));
|
assertThat(encoded, containsString(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID));
|
||||||
assertThat(encoded, not(containsString("\"data\"")));
|
assertThat(encoded, not(containsString("\"data\"")));
|
||||||
|
|
||||||
// Now update
|
// Now update
|
||||||
|
@ -212,9 +212,9 @@ public class BinaryStorageInterceptorR4Test extends BaseResourceProviderR4Test {
|
||||||
IIdType id = outcome.getId().toUnqualifiedVersionless();
|
IIdType id = outcome.getId().toUnqualifiedVersionless();
|
||||||
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getResource());
|
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getResource());
|
||||||
ourLog.info("Encoded: {}", encoded);
|
ourLog.info("Encoded: {}", encoded);
|
||||||
assertThat(encoded, containsString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID));
|
assertThat(encoded, containsString(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID));
|
||||||
assertThat(encoded, not(containsString("\"data\"")));
|
assertThat(encoded, not(containsString("\"data\"")));
|
||||||
String binaryId = docRef.getContentFirstRep().getAttachment().getDataElement().getExtensionString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID);
|
String binaryId = docRef.getContentFirstRep().getAttachment().getDataElement().getExtensionString(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID);
|
||||||
assertThat(binaryId, not(blankOrNullString()));
|
assertThat(binaryId, not(blankOrNullString()));
|
||||||
|
|
||||||
// Now update
|
// Now update
|
||||||
|
@ -223,7 +223,7 @@ public class BinaryStorageInterceptorR4Test extends BaseResourceProviderR4Test {
|
||||||
docRef.setStatus(Enumerations.DocumentReferenceStatus.CURRENT);
|
docRef.setStatus(Enumerations.DocumentReferenceStatus.CURRENT);
|
||||||
docRef.getContentFirstRep().getAttachment().setContentType("application/octet-stream");
|
docRef.getContentFirstRep().getAttachment().setContentType("application/octet-stream");
|
||||||
docRef.getContentFirstRep().getAttachment().getDataElement().addExtension(
|
docRef.getContentFirstRep().getAttachment().getDataElement().addExtension(
|
||||||
JpaConstants.EXT_EXTERNALIZED_BINARY_ID,
|
HapiExtensions.EXT_EXTERNALIZED_BINARY_ID,
|
||||||
new StringType(binaryId)
|
new StringType(binaryId)
|
||||||
);
|
);
|
||||||
outcome = myDocumentReferenceDao.update(docRef, mySrd);
|
outcome = myDocumentReferenceDao.update(docRef, mySrd);
|
||||||
|
@ -259,9 +259,9 @@ public class BinaryStorageInterceptorR4Test extends BaseResourceProviderR4Test {
|
||||||
IIdType id = outcome.getId().toUnqualifiedVersionless();
|
IIdType id = outcome.getId().toUnqualifiedVersionless();
|
||||||
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getResource());
|
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getResource());
|
||||||
ourLog.info("Encoded: {}", encoded);
|
ourLog.info("Encoded: {}", encoded);
|
||||||
assertThat(encoded, containsString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID));
|
assertThat(encoded, containsString(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID));
|
||||||
assertThat(encoded, not(containsString("\"data\"")));
|
assertThat(encoded, not(containsString("\"data\"")));
|
||||||
String binaryId = docRef.getContentFirstRep().getAttachment().getDataElement().getExtensionString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID);
|
String binaryId = docRef.getContentFirstRep().getAttachment().getDataElement().getExtensionString(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID);
|
||||||
assertThat(binaryId, not(blankOrNullString()));
|
assertThat(binaryId, not(blankOrNullString()));
|
||||||
|
|
||||||
// Now update
|
// Now update
|
||||||
|
@ -271,13 +271,13 @@ public class BinaryStorageInterceptorR4Test extends BaseResourceProviderR4Test {
|
||||||
content = docRef.addContent();
|
content = docRef.addContent();
|
||||||
content.getAttachment().setContentType("application/octet-stream");
|
content.getAttachment().setContentType("application/octet-stream");
|
||||||
content.getAttachment().getDataElement().addExtension(
|
content.getAttachment().getDataElement().addExtension(
|
||||||
JpaConstants.EXT_EXTERNALIZED_BINARY_ID,
|
HapiExtensions.EXT_EXTERNALIZED_BINARY_ID,
|
||||||
new StringType(binaryId)
|
new StringType(binaryId)
|
||||||
);
|
);
|
||||||
content2 = docRef.addContent();
|
content2 = docRef.addContent();
|
||||||
content2.getAttachment().setContentType("application/octet-stream");
|
content2.getAttachment().setContentType("application/octet-stream");
|
||||||
content2.getAttachment().getDataElement().addExtension(
|
content2.getAttachment().getDataElement().addExtension(
|
||||||
JpaConstants.EXT_EXTERNALIZED_BINARY_ID,
|
HapiExtensions.EXT_EXTERNALIZED_BINARY_ID,
|
||||||
new StringType("12345-67890")
|
new StringType("12345-67890")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -305,14 +305,14 @@ public class BinaryStorageInterceptorR4Test extends BaseResourceProviderR4Test {
|
||||||
IIdType id = outcome.getId().toUnqualifiedVersionless();
|
IIdType id = outcome.getId().toUnqualifiedVersionless();
|
||||||
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getResource());
|
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getResource());
|
||||||
ourLog.info("Encoded: {}", encoded);
|
ourLog.info("Encoded: {}", encoded);
|
||||||
assertThat(encoded, containsString(JpaConstants.EXT_EXTERNALIZED_BINARY_ID));
|
assertThat(encoded, containsString(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID));
|
||||||
assertThat(encoded, not(containsString("\"data\"")));
|
assertThat(encoded, not(containsString("\"data\"")));
|
||||||
|
|
||||||
// Now read it back and make sure it was de-externalized
|
// Now read it back and make sure it was de-externalized
|
||||||
Binary output = myBinaryDao.read(id, mySrd);
|
Binary output = myBinaryDao.read(id, mySrd);
|
||||||
assertEquals("application/octet-stream", output.getContentType());
|
assertEquals("application/octet-stream", output.getContentType());
|
||||||
assertEquals(null, output.getData());
|
assertEquals(null, output.getData());
|
||||||
assertNotNull(output.getDataElement().getExtensionByUrl(JpaConstants.EXT_EXTERNALIZED_BINARY_ID).getValue());
|
assertNotNull(output.getDataElement().getExtensionByUrl(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID).getValue());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,12 @@ import ca.uhn.fhir.jpa.api.model.ExpungeOptions;
|
||||||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
|
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
|
||||||
import ca.uhn.fhir.jpa.search.PersistedJpaSearchFirstPageBundleProvider;
|
import ca.uhn.fhir.jpa.search.PersistedJpaSearchFirstPageBundleProvider;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
|
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
@ -104,7 +104,7 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
|
||||||
.setExpression("Patient")
|
.setExpression("Patient")
|
||||||
.setDefinition("SearchParameter/patient-birthdate");
|
.setDefinition("SearchParameter/patient-birthdate");
|
||||||
sp.addExtension()
|
sp.addExtension()
|
||||||
.setUrl(SearchParamConstants.EXT_SP_UNIQUE)
|
.setUrl(HapiExtensions.EXT_SP_UNIQUE)
|
||||||
.setValue(new BooleanType(true));
|
.setValue(new BooleanType(true));
|
||||||
mySearchParameterDao.update(sp);
|
mySearchParameterDao.update(sp);
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,15 @@ import ca.uhn.fhir.jpa.subscription.channel.impl.LinkedBlockingChannel;
|
||||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionMatcherInterceptor;
|
import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionMatcherInterceptor;
|
||||||
import ca.uhn.fhir.rest.annotation.Create;
|
import ca.uhn.fhir.rest.annotation.Create;
|
||||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Transaction;
|
||||||
|
import ca.uhn.fhir.rest.annotation.TransactionParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Update;
|
import ca.uhn.fhir.rest.annotation.Update;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||||
import ca.uhn.fhir.util.BundleUtil;
|
|
||||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||||
|
import ca.uhn.fhir.util.BundleUtil;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import net.ttddyy.dsproxy.QueryCount;
|
import net.ttddyy.dsproxy.QueryCount;
|
||||||
import net.ttddyy.dsproxy.listener.SingleQueryCountHolder;
|
import net.ttddyy.dsproxy.listener.SingleQueryCountHolder;
|
||||||
|
@ -22,9 +24,19 @@ import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||||
import org.eclipse.jetty.servlet.ServletHolder;
|
import org.eclipse.jetty.servlet.ServletHolder;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.Bundle;
|
||||||
import org.junit.*;
|
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||||
|
import org.hl7.fhir.r4.model.Coding;
|
||||||
|
import org.hl7.fhir.r4.model.IdType;
|
||||||
|
import org.hl7.fhir.r4.model.Observation;
|
||||||
|
import org.hl7.fhir.r4.model.Subscription;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
@ -36,28 +48,23 @@ import java.util.List;
|
||||||
@Ignore
|
@Ignore
|
||||||
public abstract class BaseSubscriptionsR4Test extends BaseResourceProviderR4Test {
|
public abstract class BaseSubscriptionsR4Test extends BaseResourceProviderR4Test {
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseSubscriptionsR4Test.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseSubscriptionsR4Test.class);
|
||||||
|
protected static int ourListenerPort;
|
||||||
private static Server ourListenerServer;
|
|
||||||
protected static int ourListenerPort;
|
|
||||||
protected static List<String> ourContentTypes = Collections.synchronizedList(new ArrayList<>());
|
protected static List<String> ourContentTypes = Collections.synchronizedList(new ArrayList<>());
|
||||||
protected static List<String> ourHeaders = Collections.synchronizedList(new ArrayList<>());
|
protected static List<String> ourHeaders = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
protected static List<Bundle> ourTransactions = Collections.synchronizedList(Lists.newArrayList());
|
||||||
|
protected static List<Observation> ourCreatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||||
|
protected static List<Observation> ourUpdatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||||
|
private static Server ourListenerServer;
|
||||||
private static SingleQueryCountHolder ourCountHolder;
|
private static SingleQueryCountHolder ourCountHolder;
|
||||||
|
private static String ourListenerServerBase;
|
||||||
@Autowired
|
|
||||||
private SingleQueryCountHolder myCountHolder;
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected SubscriptionTestUtil mySubscriptionTestUtil;
|
protected SubscriptionTestUtil mySubscriptionTestUtil;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected SubscriptionMatcherInterceptor mySubscriptionMatcherInterceptor;
|
protected SubscriptionMatcherInterceptor mySubscriptionMatcherInterceptor;
|
||||||
|
|
||||||
protected CountingInterceptor myCountingInterceptor;
|
protected CountingInterceptor myCountingInterceptor;
|
||||||
|
|
||||||
protected static List<Observation> ourCreatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
|
||||||
protected static List<Observation> ourUpdatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
|
||||||
private static String ourListenerServerBase;
|
|
||||||
|
|
||||||
protected List<IIdType> mySubscriptionIds = Collections.synchronizedList(new ArrayList<>());
|
protected List<IIdType> mySubscriptionIds = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
@Autowired
|
||||||
|
private SingleQueryCountHolder myCountHolder;
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void afterUnregisterRestHookListener() {
|
public void afterUnregisterRestHookListener() {
|
||||||
|
@ -87,6 +94,7 @@ public abstract class BaseSubscriptionsR4Test extends BaseResourceProviderR4Test
|
||||||
public void beforeReset() throws Exception {
|
public void beforeReset() throws Exception {
|
||||||
ourCreatedObservations.clear();
|
ourCreatedObservations.clear();
|
||||||
ourUpdatedObservations.clear();
|
ourUpdatedObservations.clear();
|
||||||
|
ourTransactions.clear();
|
||||||
ourContentTypes.clear();
|
ourContentTypes.clear();
|
||||||
ourHeaders.clear();
|
ourHeaders.clear();
|
||||||
|
|
||||||
|
@ -162,8 +170,7 @@ public abstract class BaseSubscriptionsR4Test extends BaseResourceProviderR4Test
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class ObservationResourceProvider implements IResourceProvider {
|
||||||
public static class ObservationListener implements IResourceProvider {
|
|
||||||
|
|
||||||
@Create
|
@Create
|
||||||
public MethodOutcome create(@ResourceParam Observation theObservation, HttpServletRequest theRequest) {
|
public MethodOutcome create(@ResourceParam Observation theObservation, HttpServletRequest theRequest) {
|
||||||
|
@ -202,6 +209,17 @@ public abstract class BaseSubscriptionsR4Test extends BaseResourceProviderR4Test
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class PlainProvider {
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
public Bundle transaction(@TransactionParam Bundle theInput) {
|
||||||
|
ourLog.info("Received transaction update");
|
||||||
|
ourTransactions.add(theInput);
|
||||||
|
return theInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void reportTotalSelects() {
|
public static void reportTotalSelects() {
|
||||||
ourLog.info("Total database select queries: {}", getQueryCount().getSelect());
|
ourLog.info("Total database select queries: {}", getQueryCount().getSelect());
|
||||||
|
@ -214,9 +232,9 @@ public abstract class BaseSubscriptionsR4Test extends BaseResourceProviderR4Test
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void startListenerServer() throws Exception {
|
public static void startListenerServer() throws Exception {
|
||||||
RestfulServer ourListenerRestServer = new RestfulServer(FhirContext.forR4());
|
RestfulServer ourListenerRestServer = new RestfulServer(FhirContext.forR4());
|
||||||
|
|
||||||
ObservationListener obsListener = new ObservationListener();
|
ourListenerRestServer.registerProvider(new ObservationResourceProvider());
|
||||||
ourListenerRestServer.setResourceProviders(obsListener);
|
ourListenerRestServer.registerProvider(new PlainProvider());
|
||||||
|
|
||||||
ourListenerServer = new Server(0);
|
ourListenerServer = new Server(0);
|
||||||
|
|
||||||
|
@ -229,8 +247,8 @@ public abstract class BaseSubscriptionsR4Test extends BaseResourceProviderR4Test
|
||||||
|
|
||||||
ourListenerServer.setHandler(proxyHandler);
|
ourListenerServer.setHandler(proxyHandler);
|
||||||
JettyUtil.startServer(ourListenerServer);
|
JettyUtil.startServer(ourListenerServer);
|
||||||
ourListenerPort = JettyUtil.getPortForStartedServer(ourListenerServer);
|
ourListenerPort = JettyUtil.getPortForStartedServer(ourListenerServer);
|
||||||
ourListenerServerBase = "http://localhost:" + ourListenerPort + "/fhir/context";
|
ourListenerServerBase = "http://localhost:" + ourListenerPort + "/fhir/context";
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
|
|
|
@ -85,6 +85,8 @@ public class SubscriptionValidatingInterceptorTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidate_RestHook_NoEndpoint() {
|
public void testValidate_RestHook_NoEndpoint() {
|
||||||
|
when(myDaoRegistry.isResourceTypeSupported(eq("Patient"))).thenReturn(true);
|
||||||
|
|
||||||
Subscription subscription = new Subscription();
|
Subscription subscription = new Subscription();
|
||||||
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE);
|
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE);
|
||||||
subscription.setCriteria("Patient?identifier=foo");
|
subscription.setCriteria("Patient?identifier=foo");
|
||||||
|
@ -102,6 +104,8 @@ public class SubscriptionValidatingInterceptorTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidate_RestHook_NoType() {
|
public void testValidate_RestHook_NoType() {
|
||||||
|
when(myDaoRegistry.isResourceTypeSupported(eq("Patient"))).thenReturn(true);
|
||||||
|
|
||||||
Subscription subscription = new Subscription();
|
Subscription subscription = new Subscription();
|
||||||
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE);
|
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE);
|
||||||
subscription.setCriteria("Patient?identifier=foo");
|
subscription.setCriteria("Patient?identifier=foo");
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package ca.uhn.fhir.jpa.subscription.email;
|
package ca.uhn.fhir.jpa.subscription.email;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
|
||||||
import ca.uhn.fhir.jpa.provider.dstu3.BaseResourceProviderDstu3Test;
|
import ca.uhn.fhir.jpa.provider.dstu3.BaseResourceProviderDstu3Test;
|
||||||
import ca.uhn.fhir.jpa.subscription.SubscriptionTestUtil;
|
import ca.uhn.fhir.jpa.subscription.SubscriptionTestUtil;
|
||||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import com.icegreen.greenmail.store.FolderException;
|
import com.icegreen.greenmail.store.FolderException;
|
||||||
import com.icegreen.greenmail.util.GreenMail;
|
import com.icegreen.greenmail.util.GreenMail;
|
||||||
import com.icegreen.greenmail.util.ServerSetup;
|
import com.icegreen.greenmail.util.ServerSetup;
|
||||||
|
@ -166,10 +166,10 @@ public class EmailSubscriptionDstu3Test extends BaseResourceProviderDstu3Test {
|
||||||
Assert.assertNotNull(subscriptionTemp);
|
Assert.assertNotNull(subscriptionTemp);
|
||||||
|
|
||||||
subscriptionTemp.getChannel().addExtension()
|
subscriptionTemp.getChannel().addExtension()
|
||||||
.setUrl(JpaConstants.EXT_SUBSCRIPTION_EMAIL_FROM)
|
.setUrl(HapiExtensions.EXT_SUBSCRIPTION_EMAIL_FROM)
|
||||||
.setValue(new StringType("mailto:myfrom@from.com"));
|
.setValue(new StringType("mailto:myfrom@from.com"));
|
||||||
subscriptionTemp.getChannel().addExtension()
|
subscriptionTemp.getChannel().addExtension()
|
||||||
.setUrl(JpaConstants.EXT_SUBSCRIPTION_SUBJECT_TEMPLATE)
|
.setUrl(HapiExtensions.EXT_SUBSCRIPTION_SUBJECT_TEMPLATE)
|
||||||
.setValue(new StringType("This is a subject"));
|
.setValue(new StringType("This is a subject"));
|
||||||
subscriptionTemp.setIdElement(subscriptionTemp.getIdElement().toUnqualifiedVersionless());
|
subscriptionTemp.setIdElement(subscriptionTemp.getIdElement().toUnqualifiedVersionless());
|
||||||
|
|
||||||
|
@ -220,10 +220,10 @@ public class EmailSubscriptionDstu3Test extends BaseResourceProviderDstu3Test {
|
||||||
Subscription subscriptionTemp = ourClient.read(Subscription.class, sub1.getId());
|
Subscription subscriptionTemp = ourClient.read(Subscription.class, sub1.getId());
|
||||||
Assert.assertNotNull(subscriptionTemp);
|
Assert.assertNotNull(subscriptionTemp);
|
||||||
subscriptionTemp.getChannel().addExtension()
|
subscriptionTemp.getChannel().addExtension()
|
||||||
.setUrl(JpaConstants.EXT_SUBSCRIPTION_EMAIL_FROM)
|
.setUrl(HapiExtensions.EXT_SUBSCRIPTION_EMAIL_FROM)
|
||||||
.setValue(new StringType("myfrom@from.com"));
|
.setValue(new StringType("myfrom@from.com"));
|
||||||
subscriptionTemp.getChannel().addExtension()
|
subscriptionTemp.getChannel().addExtension()
|
||||||
.setUrl(JpaConstants.EXT_SUBSCRIPTION_SUBJECT_TEMPLATE)
|
.setUrl(HapiExtensions.EXT_SUBSCRIPTION_SUBJECT_TEMPLATE)
|
||||||
.setValue(new StringType("This is a subject"));
|
.setValue(new StringType("This is a subject"));
|
||||||
subscriptionTemp.setIdElement(subscriptionTemp.getIdElement().toUnqualifiedVersionless());
|
subscriptionTemp.setIdElement(subscriptionTemp.getIdElement().toUnqualifiedVersionless());
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ package ca.uhn.fhir.jpa.subscription.resthook;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
|
||||||
import ca.uhn.fhir.jpa.provider.dstu3.BaseResourceProviderDstu3Test;
|
import ca.uhn.fhir.jpa.provider.dstu3.BaseResourceProviderDstu3Test;
|
||||||
import ca.uhn.fhir.jpa.subscription.NotificationServlet;
|
import ca.uhn.fhir.jpa.subscription.NotificationServlet;
|
||||||
import ca.uhn.fhir.jpa.subscription.SubscriptionTestUtil;
|
import ca.uhn.fhir.jpa.subscription.SubscriptionTestUtil;
|
||||||
|
@ -18,6 +17,7 @@ import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import ca.uhn.fhir.util.MetaUtil;
|
import ca.uhn.fhir.util.MetaUtil;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
|
@ -158,7 +158,7 @@ public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test {
|
||||||
String databaseCriteria = "Observation?code=17861-6&context.type=IHD";
|
String databaseCriteria = "Observation?code=17861-6&context.type=IHD";
|
||||||
Subscription subscription = createSubscription(databaseCriteria, null, ourNotificationListenerServer);
|
Subscription subscription = createSubscription(databaseCriteria, null, ourNotificationListenerServer);
|
||||||
List<Coding> tag = subscription.getMeta().getTag();
|
List<Coding> tag = subscription.getMeta().getTag();
|
||||||
assertEquals(JpaConstants.EXT_SUBSCRIPTION_MATCHING_STRATEGY, tag.get(0).getSystem());
|
assertEquals(HapiExtensions.EXT_SUBSCRIPTION_MATCHING_STRATEGY, tag.get(0).getSystem());
|
||||||
assertEquals(SubscriptionMatchingStrategy.DATABASE.toString(), tag.get(0).getCode());
|
assertEquals(SubscriptionMatchingStrategy.DATABASE.toString(), tag.get(0).getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test {
|
||||||
Subscription subscription = createSubscription(inMemoryCriteria, null, ourNotificationListenerServer);
|
Subscription subscription = createSubscription(inMemoryCriteria, null, ourNotificationListenerServer);
|
||||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(subscription));
|
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(subscription));
|
||||||
List<Coding> tag = subscription.getMeta().getTag();
|
List<Coding> tag = subscription.getMeta().getTag();
|
||||||
assertEquals(JpaConstants.EXT_SUBSCRIPTION_MATCHING_STRATEGY, tag.get(0).getSystem());
|
assertEquals(HapiExtensions.EXT_SUBSCRIPTION_MATCHING_STRATEGY, tag.get(0).getSystem());
|
||||||
assertEquals(SubscriptionMatchingStrategy.IN_MEMORY.toString(), tag.get(0).getCode());
|
assertEquals(SubscriptionMatchingStrategy.IN_MEMORY.toString(), tag.get(0).getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,7 +497,7 @@ public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test {
|
||||||
List<Coding> tags = subscriptionOrig.getMeta().getTag();
|
List<Coding> tags = subscriptionOrig.getMeta().getTag();
|
||||||
assertEquals(1, tags.size());
|
assertEquals(1, tags.size());
|
||||||
Coding tag = tags.get(0);
|
Coding tag = tags.get(0);
|
||||||
assertEquals(JpaConstants.EXT_SUBSCRIPTION_MATCHING_STRATEGY, tag.getSystem());
|
assertEquals(HapiExtensions.EXT_SUBSCRIPTION_MATCHING_STRATEGY, tag.getSystem());
|
||||||
assertEquals(SubscriptionMatchingStrategy.IN_MEMORY.toString(), tag.getCode());
|
assertEquals(SubscriptionMatchingStrategy.IN_MEMORY.toString(), tag.getCode());
|
||||||
assertEquals("In-memory", tag.getDisplay());
|
assertEquals("In-memory", tag.getDisplay());
|
||||||
|
|
||||||
|
@ -515,7 +515,7 @@ public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test {
|
||||||
tags = theSubscription.getMeta().getTag();
|
tags = theSubscription.getMeta().getTag();
|
||||||
assertEquals(1, tags.size());
|
assertEquals(1, tags.size());
|
||||||
tag = tags.get(0);
|
tag = tags.get(0);
|
||||||
assertEquals(JpaConstants.EXT_SUBSCRIPTION_MATCHING_STRATEGY, tag.getSystem());
|
assertEquals(HapiExtensions.EXT_SUBSCRIPTION_MATCHING_STRATEGY, tag.getSystem());
|
||||||
assertEquals(SubscriptionMatchingStrategy.IN_MEMORY.toString(), tag.getCode());
|
assertEquals(SubscriptionMatchingStrategy.IN_MEMORY.toString(), tag.getCode());
|
||||||
assertEquals("In-memory", tag.getDisplay());
|
assertEquals("In-memory", tag.getDisplay());
|
||||||
}
|
}
|
||||||
|
@ -530,7 +530,7 @@ public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test {
|
||||||
List<Coding> tags = subscriptionOrig.getMeta().getTag();
|
List<Coding> tags = subscriptionOrig.getMeta().getTag();
|
||||||
assertEquals(1, tags.size());
|
assertEquals(1, tags.size());
|
||||||
Coding tag = tags.get(0);
|
Coding tag = tags.get(0);
|
||||||
assertEquals(JpaConstants.EXT_SUBSCRIPTION_MATCHING_STRATEGY, tag.getSystem());
|
assertEquals(HapiExtensions.EXT_SUBSCRIPTION_MATCHING_STRATEGY, tag.getSystem());
|
||||||
assertEquals(SubscriptionMatchingStrategy.DATABASE.toString(), tag.getCode());
|
assertEquals(SubscriptionMatchingStrategy.DATABASE.toString(), tag.getCode());
|
||||||
assertEquals("Database", tag.getDisplay());
|
assertEquals("Database", tag.getDisplay());
|
||||||
|
|
||||||
|
@ -542,7 +542,7 @@ public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test {
|
||||||
tags = subscription.getMeta().getTag();
|
tags = subscription.getMeta().getTag();
|
||||||
assertEquals(1, tags.size());
|
assertEquals(1, tags.size());
|
||||||
tag = tags.get(0);
|
tag = tags.get(0);
|
||||||
assertEquals(JpaConstants.EXT_SUBSCRIPTION_MATCHING_STRATEGY, tag.getSystem());
|
assertEquals(HapiExtensions.EXT_SUBSCRIPTION_MATCHING_STRATEGY, tag.getSystem());
|
||||||
assertEquals(SubscriptionMatchingStrategy.DATABASE.toString(), tag.getCode());
|
assertEquals(SubscriptionMatchingStrategy.DATABASE.toString(), tag.getCode());
|
||||||
assertEquals("Database", tag.getDisplay());
|
assertEquals("Database", tag.getDisplay());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package ca.uhn.fhir.jpa.subscription.resthook;
|
package ca.uhn.fhir.jpa.subscription.resthook;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.config.StoppableSubscriptionDeliveringRestHookSubscriber;
|
import ca.uhn.fhir.jpa.config.StoppableSubscriptionDeliveringRestHookSubscriber;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
|
||||||
import ca.uhn.fhir.jpa.subscription.BaseSubscriptionsR4Test;
|
import ca.uhn.fhir.jpa.subscription.BaseSubscriptionsR4Test;
|
||||||
import ca.uhn.fhir.rest.api.CacheControlDirective;
|
import ca.uhn.fhir.rest.api.CacheControlDirective;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.*;
|
||||||
|
@ -337,7 +337,7 @@ public class RestHookTestR4Test extends BaseSubscriptionsR4Test {
|
||||||
|
|
||||||
subscription1
|
subscription1
|
||||||
.getChannel()
|
.getChannel()
|
||||||
.addExtension(JpaConstants.EXT_SUBSCRIPTION_RESTHOOK_STRIP_VERSION_IDS, new BooleanType("true"));
|
.addExtension(HapiExtensions.EXT_SUBSCRIPTION_RESTHOOK_STRIP_VERSION_IDS, new BooleanType("true"));
|
||||||
ourLog.info("** About to update subscription");
|
ourLog.info("** About to update subscription");
|
||||||
|
|
||||||
int modCount = (int) myCountingInterceptor.getSentCount("Subscription");
|
int modCount = (int) myCountingInterceptor.getSentCount("Subscription");
|
||||||
|
@ -413,7 +413,7 @@ public class RestHookTestR4Test extends BaseSubscriptionsR4Test {
|
||||||
Subscription subscription = newSubscription(criteria1, payload);
|
Subscription subscription = newSubscription(criteria1, payload);
|
||||||
subscription
|
subscription
|
||||||
.getChannel()
|
.getChannel()
|
||||||
.addExtension(JpaConstants.EXT_SUBSCRIPTION_RESTHOOK_DELIVER_LATEST_VERSION, new BooleanType("true"));
|
.addExtension(HapiExtensions.EXT_SUBSCRIPTION_RESTHOOK_DELIVER_LATEST_VERSION, new BooleanType("true"));
|
||||||
ourClient.create().resource(subscription).execute();
|
ourClient.create().resource(subscription).execute();
|
||||||
|
|
||||||
waitForActivatedSubscriptionCount(1);
|
waitForActivatedSubscriptionCount(1);
|
||||||
|
@ -1013,4 +1013,39 @@ public class RestHookTestR4Test extends BaseSubscriptionsR4Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeliverSearchResult() throws Exception {
|
||||||
|
{
|
||||||
|
Subscription subscription = newSubscription("Observation?", "application/json");
|
||||||
|
subscription.addExtension(HapiExtensions.EXT_SUBSCRIPTION_PAYLOAD_SEARCH_CRITERIA, new StringType("Observation?_id=${matched_resource_id}&_include=*"));
|
||||||
|
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(subscription));
|
||||||
|
MethodOutcome methodOutcome = ourClient.create().resource(subscription).execute();
|
||||||
|
mySubscriptionIds.add(methodOutcome.getId());
|
||||||
|
waitForActivatedSubscriptionCount(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.setActive(true);
|
||||||
|
IIdType patientId = ourClient.create().resource(patient).execute().getId();
|
||||||
|
|
||||||
|
Observation observation = new Observation();
|
||||||
|
observation.addExtension().setUrl("Observation#accessType").setValue(new Coding().setCode("Catheter"));
|
||||||
|
observation.getSubject().setReferenceElement(patientId.toUnqualifiedVersionless());
|
||||||
|
MethodOutcome methodOutcome = ourClient.create().resource(observation).execute();
|
||||||
|
assertEquals(true, methodOutcome.getCreated());
|
||||||
|
|
||||||
|
waitForQueueToDrain();
|
||||||
|
waitForSize(1, ourTransactions);
|
||||||
|
|
||||||
|
ourLog.info("Received transaction: {}", myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(ourTransactions.get(0)));
|
||||||
|
|
||||||
|
Bundle xact = ourTransactions.get(0);
|
||||||
|
assertEquals(2, xact.getEntry().size());
|
||||||
|
|
||||||
|
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(ourTransactions.get(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package ca.uhn.fhir.jpa.subscription.resthook;
|
package ca.uhn.fhir.jpa.subscription.resthook;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.config.StoppableSubscriptionDeliveringRestHookSubscriber;
|
import ca.uhn.fhir.jpa.config.StoppableSubscriptionDeliveringRestHookSubscriber;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
|
||||||
import ca.uhn.fhir.jpa.subscription.BaseSubscriptionsR5Test;
|
import ca.uhn.fhir.jpa.subscription.BaseSubscriptionsR5Test;
|
||||||
import ca.uhn.fhir.rest.api.CacheControlDirective;
|
import ca.uhn.fhir.rest.api.CacheControlDirective;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||||
import org.hl7.fhir.r5.model.*;
|
import org.hl7.fhir.r5.model.*;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
@ -299,7 +299,7 @@ public class RestHookTestR5Test extends BaseSubscriptionsR5Test {
|
||||||
assertEquals(observation1.getIdElement().getVersionIdPart(), idElement.getVersionIdPart());
|
assertEquals(observation1.getIdElement().getVersionIdPart(), idElement.getVersionIdPart());
|
||||||
|
|
||||||
subscription1
|
subscription1
|
||||||
.addExtension(JpaConstants.EXT_SUBSCRIPTION_RESTHOOK_STRIP_VERSION_IDS, new BooleanType("true"));
|
.addExtension(HapiExtensions.EXT_SUBSCRIPTION_RESTHOOK_STRIP_VERSION_IDS, new BooleanType("true"));
|
||||||
ourLog.info("** About to update subscription");
|
ourLog.info("** About to update subscription");
|
||||||
|
|
||||||
int modCount = myCountingInterceptor.getSentCount("Subscription");
|
int modCount = myCountingInterceptor.getSentCount("Subscription");
|
||||||
|
@ -375,7 +375,7 @@ public class RestHookTestR5Test extends BaseSubscriptionsR5Test {
|
||||||
|
|
||||||
Subscription subscription = newSubscription(criteria1, payload);
|
Subscription subscription = newSubscription(criteria1, payload);
|
||||||
subscription
|
subscription
|
||||||
.addExtension(JpaConstants.EXT_SUBSCRIPTION_RESTHOOK_DELIVER_LATEST_VERSION, new BooleanType("true"));
|
.addExtension(HapiExtensions.EXT_SUBSCRIPTION_RESTHOOK_DELIVER_LATEST_VERSION, new BooleanType("true"));
|
||||||
ourClient.create().resource(subscription).execute();
|
ourClient.create().resource(subscription).execute();
|
||||||
|
|
||||||
waitForActivatedSubscriptionCount(1);
|
waitForActivatedSubscriptionCount(1);
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package ca.uhn.fhir.jpa.term;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
|
import org.hl7.fhir.r4.model.CodeSystem;
|
||||||
|
import org.hl7.fhir.r4.model.CodeType;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class TermCodeSystemStorageSvcTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
|
public static final String URL_MY_CODE_SYSTEM = "http://example.com/my_code_system";
|
||||||
|
|
||||||
|
private CodeSystem createCodeSystemWithMoreThan100Concepts() {
|
||||||
|
CodeSystem codeSystem = new CodeSystem();
|
||||||
|
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
|
||||||
|
codeSystem.setContent(CodeSystem.CodeSystemContentMode.NOTPRESENT);
|
||||||
|
|
||||||
|
for (int i = 0; i < 125; i++) {
|
||||||
|
codeSystem.addConcept(new CodeSystem.ConceptDefinitionComponent(new CodeType("codeA " + i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return codeSystem;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStoreNewCodeSystemVersionForExistingCodeSystem() {
|
||||||
|
CodeSystem upload = createCodeSystemWithMoreThan100Concepts();
|
||||||
|
|
||||||
|
ResourceTable codeSystemResourceEntity = (ResourceTable)myCodeSystemDao.create(upload, mySrd).getEntity();
|
||||||
|
|
||||||
|
runInTransaction(() -> myTermCodeSystemStorageSvc.storeNewCodeSystemVersionIfNeeded(upload, codeSystemResourceEntity));
|
||||||
|
|
||||||
|
myTerminologyDeferredStorageSvc.setProcessDeferred(true);
|
||||||
|
myTerminologyDeferredStorageSvc.saveDeferred();
|
||||||
|
myTerminologyDeferredStorageSvc.saveDeferred();
|
||||||
|
|
||||||
|
assertEquals(125, myTermConceptDao.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
package ca.uhn.fhir.jpa.term;
|
package ca.uhn.fhir.jpa.term;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
|
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemVersionDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.ITermConceptDao;
|
import ca.uhn.fhir.jpa.dao.data.ITermConceptDao;
|
||||||
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
||||||
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
|
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
|
||||||
|
@ -11,6 +13,8 @@ import org.mockito.Mock;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.same;
|
import static org.mockito.ArgumentMatchers.same;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
@ -24,6 +28,8 @@ public class TermDeferredStorageSvcImplTest {
|
||||||
private ITermCodeSystemStorageSvc myTermConceptStorageSvc;
|
private ITermCodeSystemStorageSvc myTermConceptStorageSvc;
|
||||||
@Mock
|
@Mock
|
||||||
private ITermConceptDao myConceptDao;
|
private ITermConceptDao myConceptDao;
|
||||||
|
@Mock
|
||||||
|
private ITermCodeSystemVersionDao myTermCodeSystemVersionDao;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSaveDeferredWithExecutionSuspended() {
|
public void testSaveDeferredWithExecutionSuspended() {
|
||||||
|
@ -38,16 +44,45 @@ public class TermDeferredStorageSvcImplTest {
|
||||||
TermConcept concept = new TermConcept();
|
TermConcept concept = new TermConcept();
|
||||||
concept.setCode("CODE_A");
|
concept.setCode("CODE_A");
|
||||||
|
|
||||||
|
TermCodeSystemVersion myTermCodeSystemVersion = new TermCodeSystemVersion();
|
||||||
|
myTermCodeSystemVersion.setId(1L);
|
||||||
|
concept.setCodeSystemVersion(myTermCodeSystemVersion);
|
||||||
|
|
||||||
TermDeferredStorageSvcImpl svc = new TermDeferredStorageSvcImpl();
|
TermDeferredStorageSvcImpl svc = new TermDeferredStorageSvcImpl();
|
||||||
svc.setTransactionManagerForUnitTest(myTxManager);
|
svc.setTransactionManagerForUnitTest(myTxManager);
|
||||||
svc.setCodeSystemStorageSvcForUnitTest(myTermConceptStorageSvc);
|
svc.setCodeSystemStorageSvcForUnitTest(myTermConceptStorageSvc);
|
||||||
svc.setDaoConfigForUnitTest(new DaoConfig());
|
svc.setDaoConfigForUnitTest(new DaoConfig());
|
||||||
|
|
||||||
|
when(myTermCodeSystemVersionDao.findById(anyLong())).thenReturn(Optional.of(myTermCodeSystemVersion));
|
||||||
|
svc.setCodeSystemVersionDaoForUnitTest(myTermCodeSystemVersionDao);
|
||||||
svc.setProcessDeferred(true);
|
svc.setProcessDeferred(true);
|
||||||
svc.addConceptToStorageQueue(concept);
|
svc.addConceptToStorageQueue(concept);
|
||||||
svc.saveDeferred();
|
svc.saveDeferred();
|
||||||
|
|
||||||
verify(myTermConceptStorageSvc, times(1)).saveConcept(same(concept));
|
verify(myTermConceptStorageSvc, times(1)).saveConcept(same(concept));
|
||||||
verifyNoMoreInteractions(myTermConceptStorageSvc);
|
verifyNoMoreInteractions(myTermConceptStorageSvc);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSaveDeferred_Concept_StaleCodeSystemVersion() {
|
||||||
|
TermConcept concept = new TermConcept();
|
||||||
|
concept.setCode("CODE_A");
|
||||||
|
|
||||||
|
TermCodeSystemVersion myTermCodeSystemVersion = new TermCodeSystemVersion();
|
||||||
|
concept.setCodeSystemVersion(myTermCodeSystemVersion);
|
||||||
|
|
||||||
|
TermDeferredStorageSvcImpl svc = new TermDeferredStorageSvcImpl();
|
||||||
|
svc.setTransactionManagerForUnitTest(myTxManager);
|
||||||
|
svc.setCodeSystemStorageSvcForUnitTest(myTermConceptStorageSvc);
|
||||||
|
svc.setDaoConfigForUnitTest(new DaoConfig());
|
||||||
|
|
||||||
|
svc.setCodeSystemVersionDaoForUnitTest(myTermCodeSystemVersionDao);
|
||||||
|
svc.setProcessDeferred(true);
|
||||||
|
svc.addConceptToStorageQueue(concept);
|
||||||
|
svc.saveDeferred();
|
||||||
|
verify(myTermConceptStorageSvc, times(0)).saveConcept(same(concept));
|
||||||
|
verifyNoMoreInteractions(myTermConceptStorageSvc);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -10,9 +10,9 @@ import ca.uhn.fhir.jpa.entity.TermValueSetConcept;
|
||||||
import ca.uhn.fhir.jpa.entity.TermValueSetConceptDesignation;
|
import ca.uhn.fhir.jpa.entity.TermValueSetConceptDesignation;
|
||||||
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
|
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
|
||||||
import ca.uhn.fhir.jpa.term.custom.CustomTerminologySet;
|
import ca.uhn.fhir.jpa.term.custom.CustomTerminologySet;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.CodeSystem;
|
import org.hl7.fhir.r4.model.CodeSystem;
|
||||||
|
@ -796,7 +796,7 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
|
||||||
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
|
String encoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
Extension extensionByUrl = outcome.getExpansion().getExtensionByUrl(JpaConstants.EXT_VALUESET_EXPANSION_MESSAGE);
|
Extension extensionByUrl = outcome.getExpansion().getExtensionByUrl(HapiExtensions.EXT_VALUESET_EXPANSION_MESSAGE);
|
||||||
assertEquals("Unknown CodeSystem URI \"http://unknown-system\" referenced from ValueSet", extensionByUrl.getValueAsPrimitive().getValueAsString());
|
assertEquals("Unknown CodeSystem URI \"http://unknown-system\" referenced from ValueSet", extensionByUrl.getValueAsPrimitive().getValueAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>mysql</groupId>
|
<groupId>mysql</groupId>
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
<version>6.0.5</version>
|
<version>8.0.16</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!--
|
<!--
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -166,62 +166,6 @@ public class JpaConstants {
|
||||||
*/
|
*/
|
||||||
public static final String OPERATION_LASTN = "$lastn";
|
public static final String OPERATION_LASTN = "$lastn";
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* This extension should be of type <code>string</code> and should be
|
|
||||||
* placed on the <code>Subscription.channel</code> element
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public static final String EXT_SUBSCRIPTION_SUBJECT_TEMPLATE = "http://hapifhir.io/fhir/StructureDefinition/subscription-email-subject-template";
|
|
||||||
/**
|
|
||||||
* This extension URL indicates whether a REST HOOK delivery should
|
|
||||||
* include the version ID when delivering.
|
|
||||||
* <p>
|
|
||||||
* This extension should be of type <code>boolean</code> and should be
|
|
||||||
* placed on the <code>Subscription.channel</code> element.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public static final String EXT_SUBSCRIPTION_RESTHOOK_STRIP_VERSION_IDS = "http://hapifhir.io/fhir/StructureDefinition/subscription-resthook-strip-version-ids";
|
|
||||||
/**
|
|
||||||
* This extension URL indicates whether a REST HOOK delivery should
|
|
||||||
* reload the resource and deliver the latest version always. This
|
|
||||||
* could be useful for example if a resource which triggers a
|
|
||||||
* subscription gets updated many times in short succession and there
|
|
||||||
* is no value in delivering the older versions.
|
|
||||||
* <p>
|
|
||||||
* Note that if the resource is now deleted, this may cause
|
|
||||||
* the delivery to be cancelled altogether.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* This extension should be of type <code>boolean</code> and should be
|
|
||||||
* placed on the <code>Subscription.channel</code> element.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public static final String EXT_SUBSCRIPTION_RESTHOOK_DELIVER_LATEST_VERSION = "http://hapifhir.io/fhir/StructureDefinition/subscription-resthook-deliver-latest-version";
|
|
||||||
/**
|
|
||||||
* Indicate which strategy will be used to match this subscription
|
|
||||||
*/
|
|
||||||
public static final String EXT_SUBSCRIPTION_MATCHING_STRATEGY = "http://hapifhir.io/fhir/StructureDefinition/subscription-matching-strategy";
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* This extension should be of type <code>string</code> and should be
|
|
||||||
* placed on the <code>Subscription.channel</code> element
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public static final String EXT_SUBSCRIPTION_EMAIL_FROM = "http://hapifhir.io/fhir/StructureDefinition/subscription-email-from";
|
|
||||||
/**
|
|
||||||
* Extension ID for external binary references
|
|
||||||
*/
|
|
||||||
public static final String EXT_EXTERNALIZED_BINARY_ID = "http://hapifhir.io/fhir/StructureDefinition/externalized-binary-id";
|
|
||||||
/**
|
|
||||||
* Placed in system-generated extensions
|
|
||||||
*/
|
|
||||||
public static final String EXTENSION_EXT_SYSTEMDEFINED = JpaConstants.class.getName() + "_EXTENSION_EXT_SYSTEMDEFINED";
|
|
||||||
/**
|
|
||||||
* Message added to expansion valueset
|
|
||||||
*/
|
|
||||||
public static final String EXT_VALUESET_EXPANSION_MESSAGE = "http://hapifhir.io/fhir/StructureDefinition/valueset-expansion-message";
|
|
||||||
/**
|
/**
|
||||||
* Parameter for the $export operation
|
* Parameter for the $export operation
|
||||||
*/
|
*/
|
||||||
|
@ -242,11 +186,15 @@ public class JpaConstants {
|
||||||
* Parameter for the $export operation
|
* Parameter for the $export operation
|
||||||
*/
|
*/
|
||||||
public static final String PARAM_EXPORT_TYPE_FILTER = "_typeFilter";
|
public static final String PARAM_EXPORT_TYPE_FILTER = "_typeFilter";
|
||||||
|
/**
|
||||||
|
* 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";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extension URL for extension on a SearchParameter indicating that text values should not be indexed
|
* 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_TOKEN_SUPPRESS_TEXT_INDEXING = "http://hapifhir.io/fhir/StructureDefinition/searchparameter-token-suppress-text-index";
|
public static final String EXT_SEARCHPARAM_PHONETIC_ENCODER = "http://hapifhir.io/fhir/StructureDefinition/searchparameter-phonetic-encoder";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Non-instantiable
|
* Non-instantiable
|
||||||
|
|
|
@ -26,6 +26,7 @@ import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterAnd;
|
import ca.uhn.fhir.model.api.IQueryParameterAnd;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||||
|
import ca.uhn.fhir.model.api.Include;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.QualifiedParamList;
|
import ca.uhn.fhir.rest.api.QualifiedParamList;
|
||||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||||
|
@ -50,7 +51,7 @@ public class MatchUrlService {
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISearchParamRegistry mySearchParamRegistry;
|
private ISearchParamRegistry mySearchParamRegistry;
|
||||||
|
|
||||||
public SearchParameterMap translateMatchUrl(String theMatchUrl, RuntimeResourceDefinition theResourceDefinition) {
|
public SearchParameterMap translateMatchUrl(String theMatchUrl, RuntimeResourceDefinition theResourceDefinition, Flag... theFlags) {
|
||||||
SearchParameterMap paramMap = new SearchParameterMap();
|
SearchParameterMap paramMap = new SearchParameterMap();
|
||||||
List<NameValuePair> parameters = translateMatchUrl(theMatchUrl);
|
List<NameValuePair> parameters = translateMatchUrl(theMatchUrl);
|
||||||
|
|
||||||
|
@ -79,6 +80,13 @@ public class MatchUrlService {
|
||||||
|
|
||||||
for (String nextParamName : nameToParamLists.keySet()) {
|
for (String nextParamName : nameToParamLists.keySet()) {
|
||||||
List<QualifiedParamList> paramList = nameToParamLists.get(nextParamName);
|
List<QualifiedParamList> paramList = nameToParamLists.get(nextParamName);
|
||||||
|
|
||||||
|
if (theFlags != null) {
|
||||||
|
for (Flag next : theFlags) {
|
||||||
|
next.process(nextParamName, paramList, paramMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Constants.PARAM_LASTUPDATED.equals(nextParamName)) {
|
if (Constants.PARAM_LASTUPDATED.equals(nextParamName)) {
|
||||||
if (paramList != null && paramList.size() > 0) {
|
if (paramList != null && paramList.size() > 0) {
|
||||||
if (paramList.size() > 2) {
|
if (paramList.size() > 2) {
|
||||||
|
@ -131,8 +139,8 @@ public class MatchUrlService {
|
||||||
return UrlUtil.translateMatchUrl(theMatchUrl);
|
return UrlUtil.translateMatchUrl(theMatchUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IQueryParameterAnd newInstanceAnd(String theParamType) {
|
private IQueryParameterAnd<?> newInstanceAnd(String theParamType) {
|
||||||
Class<? extends IQueryParameterAnd> clazz = ResourceMetaParams.RESOURCE_META_AND_PARAMS.get(theParamType);
|
Class<? extends IQueryParameterAnd<?>> clazz = ResourceMetaParams.RESOURCE_META_AND_PARAMS.get(theParamType);
|
||||||
return ReflectionUtil.newInstance(clazz);
|
return ReflectionUtil.newInstance(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,4 +148,44 @@ public class MatchUrlService {
|
||||||
Class<? extends IQueryParameterType> clazz = ResourceMetaParams.RESOURCE_META_PARAMS.get(theParamType);
|
Class<? extends IQueryParameterType> clazz = ResourceMetaParams.RESOURCE_META_PARAMS.get(theParamType);
|
||||||
return ReflectionUtil.newInstance(clazz);
|
return ReflectionUtil.newInstance(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract static class Flag {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
Flag() {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract void process(String theParamName, List<QualifiedParamList> theValues, SearchParameterMap theMapToPopulate);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the parser should process _include and _revinclude (by default these are not handled)
|
||||||
|
*/
|
||||||
|
public static Flag processIncludes() {
|
||||||
|
return new Flag() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void process(String theParamName, List<QualifiedParamList> theValues, SearchParameterMap theMapToPopulate) {
|
||||||
|
if (Constants.PARAM_INCLUDE.equals(theParamName)) {
|
||||||
|
for (QualifiedParamList nextQualifiedList : theValues) {
|
||||||
|
for (String nextValue : nextQualifiedList) {
|
||||||
|
theMapToPopulate.addInclude(new Include(nextValue, ParameterUtil.isIncludeIterate(nextQualifiedList.getQualifier())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (Constants.PARAM_REVINCLUDE.equals(theParamName)) {
|
||||||
|
for (QualifiedParamList nextQualifiedList : theValues) {
|
||||||
|
for (String nextValue : nextQualifiedList) {
|
||||||
|
theMapToPopulate.addInclude(new Include(nextValue, ParameterUtil.isIncludeIterate(nextQualifiedList.getQualifier())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,5 @@ package ca.uhn.fhir.jpa.searchparam;
|
||||||
|
|
||||||
public class SearchParamConstants {
|
public class SearchParamConstants {
|
||||||
|
|
||||||
public static final String EXT_SP_UNIQUE = "http://hapifhir.io/fhir/StructureDefinition/sp-unique";
|
|
||||||
|
|
||||||
public static final String UCUM_NS = "http://unitsofmeasure.org";
|
public static final String UCUM_NS = "http://unitsofmeasure.org";
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.matcher.SearchParamMatcher;
|
||||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||||
import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryImpl;
|
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.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
@ -81,6 +82,12 @@ public class SearchParamConfig {
|
||||||
return new SearchParamExtractorService();
|
return new SearchParamExtractorService();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Lazy
|
||||||
|
public SearchParameterCanonicalizer searchParameterCanonicalizer(FhirContext theFhirContext) {
|
||||||
|
return new SearchParameterCanonicalizer(theFhirContext);
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public IndexedSearchParamExtractor indexedSearchParamExtractor() {
|
public IndexedSearchParamExtractor indexedSearchParamExtractor() {
|
||||||
return new IndexedSearchParamExtractor();
|
return new IndexedSearchParamExtractor();
|
||||||
|
|
|
@ -37,12 +37,12 @@ import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
|
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
|
||||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||||
import ca.uhn.fhir.model.primitive.BoundCodeDt;
|
import ca.uhn.fhir.model.primitive.BoundCodeDt;
|
||||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import ca.uhn.fhir.util.StringUtil;
|
import ca.uhn.fhir.util.StringUtil;
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -81,8 +81,8 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
import static org.apache.commons.lang3.StringUtils.trim;
|
import static org.apache.commons.lang3.StringUtils.trim;
|
||||||
|
|
||||||
public abstract class BaseSearchParamExtractor implements ISearchParamExtractor {
|
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 Pattern SPLIT_R4 = Pattern.compile("\\|");
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseSearchParamExtractor.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseSearchParamExtractor.class);
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -95,6 +95,7 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
||||||
private ModelConfig myModelConfig;
|
private ModelConfig myModelConfig;
|
||||||
@Autowired
|
@Autowired
|
||||||
private PartitionSettings myPartitionSettings;
|
private PartitionSettings myPartitionSettings;
|
||||||
|
|
||||||
private Set<String> myIgnoredForSearchDatatypes;
|
private Set<String> myIgnoredForSearchDatatypes;
|
||||||
private BaseRuntimeChildDefinition myQuantityValueValueChild;
|
private BaseRuntimeChildDefinition myQuantityValueValueChild;
|
||||||
private BaseRuntimeChildDefinition myQuantitySystemValueChild;
|
private BaseRuntimeChildDefinition myQuantitySystemValueChild;
|
||||||
|
@ -252,7 +253,7 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
||||||
@Override
|
@Override
|
||||||
public List<String> extractParamValuesAsStrings(RuntimeSearchParam theSearchParam, IBaseResource theResource) {
|
public List<String> extractParamValuesAsStrings(RuntimeSearchParam theSearchParam, IBaseResource theResource) {
|
||||||
IExtractor extractor;
|
IExtractor extractor;
|
||||||
switch(theSearchParam.getParamType()) {
|
switch (theSearchParam.getParamType()) {
|
||||||
case DATE:
|
case DATE:
|
||||||
extractor = createDateExtractor(theResource);
|
extractor = createDateExtractor(theResource);
|
||||||
break;
|
break;
|
||||||
|
@ -972,12 +973,10 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
||||||
for (String next : families) {
|
for (String next : families) {
|
||||||
createStringIndexIfNotBlank(theResourceType, theParams, theSearchParam, next);
|
createStringIndexIfNotBlank(theResourceType, theParams, theSearchParam, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> givens = extractValuesAsStrings(myHumanNameGivenValueChild, theValue);
|
List<String> givens = extractValuesAsStrings(myHumanNameGivenValueChild, theValue);
|
||||||
for (String next : givens) {
|
for (String next : givens) {
|
||||||
createStringIndexIfNotBlank(theResourceType, theParams, theSearchParam, next);
|
createStringIndexIfNotBlank(theResourceType, theParams, theSearchParam, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addString_Quantity(String theResourceType, Set<ResourceIndexedSearchParamString> theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
|
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 searchParamName = theSearchParam.getName();
|
||||||
String valueNormalized = StringUtil.normalizeStringForSearchIndexing(value);
|
String valueNormalized = StringUtil.normalizeStringForSearchIndexing(value);
|
||||||
if (valueNormalized.length() > ResourceIndexedSearchParamString.MAX_LENGTH) {
|
String valueEncoded = theSearchParam.encode(valueNormalized);
|
||||||
valueNormalized = valueNormalized.substring(0, ResourceIndexedSearchParamString.MAX_LENGTH);
|
|
||||||
|
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;
|
Set params = theParams;
|
||||||
params.add(nextEntity);
|
params.add(nextEntity);
|
||||||
|
@ -1374,7 +1375,7 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean tokenTextIndexingEnabledForSearchParam(ModelConfig theModelConfig, RuntimeSearchParam theSearchParam) {
|
public static boolean tokenTextIndexingEnabledForSearchParam(ModelConfig theModelConfig, RuntimeSearchParam theSearchParam) {
|
||||||
Optional<Boolean> noSuppressForSearchParam = theSearchParam.getExtensions(JpaConstants.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING).stream()
|
Optional<Boolean> noSuppressForSearchParam = theSearchParam.getExtensions(HapiExtensions.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING).stream()
|
||||||
.map(IBaseExtension::getValue)
|
.map(IBaseExtension::getValue)
|
||||||
.map(val -> (IPrimitiveType<?>) val)
|
.map(val -> (IPrimitiveType<?>) val)
|
||||||
.map(IPrimitiveType::getValueAsString)
|
.map(IPrimitiveType::getValueAsString)
|
||||||
|
|
|
@ -85,6 +85,7 @@ public class SearchParamExtractorService {
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
private IResourceLinkResolver myResourceLinkResolver;
|
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
|
* 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}.
|
* 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.RuntimeResourceDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
|
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
|
||||||
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -59,4 +60,12 @@ public interface ISearchParamRegistry {
|
||||||
RuntimeSearchParam getSearchParamByName(RuntimeResourceDefinition theResourceDef, String theParamName);
|
RuntimeSearchParam getSearchParamByName(RuntimeResourceDefinition theResourceDef, String theParamName);
|
||||||
|
|
||||||
Collection<RuntimeSearchParam> getSearchParamsByResourceType(RuntimeResourceDefinition theResourceDef);
|
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.FhirContext;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
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.HookParams;
|
||||||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
|
@ -32,35 +33,35 @@ import ca.uhn.fhir.jpa.model.sched.ISchedulerService;
|
||||||
import ca.uhn.fhir.jpa.model.sched.ScheduledJobDefinition;
|
import ca.uhn.fhir.jpa.model.sched.ScheduledJobDefinition;
|
||||||
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
||||||
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
|
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.searchparam.retry.Retrier;
|
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.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
import ca.uhn.fhir.util.DatatypeUtil;
|
import ca.uhn.fhir.util.DatatypeUtil;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import ca.uhn.fhir.util.SearchParameterUtil;
|
import ca.uhn.fhir.util.SearchParameterUtil;
|
||||||
import ca.uhn.fhir.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
import org.hl7.fhir.dstu3.model.Extension;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.dstu3.model.SearchParameter;
|
|
||||||
import org.hl7.fhir.instance.model.api.*;
|
|
||||||
import org.hl7.fhir.r4.model.Reference;
|
|
||||||
import org.quartz.JobExecutionContext;
|
import org.quartz.JobExecutionContext;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
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 java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|
||||||
|
|
||||||
public class SearchParamRegistryImpl implements ISearchParamRegistry {
|
public class SearchParamRegistryImpl implements ISearchParamRegistry {
|
||||||
|
|
||||||
|
@ -76,8 +77,12 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry {
|
||||||
private FhirContext myFhirContext;
|
private FhirContext myFhirContext;
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISchedulerService mySchedulerService;
|
private ISchedulerService mySchedulerService;
|
||||||
|
@Autowired
|
||||||
|
private SearchParameterCanonicalizer mySearchParameterCanonicalizer;
|
||||||
|
|
||||||
private Map<String, Map<String, RuntimeSearchParam>> myBuiltInSearchParams;
|
private Map<String, Map<String, RuntimeSearchParam>> myBuiltInSearchParams;
|
||||||
|
private IPhoneticEncoder myPhoneticEncoder;
|
||||||
|
|
||||||
private volatile Map<String, List<JpaRuntimeSearchParam>> myActiveUniqueSearchParams = Collections.emptyMap();
|
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<Set<String>, List<JpaRuntimeSearchParam>>> myActiveParamNamesToUniqueSearchParams = Collections.emptyMap();
|
||||||
private volatile Map<String, Map<String, RuntimeSearchParam>> myActiveSearchParams;
|
private volatile Map<String, Map<String, RuntimeSearchParam>> myActiveSearchParams;
|
||||||
|
@ -175,6 +180,8 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry {
|
||||||
uniqueSearchParams.add(nextCandidateCasted);
|
uniqueSearchParams.add(nextCandidateCasted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setPhoneticEncoder(nextCandidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -228,21 +235,11 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry {
|
||||||
myActiveParamNamesToUniqueSearchParams = activeParamNamesToUniqueSearchParams;
|
myActiveParamNamesToUniqueSearchParams = activeParamNamesToUniqueSearchParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
void setFhirContextForUnitTest(FhirContext theFhirContext) {
|
|
||||||
myFhirContext = theFhirContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void postConstruct() {
|
public void postConstruct() {
|
||||||
myBuiltInSearchParams = createBuiltInSearchParamMap(myFhirContext);
|
myBuiltInSearchParams = createBuiltInSearchParamMap(myFhirContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
public void setSearchParamProviderForUnitTest(ISearchParamProvider theSearchParamProvider) {
|
|
||||||
mySearchParamProvider = theSearchParamProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int doRefresh(long theRefreshInterval) {
|
public int doRefresh(long theRefreshInterval) {
|
||||||
if (System.currentTimeMillis() - theRefreshInterval > myLastRefresh) {
|
if (System.currentTimeMillis() - theRefreshInterval > myLastRefresh) {
|
||||||
StopWatch sw = new StopWatch();
|
StopWatch sw = new StopWatch();
|
||||||
|
@ -280,7 +277,7 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeSearchParam runtimeSp = canonicalizeSearchParameter(nextSp);
|
RuntimeSearchParam runtimeSp = mySearchParameterCanonicalizer.canonicalizeSearchParameter(nextSp);
|
||||||
if (runtimeSp == null) {
|
if (runtimeSp == null) {
|
||||||
continue;
|
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(SearchParamConstants.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(SearchParamConstants.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(SearchParamConstants.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(SearchParamConstants.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
|
@Override
|
||||||
public RuntimeSearchParam getSearchParamByName(RuntimeResourceDefinition theResourceDef, String theParamName) {
|
public RuntimeSearchParam getSearchParamByName(RuntimeResourceDefinition theResourceDef, String theParamName) {
|
||||||
|
@ -760,26 +402,6 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry {
|
||||||
return Collections.unmodifiableMap(myActiveSearchParams);
|
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) {
|
public static Map<String, Map<String, RuntimeSearchParam>> createBuiltInSearchParamMap(FhirContext theFhirContext) {
|
||||||
Map<String, Map<String, RuntimeSearchParam>> resourceNameToSearchParams = new HashMap<>();
|
Map<String, Map<String, RuntimeSearchParam>> resourceNameToSearchParams = new HashMap<>();
|
||||||
|
|
||||||
|
@ -797,4 +419,31 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry {
|
||||||
}
|
}
|
||||||
return Collections.unmodifiableMap(resourceNameToSearchParams);
|
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.FhirContext;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
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.DefaultProfileValidationSupport;
|
||||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||||
|
@ -291,6 +292,11 @@ public class SearchParamExtractorDstu3Test {
|
||||||
public Collection<RuntimeSearchParam> getSearchParamsByResourceType(RuntimeResourceDefinition theResourceDef) {
|
public Collection<RuntimeSearchParam> getSearchParamsByResourceType(RuntimeResourceDefinition theResourceDef) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPhoneticEncoder(IPhoneticEncoder thePhoneticEncoder) {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
|
|
|
@ -16,6 +16,7 @@ import ca.uhn.fhir.context.RuntimePrimitiveDatatypeNarrativeDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition;
|
import ca.uhn.fhir.context.RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
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.DefaultProfileValidationSupport;
|
||||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
|
@ -300,6 +301,11 @@ public class SearchParamExtractorMegaTest {
|
||||||
public Collection<RuntimeSearchParam> getSearchParamsByResourceType(RuntimeResourceDefinition theResourceDef) {
|
public Collection<RuntimeSearchParam> getSearchParamsByResourceType(RuntimeResourceDefinition theResourceDef) {
|
||||||
return null;
|
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.FhirContext;
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
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.jpa.model.sched.ISchedulerService;
|
||||||
import ca.uhn.fhir.rest.server.SimpleBundleProvider;
|
import ca.uhn.fhir.rest.server.SimpleBundleProvider;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
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.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mock;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
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 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.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(SpringRunner.class)
|
||||||
public class SearchParamRegistryImplTest {
|
public class SearchParamRegistryImplTest {
|
||||||
|
@Autowired
|
||||||
|
SearchParamRegistryImpl mySearchParamRegistry;
|
||||||
|
|
||||||
@Mock
|
@MockBean
|
||||||
private ISchedulerService mySchedulerService;
|
private ISchedulerService mySchedulerService;
|
||||||
@Mock
|
@MockBean
|
||||||
private ISearchParamProvider mySearchParamProvider;
|
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
|
@Before
|
||||||
public void before() {
|
public void before() {
|
||||||
|
@ -42,56 +69,40 @@ public class SearchParamRegistryImplTest {
|
||||||
public void testRefreshAfterExpiry() {
|
public void testRefreshAfterExpiry() {
|
||||||
when(mySearchParamProvider.search(any())).thenReturn(new SimpleBundleProvider());
|
when(mySearchParamProvider.search(any())).thenReturn(new SimpleBundleProvider());
|
||||||
|
|
||||||
SearchParamRegistryImpl registry = new SearchParamRegistryImpl();
|
mySearchParamRegistry.requestRefresh();
|
||||||
registry.setSchedulerServiceForUnitTest(mySchedulerService);
|
assertEquals(146, mySearchParamRegistry.doRefresh(100000));
|
||||||
registry.setFhirContextForUnitTest(FhirContext.forR4());
|
|
||||||
registry.setSearchParamProviderForUnitTest(mySearchParamProvider);
|
|
||||||
registry.postConstruct();
|
|
||||||
|
|
||||||
registry.requestRefresh();
|
|
||||||
assertEquals(146, registry.doRefresh(100000));
|
|
||||||
|
|
||||||
// Second time we don't need to run because we ran recently
|
// 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
|
@Test
|
||||||
public void testRefreshCacheIfNecessary() {
|
public void testRefreshCacheIfNecessary() {
|
||||||
SearchParamRegistryImpl registry = new SearchParamRegistryImpl();
|
|
||||||
|
|
||||||
when(mySearchParamProvider.search(any())).thenReturn(new SimpleBundleProvider());
|
when(mySearchParamProvider.search(any())).thenReturn(new SimpleBundleProvider());
|
||||||
when(mySearchParamProvider.refreshCache(any(), anyLong())).thenAnswer(t -> {
|
when(mySearchParamProvider.refreshCache(any(), anyLong())).thenAnswer(t -> {
|
||||||
registry.doRefresh(t.getArgument(1, Long.class));
|
mySearchParamRegistry.doRefresh(t.getArgument(1, Long.class));
|
||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
registry.setSchedulerServiceForUnitTest(mySchedulerService);
|
mySearchParamRegistry.requestRefresh();
|
||||||
registry.setFhirContextForUnitTest(FhirContext.forR4());
|
|
||||||
registry.setSearchParamProviderForUnitTest(mySearchParamProvider);
|
|
||||||
registry.postConstruct();
|
|
||||||
registry.requestRefresh();
|
|
||||||
|
|
||||||
assertTrue(registry.refreshCacheIfNecessary());
|
assertTrue(mySearchParamRegistry.refreshCacheIfNecessary());
|
||||||
assertFalse(registry.refreshCacheIfNecessary());
|
assertFalse(mySearchParamRegistry.refreshCacheIfNecessary());
|
||||||
|
|
||||||
registry.requestRefresh();
|
mySearchParamRegistry.requestRefresh();
|
||||||
assertTrue(registry.refreshCacheIfNecessary());
|
assertTrue(mySearchParamRegistry.refreshCacheIfNecessary());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetActiveUniqueSearchParams_Empty() {
|
public void testGetActiveUniqueSearchParams_Empty() {
|
||||||
SearchParamRegistryImpl registry = new SearchParamRegistryImpl();
|
assertThat(mySearchParamRegistry.getActiveUniqueSearchParams("Patient"), Matchers.empty());
|
||||||
assertThat(registry.getActiveUniqueSearchParams("Patient"), Matchers.empty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetActiveSearchParams() {
|
public void testGetActiveSearchParams() {
|
||||||
SearchParamRegistryImpl registry = new SearchParamRegistryImpl();
|
|
||||||
registry.setFhirContextForUnitTest(FhirContext.forR4());
|
|
||||||
registry.postConstruct();
|
|
||||||
|
|
||||||
when(mySearchParamProvider.search(any())).thenReturn(new SimpleBundleProvider());
|
when(mySearchParamProvider.search(any())).thenReturn(new SimpleBundleProvider());
|
||||||
when(mySearchParamProvider.refreshCache(any(), anyLong())).thenAnswer(t -> {
|
when(mySearchParamProvider.refreshCache(any(), anyLong())).thenAnswer(t -> {
|
||||||
if (myAnswerCount == 0) {
|
if (myAnswerCount == 0) {
|
||||||
|
@ -99,21 +110,16 @@ public class SearchParamRegistryImplTest {
|
||||||
throw new InternalErrorException("this is an error!");
|
throw new InternalErrorException("this is an error!");
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.doRefresh(0);
|
mySearchParamRegistry.doRefresh(0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
registry.setSearchParamProviderForUnitTest(mySearchParamProvider);
|
Map<String, RuntimeSearchParam> outcome = mySearchParamRegistry.getActiveSearchParams("Patient");
|
||||||
Map<String, RuntimeSearchParam> outcome = registry.getActiveSearchParams("Patient");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExtractExtensions() {
|
public void testExtractExtensions() {
|
||||||
SearchParamRegistryImpl registry = new SearchParamRegistryImpl();
|
|
||||||
registry.setFhirContextForUnitTest(FhirContext.forR4());
|
|
||||||
registry.postConstruct();
|
|
||||||
|
|
||||||
SearchParameter searchParameter = new SearchParameter();
|
SearchParameter searchParameter = new SearchParameter();
|
||||||
searchParameter.setCode("foo");
|
searchParameter.setCode("foo");
|
||||||
searchParameter.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
searchParameter.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||||
|
@ -129,12 +135,12 @@ public class SearchParamRegistryImplTest {
|
||||||
|
|
||||||
when(mySearchParamProvider.search(any())).thenReturn(new SimpleBundleProvider(searchParameter));
|
when(mySearchParamProvider.search(any())).thenReturn(new SimpleBundleProvider(searchParameter));
|
||||||
when(mySearchParamProvider.refreshCache(any(), anyLong())).thenAnswer(t -> {
|
when(mySearchParamProvider.refreshCache(any(), anyLong())).thenAnswer(t -> {
|
||||||
registry.doRefresh(0);
|
mySearchParamRegistry.doRefresh(0);
|
||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
registry.setSearchParamProviderForUnitTest(mySearchParamProvider);
|
mySearchParamRegistry.forceRefresh();
|
||||||
Map<String, RuntimeSearchParam> outcome = registry.getActiveSearchParams("Patient");
|
Map<String, RuntimeSearchParam> outcome = mySearchParamRegistry.getActiveSearchParams("Patient");
|
||||||
|
|
||||||
RuntimeSearchParam converted = outcome.get("foo");
|
RuntimeSearchParam converted = outcome.get("foo");
|
||||||
assertNotNull(converted);
|
assertNotNull(converted);
|
||||||
|
|
|
@ -74,7 +74,7 @@ public class SubscriptionDeliveringMessageSubscriber extends BaseSubscriptionDel
|
||||||
public void handleMessage(ResourceDeliveryMessage theMessage) throws MessagingException, URISyntaxException {
|
public void handleMessage(ResourceDeliveryMessage theMessage) throws MessagingException, URISyntaxException {
|
||||||
CanonicalSubscription subscription = theMessage.getSubscription();
|
CanonicalSubscription subscription = theMessage.getSubscription();
|
||||||
|
|
||||||
// Interceptor call: SUBSCRIPTION_BEFORE_REST_HOOK_DELIVERY
|
// Interceptor call: SUBSCRIPTION_BEFORE_MESSAGE_DELIVERY
|
||||||
HookParams params = new HookParams()
|
HookParams params = new HookParams()
|
||||||
.add(CanonicalSubscription.class, subscription)
|
.add(CanonicalSubscription.class, subscription)
|
||||||
.add(ResourceDeliveryMessage.class, theMessage);
|
.add(ResourceDeliveryMessage.class, theMessage);
|
||||||
|
@ -104,7 +104,7 @@ public class SubscriptionDeliveringMessageSubscriber extends BaseSubscriptionDel
|
||||||
|
|
||||||
deliverPayload(theMessage, subscription, channelProducer);
|
deliverPayload(theMessage, subscription, channelProducer);
|
||||||
|
|
||||||
// Interceptor call: SUBSCRIPTION_AFTER_REST_HOOK_DELIVERY
|
// Interceptor call: SUBSCRIPTION_AFTER_MESSAGE_DELIVERY
|
||||||
params = new HookParams()
|
params = new HookParams()
|
||||||
.add(CanonicalSubscription.class, subscription)
|
.add(CanonicalSubscription.class, subscription)
|
||||||
.add(ResourceDeliveryMessage.class, theMessage);
|
.add(ResourceDeliveryMessage.class, theMessage);
|
||||||
|
|
|
@ -25,11 +25,14 @@ import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
|
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||||
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.deliver.BaseSubscriptionDeliverySubscriber;
|
import ca.uhn.fhir.jpa.subscription.match.deliver.BaseSubscriptionDeliverySubscriber;
|
||||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
|
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
|
||||||
import ca.uhn.fhir.jpa.subscription.model.ResourceDeliveryMessage;
|
import ca.uhn.fhir.jpa.subscription.model.ResourceDeliveryMessage;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||||
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.client.api.Header;
|
import ca.uhn.fhir.rest.client.api.Header;
|
||||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||||
|
@ -40,7 +43,9 @@ import ca.uhn.fhir.rest.client.interceptor.SimpleRequestHeaderInterceptor;
|
||||||
import ca.uhn.fhir.rest.gclient.IClientExecutable;
|
import ca.uhn.fhir.rest.gclient.IClientExecutable;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
|
import ca.uhn.fhir.util.TransactionBuilder;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.text.StringSubstitutor;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -49,6 +54,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.messaging.MessagingException;
|
import org.springframework.messaging.MessagingException;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -65,6 +71,9 @@ public class SubscriptionDeliveringRestHookSubscriber extends BaseSubscriptionDe
|
||||||
@Autowired
|
@Autowired
|
||||||
private DaoRegistry myDaoRegistry;
|
private DaoRegistry myDaoRegistry;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MatchUrlService myMatchUrlService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
|
@ -81,55 +90,82 @@ public class SubscriptionDeliveringRestHookSubscriber extends BaseSubscriptionDe
|
||||||
|
|
||||||
protected void doDelivery(ResourceDeliveryMessage theMsg, CanonicalSubscription theSubscription, EncodingEnum thePayloadType, IGenericClient theClient, IBaseResource thePayloadResource) {
|
protected void doDelivery(ResourceDeliveryMessage theMsg, CanonicalSubscription theSubscription, EncodingEnum thePayloadType, IGenericClient theClient, IBaseResource thePayloadResource) {
|
||||||
IClientExecutable<?, ?> operation;
|
IClientExecutable<?, ?> operation;
|
||||||
|
|
||||||
|
if (isNotBlank(theSubscription.getPayloadSearchCriteria())) {
|
||||||
|
operation = createDeliveryRequestTransaction(theSubscription, theClient, thePayloadResource);
|
||||||
|
} else if (thePayloadType != null) {
|
||||||
|
operation = createDeliveryRequestNormal(theMsg, theClient, thePayloadResource);
|
||||||
|
} else {
|
||||||
|
sendNotification(theMsg);
|
||||||
|
operation = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation != null) {
|
||||||
|
|
||||||
|
if (thePayloadType != null) {
|
||||||
|
operation.encoded(thePayloadType);
|
||||||
|
}
|
||||||
|
|
||||||
|
String payloadId = thePayloadResource.getIdElement().toUnqualified().getValue();
|
||||||
|
ourLog.info("Delivering {} rest-hook payload {} for {}", theMsg.getOperationType(), payloadId, theSubscription.getIdElement(myFhirContext).toUnqualifiedVersionless().getValue());
|
||||||
|
|
||||||
|
try {
|
||||||
|
operation.execute();
|
||||||
|
} catch (ResourceNotFoundException e) {
|
||||||
|
ourLog.error("Cannot reach {} ", theMsg.getSubscription().getEndpointUrl());
|
||||||
|
ourLog.error("Exception: ", e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private IClientExecutable<?, ?> createDeliveryRequestNormal(ResourceDeliveryMessage theMsg, IGenericClient theClient, IBaseResource thePayloadResource) {
|
||||||
|
IClientExecutable<?, ?> operation;
|
||||||
switch (theMsg.getOperationType()) {
|
switch (theMsg.getOperationType()) {
|
||||||
case CREATE:
|
case CREATE:
|
||||||
case UPDATE:
|
case UPDATE:
|
||||||
if (thePayloadResource == null || thePayloadResource.isEmpty()) {
|
operation = theClient.update().resource(thePayloadResource);
|
||||||
if (thePayloadType != null) {
|
|
||||||
operation = theClient.create().resource(thePayloadResource);
|
|
||||||
} else {
|
|
||||||
sendNotification(theMsg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (thePayloadType != null) {
|
|
||||||
operation = theClient.update().resource(thePayloadResource);
|
|
||||||
} else {
|
|
||||||
sendNotification(theMsg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case DELETE:
|
case DELETE:
|
||||||
operation = theClient.delete().resourceById(theMsg.getPayloadId(myFhirContext));
|
operation = theClient.delete().resourceById(theMsg.getPayloadId(myFhirContext));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ourLog.warn("Ignoring delivery message of type: {}", theMsg.getOperationType());
|
ourLog.warn("Ignoring delivery message of type: {}", theMsg.getOperationType());
|
||||||
return;
|
operation = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IClientExecutable<?, ?> createDeliveryRequestTransaction(CanonicalSubscription theSubscription, IGenericClient theClient, IBaseResource thePayloadResource) {
|
||||||
|
IClientExecutable<?, ?> operation;
|
||||||
|
String resType = theSubscription.getPayloadSearchCriteria().substring(0, theSubscription.getPayloadSearchCriteria().indexOf('?'));
|
||||||
|
IFhirResourceDao<?> dao = myDaoRegistry.getResourceDao(resType);
|
||||||
|
RuntimeResourceDefinition resourceDefinition = myFhirContext.getResourceDefinition(resType);
|
||||||
|
|
||||||
|
String payloadUrl = theSubscription.getPayloadSearchCriteria();
|
||||||
|
Map<String, String> valueMap = new HashMap<>(1);
|
||||||
|
valueMap.put("matched_resource_id", thePayloadResource.getIdElement().toUnqualifiedVersionless().getValue());
|
||||||
|
payloadUrl = new StringSubstitutor(valueMap).replace(payloadUrl);
|
||||||
|
SearchParameterMap payloadSearchMap = myMatchUrlService.translateMatchUrl(payloadUrl, resourceDefinition, MatchUrlService.processIncludes());
|
||||||
|
payloadSearchMap.setLoadSynchronous(true);
|
||||||
|
|
||||||
|
IBundleProvider searchResults = dao.search(payloadSearchMap);
|
||||||
|
|
||||||
|
TransactionBuilder builder = new TransactionBuilder(myFhirContext);
|
||||||
|
for (IBaseResource next : searchResults.getResources(0, searchResults.size())) {
|
||||||
|
builder.addUpdateEntry(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thePayloadType != null) {
|
operation = theClient.transaction().withBundle(builder.getBundle());
|
||||||
operation.encoded(thePayloadType);
|
return operation;
|
||||||
}
|
|
||||||
|
|
||||||
String payloadId = null;
|
|
||||||
if (thePayloadResource != null) {
|
|
||||||
payloadId = thePayloadResource.getIdElement().toUnqualified().getValue();
|
|
||||||
}
|
|
||||||
ourLog.info("Delivering {} rest-hook payload {} for {}", theMsg.getOperationType(), payloadId, theSubscription.getIdElement(myFhirContext).toUnqualifiedVersionless().getValue());
|
|
||||||
|
|
||||||
try {
|
|
||||||
operation.execute();
|
|
||||||
} catch (ResourceNotFoundException e) {
|
|
||||||
ourLog.error("Cannot reach {} ", theMsg.getSubscription().getEndpointUrl());
|
|
||||||
ourLog.error("Exception: ", e);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IBaseResource getResource(IIdType payloadId) throws ResourceGoneException {
|
public IBaseResource getResource(IIdType payloadId) throws ResourceGoneException {
|
||||||
RuntimeResourceDefinition resourceDef = myFhirContext.getResourceDefinition(payloadId.getResourceType());
|
RuntimeResourceDefinition resourceDef = myFhirContext.getResourceDefinition(payloadId.getResourceType());
|
||||||
IFhirResourceDao dao = myDaoRegistry.getResourceDao(resourceDef.getImplementingClass());
|
IFhirResourceDao<?> dao = myDaoRegistry.getResourceDao(resourceDef.getImplementingClass());
|
||||||
return dao.read(payloadId.toVersionless());
|
return dao.read(payloadId.toVersionless());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,8 +273,7 @@ public class SubscriptionDeliveringRestHookSubscriber extends BaseSubscriptionDe
|
||||||
// close connection in order to return a possible cached connection to the connection pool
|
// close connection in order to return a possible cached connection to the connection pool
|
||||||
response.close();
|
response.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
ourLog.error("Error trying to reach " + theMsg.getSubscription().getEndpointUrl());
|
ourLog.error("Error trying to reach {}: {}", theMsg.getSubscription().getEndpointUrl(), e.toString());
|
||||||
e.printStackTrace();
|
|
||||||
throw new ResourceNotFoundException(e.getMessage());
|
throw new ResourceNotFoundException(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,13 +22,13 @@ package ca.uhn.fhir.jpa.subscription.match.registry;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.ConfigurationException;
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
|
||||||
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionMatchingStrategy;
|
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionMatchingStrategy;
|
||||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
|
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
|
||||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscriptionChannelType;
|
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscriptionChannelType;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Subscription;
|
import ca.uhn.fhir.model.dstu2.resource.Subscription;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
|
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
|
||||||
|
@ -113,14 +113,15 @@ public class SubscriptionCanonicalizer {
|
||||||
retVal.setChannelExtensions(extractExtension(subscription));
|
retVal.setChannelExtensions(extractExtension(subscription));
|
||||||
retVal.setIdElement(subscription.getIdElement());
|
retVal.setIdElement(subscription.getIdElement());
|
||||||
retVal.setPayloadString(subscription.getChannel().getPayload());
|
retVal.setPayloadString(subscription.getChannel().getPayload());
|
||||||
|
retVal.setPayloadSearchCriteria(getExtensionString(subscription, HapiExtensions.EXT_SUBSCRIPTION_PAYLOAD_SEARCH_CRITERIA));
|
||||||
|
|
||||||
if (retVal.getChannelType() == CanonicalSubscriptionChannelType.EMAIL) {
|
if (retVal.getChannelType() == CanonicalSubscriptionChannelType.EMAIL) {
|
||||||
String from;
|
String from;
|
||||||
String subjectTemplate;
|
String subjectTemplate;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
from = subscription.getChannel().getExtensionString(JpaConstants.EXT_SUBSCRIPTION_EMAIL_FROM);
|
from = subscription.getChannel().getExtensionString(HapiExtensions.EXT_SUBSCRIPTION_EMAIL_FROM);
|
||||||
subjectTemplate = subscription.getChannel().getExtensionString(JpaConstants.EXT_SUBSCRIPTION_SUBJECT_TEMPLATE);
|
subjectTemplate = subscription.getChannel().getExtensionString(HapiExtensions.EXT_SUBSCRIPTION_SUBJECT_TEMPLATE);
|
||||||
} catch (FHIRException theE) {
|
} catch (FHIRException theE) {
|
||||||
throw new ConfigurationException("Failed to extract subscription extension(s): " + theE.getMessage(), theE);
|
throw new ConfigurationException("Failed to extract subscription extension(s): " + theE.getMessage(), theE);
|
||||||
}
|
}
|
||||||
|
@ -133,8 +134,8 @@ public class SubscriptionCanonicalizer {
|
||||||
String stripVersionIds;
|
String stripVersionIds;
|
||||||
String deliverLatestVersion;
|
String deliverLatestVersion;
|
||||||
try {
|
try {
|
||||||
stripVersionIds = subscription.getChannel().getExtensionString(JpaConstants.EXT_SUBSCRIPTION_RESTHOOK_STRIP_VERSION_IDS);
|
stripVersionIds = subscription.getChannel().getExtensionString(HapiExtensions.EXT_SUBSCRIPTION_RESTHOOK_STRIP_VERSION_IDS);
|
||||||
deliverLatestVersion = subscription.getChannel().getExtensionString(JpaConstants.EXT_SUBSCRIPTION_RESTHOOK_DELIVER_LATEST_VERSION);
|
deliverLatestVersion = subscription.getChannel().getExtensionString(HapiExtensions.EXT_SUBSCRIPTION_RESTHOOK_DELIVER_LATEST_VERSION);
|
||||||
} catch (FHIRException theE) {
|
} catch (FHIRException theE) {
|
||||||
throw new ConfigurationException("Failed to extract subscription extension(s): " + theE.getMessage(), theE);
|
throw new ConfigurationException("Failed to extract subscription extension(s): " + theE.getMessage(), theE);
|
||||||
}
|
}
|
||||||
|
@ -208,13 +209,14 @@ public class SubscriptionCanonicalizer {
|
||||||
retVal.setChannelExtensions(extractExtension(subscription));
|
retVal.setChannelExtensions(extractExtension(subscription));
|
||||||
retVal.setIdElement(subscription.getIdElement());
|
retVal.setIdElement(subscription.getIdElement());
|
||||||
retVal.setPayloadString(subscription.getChannel().getPayload());
|
retVal.setPayloadString(subscription.getChannel().getPayload());
|
||||||
|
retVal.setPayloadSearchCriteria(getExtensionString(subscription, HapiExtensions.EXT_SUBSCRIPTION_PAYLOAD_SEARCH_CRITERIA));
|
||||||
|
|
||||||
if (retVal.getChannelType() == CanonicalSubscriptionChannelType.EMAIL) {
|
if (retVal.getChannelType() == CanonicalSubscriptionChannelType.EMAIL) {
|
||||||
String from;
|
String from;
|
||||||
String subjectTemplate;
|
String subjectTemplate;
|
||||||
try {
|
try {
|
||||||
from = subscription.getChannel().getExtensionString(JpaConstants.EXT_SUBSCRIPTION_EMAIL_FROM);
|
from = subscription.getChannel().getExtensionString(HapiExtensions.EXT_SUBSCRIPTION_EMAIL_FROM);
|
||||||
subjectTemplate = subscription.getChannel().getExtensionString(JpaConstants.EXT_SUBSCRIPTION_SUBJECT_TEMPLATE);
|
subjectTemplate = subscription.getChannel().getExtensionString(HapiExtensions.EXT_SUBSCRIPTION_SUBJECT_TEMPLATE);
|
||||||
} catch (FHIRException theE) {
|
} catch (FHIRException theE) {
|
||||||
throw new ConfigurationException("Failed to extract subscription extension(s): " + theE.getMessage(), theE);
|
throw new ConfigurationException("Failed to extract subscription extension(s): " + theE.getMessage(), theE);
|
||||||
}
|
}
|
||||||
|
@ -226,8 +228,8 @@ public class SubscriptionCanonicalizer {
|
||||||
String stripVersionIds;
|
String stripVersionIds;
|
||||||
String deliverLatestVersion;
|
String deliverLatestVersion;
|
||||||
try {
|
try {
|
||||||
stripVersionIds = subscription.getChannel().getExtensionString(JpaConstants.EXT_SUBSCRIPTION_RESTHOOK_STRIP_VERSION_IDS);
|
stripVersionIds = subscription.getChannel().getExtensionString(HapiExtensions.EXT_SUBSCRIPTION_RESTHOOK_STRIP_VERSION_IDS);
|
||||||
deliverLatestVersion = subscription.getChannel().getExtensionString(JpaConstants.EXT_SUBSCRIPTION_RESTHOOK_DELIVER_LATEST_VERSION);
|
deliverLatestVersion = subscription.getChannel().getExtensionString(HapiExtensions.EXT_SUBSCRIPTION_RESTHOOK_DELIVER_LATEST_VERSION);
|
||||||
} catch (FHIRException theE) {
|
} catch (FHIRException theE) {
|
||||||
throw new ConfigurationException("Failed to extract subscription extension(s): " + theE.getMessage(), theE);
|
throw new ConfigurationException("Failed to extract subscription extension(s): " + theE.getMessage(), theE);
|
||||||
}
|
}
|
||||||
|
@ -261,13 +263,14 @@ public class SubscriptionCanonicalizer {
|
||||||
retVal.setChannelExtensions(extractExtension(subscription));
|
retVal.setChannelExtensions(extractExtension(subscription));
|
||||||
retVal.setIdElement(subscription.getIdElement());
|
retVal.setIdElement(subscription.getIdElement());
|
||||||
retVal.setPayloadString(subscription.getContentType());
|
retVal.setPayloadString(subscription.getContentType());
|
||||||
|
retVal.setPayloadSearchCriteria(getExtensionString(subscription, HapiExtensions.EXT_SUBSCRIPTION_PAYLOAD_SEARCH_CRITERIA));
|
||||||
|
|
||||||
if (retVal.getChannelType() == CanonicalSubscriptionChannelType.EMAIL) {
|
if (retVal.getChannelType() == CanonicalSubscriptionChannelType.EMAIL) {
|
||||||
String from;
|
String from;
|
||||||
String subjectTemplate;
|
String subjectTemplate;
|
||||||
try {
|
try {
|
||||||
from = getExtensionString(subscription, JpaConstants.EXT_SUBSCRIPTION_EMAIL_FROM);
|
from = getExtensionString(subscription, HapiExtensions.EXT_SUBSCRIPTION_EMAIL_FROM);
|
||||||
subjectTemplate = getExtensionString(subscription, JpaConstants.EXT_SUBSCRIPTION_SUBJECT_TEMPLATE);
|
subjectTemplate = getExtensionString(subscription, HapiExtensions.EXT_SUBSCRIPTION_SUBJECT_TEMPLATE);
|
||||||
} catch (FHIRException theE) {
|
} catch (FHIRException theE) {
|
||||||
throw new ConfigurationException("Failed to extract subscription extension(s): " + theE.getMessage(), theE);
|
throw new ConfigurationException("Failed to extract subscription extension(s): " + theE.getMessage(), theE);
|
||||||
}
|
}
|
||||||
|
@ -279,8 +282,8 @@ public class SubscriptionCanonicalizer {
|
||||||
String stripVersionIds;
|
String stripVersionIds;
|
||||||
String deliverLatestVersion;
|
String deliverLatestVersion;
|
||||||
try {
|
try {
|
||||||
stripVersionIds = getExtensionString(subscription, JpaConstants.EXT_SUBSCRIPTION_RESTHOOK_STRIP_VERSION_IDS);
|
stripVersionIds = getExtensionString(subscription, HapiExtensions.EXT_SUBSCRIPTION_RESTHOOK_STRIP_VERSION_IDS);
|
||||||
deliverLatestVersion = getExtensionString(subscription, JpaConstants.EXT_SUBSCRIPTION_RESTHOOK_DELIVER_LATEST_VERSION);
|
deliverLatestVersion = getExtensionString(subscription, HapiExtensions.EXT_SUBSCRIPTION_RESTHOOK_DELIVER_LATEST_VERSION);
|
||||||
} catch (FHIRException theE) {
|
} catch (FHIRException theE) {
|
||||||
throw new ConfigurationException("Failed to extract subscription extension(s): " + theE.getMessage(), theE);
|
throw new ConfigurationException("Failed to extract subscription extension(s): " + theE.getMessage(), theE);
|
||||||
}
|
}
|
||||||
|
@ -382,7 +385,7 @@ public class SubscriptionCanonicalizer {
|
||||||
meta
|
meta
|
||||||
.getTag()
|
.getTag()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(t -> JpaConstants.EXT_SUBSCRIPTION_MATCHING_STRATEGY.equals(t.getSystem()))
|
.filter(t -> HapiExtensions.EXT_SUBSCRIPTION_MATCHING_STRATEGY.equals(t.getSystem()))
|
||||||
.forEach(t -> {
|
.forEach(t -> {
|
||||||
t.setCode(null);
|
t.setCode(null);
|
||||||
t.setSystem(null);
|
t.setSystem(null);
|
||||||
|
@ -403,7 +406,7 @@ public class SubscriptionCanonicalizer {
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Unknown " + SubscriptionMatchingStrategy.class.getSimpleName() + ": " + theStrategy);
|
throw new IllegalStateException("Unknown " + SubscriptionMatchingStrategy.class.getSimpleName() + ": " + theStrategy);
|
||||||
}
|
}
|
||||||
meta.addTag().setSystem(JpaConstants.EXT_SUBSCRIPTION_MATCHING_STRATEGY).setCode(value).setDisplay(display);
|
meta.addTag().setSystem(HapiExtensions.EXT_SUBSCRIPTION_MATCHING_STRATEGY).setCode(value).setDisplay(display);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSubscriptionStatus(IBaseResource theSubscription) {
|
public String getSubscriptionStatus(IBaseResource theSubscription) {
|
||||||
|
|
|
@ -34,7 +34,11 @@ import org.hl7.fhir.r4.model.Subscription;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
|
@ -64,6 +68,8 @@ public class CanonicalSubscription implements Serializable, Cloneable, IModelJso
|
||||||
private RestHookDetails myRestHookDetails;
|
private RestHookDetails myRestHookDetails;
|
||||||
@JsonProperty("extensions")
|
@JsonProperty("extensions")
|
||||||
private Map<String, List<String>> myChannelExtensions;
|
private Map<String, List<String>> myChannelExtensions;
|
||||||
|
@JsonProperty("payloadSearchCriteria")
|
||||||
|
private String myPayloadSearchCriteria;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -72,6 +78,14 @@ public class CanonicalSubscription implements Serializable, Cloneable, IModelJso
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPayloadSearchCriteria() {
|
||||||
|
return myPayloadSearchCriteria;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayloadSearchCriteria(String thePayloadSearchCriteria) {
|
||||||
|
myPayloadSearchCriteria = thePayloadSearchCriteria;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For now we're using the R4 TriggerDefinition, but this
|
* For now we're using the R4 TriggerDefinition, but this
|
||||||
* may change in the future when things stabilize
|
* may change in the future when things stabilize
|
||||||
|
@ -80,7 +94,6 @@ public class CanonicalSubscription implements Serializable, Cloneable, IModelJso
|
||||||
myTrigger = theTrigger;
|
myTrigger = theTrigger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public CanonicalSubscriptionChannelType getChannelType() {
|
public CanonicalSubscriptionChannelType getChannelType() {
|
||||||
return myChannelType;
|
return myChannelType;
|
||||||
}
|
}
|
||||||
|
@ -136,7 +149,7 @@ public class CanonicalSubscription implements Serializable, Cloneable, IModelJso
|
||||||
public String getChannelExtension(String theUrl) {
|
public String getChannelExtension(String theUrl) {
|
||||||
String retVal = null;
|
String retVal = null;
|
||||||
List<String> strings = myChannelExtensions.get(theUrl);
|
List<String> strings = myChannelExtensions.get(theUrl);
|
||||||
if (strings != null && strings.isEmpty()==false) {
|
if (strings != null && strings.isEmpty() == false) {
|
||||||
retVal = strings.get(0);
|
retVal = strings.get(0);
|
||||||
}
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -276,6 +289,23 @@ public class CanonicalSubscription implements Serializable, Cloneable, IModelJso
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return new ToStringBuilder(this)
|
||||||
|
.append("myIdElement", myIdElement)
|
||||||
|
.append("myStatus", myStatus)
|
||||||
|
.append("myCriteriaString", myCriteriaString)
|
||||||
|
.append("myEndpointUrl", myEndpointUrl)
|
||||||
|
.append("myPayloadString", myPayloadString)
|
||||||
|
// .append("myHeaders", myHeaders)
|
||||||
|
.append("myChannelType", myChannelType)
|
||||||
|
// .append("myTrigger", myTrigger)
|
||||||
|
// .append("myEmailDetails", myEmailDetails)
|
||||||
|
// .append("myRestHookDetails", myRestHookDetails)
|
||||||
|
// .append("myChannelExtensions", myChannelExtensions)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public static class EmailDetails implements IModelJson {
|
public static class EmailDetails implements IModelJson {
|
||||||
|
|
||||||
@JsonProperty("from")
|
@JsonProperty("from")
|
||||||
|
@ -394,21 +424,4 @@ public class CanonicalSubscription implements Serializable, Cloneable, IModelJso
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return new ToStringBuilder(this)
|
|
||||||
.append("myIdElement", myIdElement)
|
|
||||||
.append("myStatus", myStatus)
|
|
||||||
.append("myCriteriaString", myCriteriaString)
|
|
||||||
.append("myEndpointUrl", myEndpointUrl)
|
|
||||||
.append("myPayloadString", myPayloadString)
|
|
||||||
// .append("myHeaders", myHeaders)
|
|
||||||
.append("myChannelType", myChannelType)
|
|
||||||
// .append("myTrigger", myTrigger)
|
|
||||||
// .append("myEmailDetails", myEmailDetails)
|
|
||||||
// .append("myRestHookDetails", myRestHookDetails)
|
|
||||||
// .append("myChannelExtensions", myChannelExtensions)
|
|
||||||
.toString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import ca.uhn.fhir.interceptor.api.Hook;
|
||||||
import ca.uhn.fhir.interceptor.api.Interceptor;
|
import ca.uhn.fhir.interceptor.api.Interceptor;
|
||||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
|
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionMatchingStrategy;
|
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionMatchingStrategy;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator;
|
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionCanonicalizer;
|
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionCanonicalizer;
|
||||||
|
@ -34,6 +35,7 @@ import ca.uhn.fhir.parser.DataFormatException;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -96,32 +98,19 @@ public class SubscriptionValidatingInterceptor {
|
||||||
|
|
||||||
if (!finished) {
|
if (!finished) {
|
||||||
|
|
||||||
String query = subscription.getCriteriaString();
|
validateQuery(subscription.getCriteriaString(), "Subscription.criteria");
|
||||||
if (isBlank(query)) {
|
|
||||||
throw new UnprocessableEntityException("Subscription.criteria must be populated");
|
|
||||||
}
|
|
||||||
|
|
||||||
int sep = query.indexOf('?');
|
if (subscription.getPayloadSearchCriteria() != null) {
|
||||||
if (sep <= 1) {
|
validateQuery(subscription.getPayloadSearchCriteria(), "Subscription.extension(url='" + HapiExtensions.EXT_SUBSCRIPTION_PAYLOAD_SEARCH_CRITERIA + "')");
|
||||||
throw new UnprocessableEntityException("Subscription.criteria must be in the form \"{Resource Type}?[params]\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
String resType = query.substring(0, sep);
|
|
||||||
if (resType.contains("/")) {
|
|
||||||
throw new UnprocessableEntityException("Subscription.criteria must be in the form \"{Resource Type}?[params]\"");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
validateChannelType(subscription);
|
validateChannelType(subscription);
|
||||||
|
|
||||||
if (!myDaoRegistry.isResourceTypeSupported(resType)) {
|
|
||||||
throw new UnprocessableEntityException("Subscription.criteria contains invalid/unsupported resource type: " + resType);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SubscriptionMatchingStrategy strategy = mySubscriptionStrategyEvaluator.determineStrategy(query);
|
SubscriptionMatchingStrategy strategy = mySubscriptionStrategyEvaluator.determineStrategy(subscription.getCriteriaString());
|
||||||
mySubscriptionCanonicalizer.setMatchingStrategyTag(theSubscription, strategy);
|
mySubscriptionCanonicalizer.setMatchingStrategyTag(theSubscription, strategy);
|
||||||
} catch (InvalidRequestException | DataFormatException e) {
|
} catch (InvalidRequestException | DataFormatException e) {
|
||||||
throw new UnprocessableEntityException("Invalid subscription criteria submitted: " + query + " " + e.getMessage());
|
throw new UnprocessableEntityException("Invalid subscription criteria submitted: " + subscription.getCriteriaString() + " " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subscription.getChannelType() == null) {
|
if (subscription.getChannelType() == null) {
|
||||||
|
@ -129,6 +118,28 @@ public class SubscriptionValidatingInterceptor {
|
||||||
} else if (subscription.getChannelType() == CanonicalSubscriptionChannelType.MESSAGE) {
|
} else if (subscription.getChannelType() == CanonicalSubscriptionChannelType.MESSAGE) {
|
||||||
validateMessageSubscriptionEndpoint(subscription.getEndpointUrl());
|
validateMessageSubscriptionEndpoint(subscription.getEndpointUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validateQuery(String theQuery, String theFieldName) {
|
||||||
|
if (isBlank(theQuery)) {
|
||||||
|
throw new UnprocessableEntityException(theFieldName + " must be populated");
|
||||||
|
}
|
||||||
|
|
||||||
|
int sep = theQuery.indexOf('?');
|
||||||
|
if (sep <= 1) {
|
||||||
|
throw new UnprocessableEntityException(theFieldName + " must be in the form \"{Resource Type}?[params]\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
String resType = theQuery.substring(0, sep);
|
||||||
|
if (resType.contains("/")) {
|
||||||
|
throw new UnprocessableEntityException(theFieldName + " must be in the form \"{Resource Type}?[params]\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!myDaoRegistry.isResourceTypeSupported(resType)) {
|
||||||
|
throw new UnprocessableEntityException(theFieldName + " contains invalid/unsupported resource type: " + resType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||||
|
@ -93,8 +94,9 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Primary
|
||||||
@Bean
|
@Bean
|
||||||
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
|
public JpaTransactionManager hapiTransactionManager(EntityManagerFactory entityManagerFactory) {
|
||||||
JpaTransactionManager retVal = new JpaTransactionManager();
|
JpaTransactionManager retVal = new JpaTransactionManager();
|
||||||
retVal.setEntityManagerFactory(entityManagerFactory);
|
retVal.setEntityManagerFactory(entityManagerFactory);
|
||||||
return retVal;
|
return retVal;
|
||||||
|
|
|
@ -19,6 +19,7 @@ import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||||
|
@ -161,7 +162,8 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
|
@Primary
|
||||||
|
public JpaTransactionManager hapiTransactionManager(EntityManagerFactory entityManagerFactory) {
|
||||||
JpaTransactionManager retVal = new JpaTransactionManager();
|
JpaTransactionManager retVal = new JpaTransactionManager();
|
||||||
retVal.setEntityManagerFactory(entityManagerFactory);
|
retVal.setEntityManagerFactory(entityManagerFactory);
|
||||||
return retVal;
|
return retVal;
|
||||||
|
|
|
@ -19,6 +19,7 @@ import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||||
|
@ -155,7 +156,8 @@ public class TestR4Config extends BaseJavaConfigR4 {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
|
@Primary
|
||||||
|
public JpaTransactionManager hapiTransactionManager(EntityManagerFactory entityManagerFactory) {
|
||||||
JpaTransactionManager retVal = new JpaTransactionManager();
|
JpaTransactionManager retVal = new JpaTransactionManager();
|
||||||
retVal.setEntityManagerFactory(entityManagerFactory);
|
retVal.setEntityManagerFactory(entityManagerFactory);
|
||||||
return retVal;
|
return retVal;
|
||||||
|
|
|
@ -19,6 +19,7 @@ import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||||
|
@ -155,7 +156,8 @@ public class TestR5Config extends BaseJavaConfigR5 {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
|
@Primary
|
||||||
|
public JpaTransactionManager hapiTransactionManager(EntityManagerFactory entityManagerFactory) {
|
||||||
JpaTransactionManager retVal = new JpaTransactionManager();
|
JpaTransactionManager retVal = new JpaTransactionManager();
|
||||||
retVal.setEntityManagerFactory(entityManagerFactory);
|
retVal.setEntityManagerFactory(entityManagerFactory);
|
||||||
return retVal;
|
return retVal;
|
||||||
|
|
|
@ -21,14 +21,13 @@ package ca.uhn.fhir.empi.rules.metric;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
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.EmpiPersonNameMatchModeEnum;
|
||||||
import ca.uhn.fhir.empi.rules.metric.matcher.HapiDateMatcher;
|
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.HapiStringMatcher;
|
||||||
import ca.uhn.fhir.empi.rules.metric.matcher.IEmpiFieldMatcher;
|
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.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.matcher.SubstringStringMatcher;
|
||||||
import ca.uhn.fhir.empi.rules.metric.similarity.HapiStringSimilarity;
|
import ca.uhn.fhir.empi.rules.metric.similarity.HapiStringSimilarity;
|
||||||
import ca.uhn.fhir.empi.rules.metric.similarity.IEmpiFieldSimilarity;
|
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.JaroWinkler;
|
||||||
import info.debatty.java.stringsimilarity.NormalizedLevenshtein;
|
import info.debatty.java.stringsimilarity.NormalizedLevenshtein;
|
||||||
import info.debatty.java.stringsimilarity.SorensenDice;
|
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 org.hl7.fhir.instance.model.api.IBase;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -49,13 +45,19 @@ import javax.annotation.Nullable;
|
||||||
* calculating differences between strings (https://en.wikipedia.org/wiki/String_metric)
|
* calculating differences between strings (https://en.wikipedia.org/wiki/String_metric)
|
||||||
*/
|
*/
|
||||||
public enum EmpiMetricEnum {
|
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()),
|
STRING(new HapiStringMatcher()),
|
||||||
SUBSTRING(new HapiStringMatcher(new SubstringStringMatcher())),
|
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()),
|
DATE(new HapiDateMatcher()),
|
||||||
JARO_WINKLER(new HapiStringSimilarity(new JaroWinkler())),
|
JARO_WINKLER(new HapiStringSimilarity(new JaroWinkler())),
|
||||||
COSINE(new HapiStringSimilarity(new Cosine())),
|
COSINE(new HapiStringSimilarity(new Cosine())),
|
||||||
|
|
|
@ -20,11 +20,22 @@ package ca.uhn.fhir.empi.rules.metric.matcher;
|
||||||
* #L%
|
* #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
|
@Override
|
||||||
public boolean matches(String theLeftString, String theRightString) {
|
public boolean matches(String theLeftString, String theRightString) {
|
||||||
return new DoubleMetaphone().isDoubleMetaphoneEqual(theLeftString, theRightString);
|
return myStringEncoder.encode(theLeftString).equals(myStringEncoder.encode(theRightString));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,14 +20,6 @@ package ca.uhn.fhir.rest.server.method;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.ConfigurationException;
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.Include;
|
import ca.uhn.fhir.model.api.Include;
|
||||||
|
@ -35,9 +27,18 @@ import ca.uhn.fhir.rest.annotation.IncludeParam;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.QualifiedParamList;
|
import ca.uhn.fhir.rest.api.QualifiedParamList;
|
||||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||||
|
import ca.uhn.fhir.rest.param.ParameterUtil;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
class IncludeParameter extends BaseQueryParameter {
|
class IncludeParameter extends BaseQueryParameter {
|
||||||
|
|
||||||
private Set<String> myAllow;
|
private Set<String> myAllow;
|
||||||
|
@ -142,7 +143,7 @@ class IncludeParameter extends BaseQueryParameter {
|
||||||
}
|
}
|
||||||
|
|
||||||
String qualifier = nextParamList.getQualifier();
|
String qualifier = nextParamList.getQualifier();
|
||||||
boolean recurse = Constants.PARAM_INCLUDE_QUALIFIER_RECURSE.equals(qualifier) || Constants.PARAM_INCLUDE_QUALIFIER_ITERATE.equals(qualifier);
|
boolean iterate = ParameterUtil.isIncludeIterate(qualifier);
|
||||||
|
|
||||||
String value = nextParamList.get(0);
|
String value = nextParamList.get(0);
|
||||||
if (myAllow != null && !myAllow.isEmpty()) {
|
if (myAllow != null && !myAllow.isEmpty()) {
|
||||||
|
@ -157,10 +158,10 @@ class IncludeParameter extends BaseQueryParameter {
|
||||||
if (mySpecType == String.class) {
|
if (mySpecType == String.class) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
return new Include(value, recurse);
|
return new Include(value, iterate);
|
||||||
}
|
}
|
||||||
|
|
||||||
retValCollection.add(new Include(value, recurse));
|
retValCollection.add(new Include(value, iterate));
|
||||||
}
|
}
|
||||||
|
|
||||||
return retValCollection;
|
return retValCollection;
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
package ca.uhn.fhir.util;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import org.hl7.fhir.r4.model.Bundle;
|
||||||
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
|
import org.hl7.fhir.r4.model.codesystems.HttpVerb;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
|
|
||||||
|
public class TransactionBuilderTest {
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(TransactionBuilderTest.class);
|
||||||
|
private FhirContext myFhirContext = FhirContext.forR4();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddEntryUpdate() {
|
||||||
|
TransactionBuilder builder = new TransactionBuilder(myFhirContext);
|
||||||
|
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.setId("http://foo/Patient/123");
|
||||||
|
patient.setActive(true);
|
||||||
|
builder.addUpdateEntry(patient);
|
||||||
|
|
||||||
|
Bundle bundle = (Bundle) builder.getBundle();
|
||||||
|
ourLog.info("Bundle:\n{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle));
|
||||||
|
|
||||||
|
assertEquals(Bundle.BundleType.TRANSACTION, bundle.getType());
|
||||||
|
assertEquals(1, bundle.getEntry().size());
|
||||||
|
assertSame(patient, bundle.getEntry().get(0).getResource());
|
||||||
|
assertEquals("http://foo/Patient/123", bundle.getEntry().get(0).getFullUrl());
|
||||||
|
assertEquals("Patient/123", bundle.getEntry().get(0).getRequest().getUrl());
|
||||||
|
assertEquals(Bundle.HTTPVerb.PUT, bundle.getEntry().get(0).getRequest().getMethod());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue