Merge remote-tracking branch 'origin/master' into ng_20201218_survivorship_poc
This commit is contained in:
commit
b00f47ef81
|
@ -151,6 +151,10 @@
|
|||
<groupId>net.bytebuddy</groupId>
|
||||
<artifactId>byte-buddy</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.bind</groupId>
|
||||
<artifactId>jaxb-impl</artifactId>
|
||||
</dependency>
|
||||
</ignoredDependencies>
|
||||
<ignoredResourcePatterns>
|
||||
<ignoredResourcePattern>.*\.txt$</ignoredResourcePattern>
|
||||
|
|
|
@ -1260,10 +1260,12 @@ class ParserState<T> {
|
|||
String versionId = elem.getMeta().getVersionId();
|
||||
if (StringUtils.isBlank(elem.getIdElement().getIdPart())) {
|
||||
// Resource has no ID
|
||||
} else if (StringUtils.isNotBlank(versionId)) {
|
||||
elem.getIdElement().setValue(resourceName + "/" + elem.getIdElement().getIdPart() + "/_history/" + versionId);
|
||||
} else {
|
||||
elem.getIdElement().setValue(resourceName + "/" + elem.getIdElement().getIdPart());
|
||||
} else if (!elem.getIdElement().getIdPart().startsWith("urn:")) {
|
||||
if (StringUtils.isNotBlank(versionId)) {
|
||||
elem.getIdElement().setValue(resourceName + "/" + elem.getIdElement().getIdPart() + "/_history/" + versionId);
|
||||
} else {
|
||||
elem.getIdElement().setValue(resourceName + "/" + elem.getIdElement().getIdPart());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import org.apache.jena.datatypes.xsd.XSDDatatype;
|
||||
import org.apache.jena.rdf.model.*;
|
||||
import org.apache.jena.riot.Lang;
|
||||
import org.apache.jena.riot.system.IRIResolver;
|
||||
import org.apache.jena.vocabulary.RDF;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
|
||||
|
@ -171,10 +172,14 @@ public class RDFParser extends BaseParser {
|
|||
if (!uriBase.endsWith("/")) {
|
||||
uriBase = uriBase + "/";
|
||||
}
|
||||
String resourceUri = uriBase + resource.getIdElement().toUnqualified();
|
||||
|
||||
if (parentResource == null) {
|
||||
parentResource = rdfModel.getResource(resourceUri);
|
||||
if (!resource.getIdElement().toUnqualified().hasIdPart()) {
|
||||
parentResource = rdfModel.getResource(null);
|
||||
} else {
|
||||
String resourceUri = IRIResolver.resolve(resource.getIdElement().toUnqualified().toString(), uriBase).toString();
|
||||
parentResource = rdfModel.getResource(resourceUri);
|
||||
}
|
||||
// If the resource already exists and has statements, return that existing resource.
|
||||
if (parentResource != null && parentResource.listProperties().toList().size() > 0) {
|
||||
return parentResource;
|
||||
|
|
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.rest.param;
|
|||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.model.base.composite.BaseQuantityDt;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
@ -301,4 +302,22 @@ public class QuantityParam extends BaseParamWithPrefix<QuantityParam> implements
|
|||
return b.toString();
|
||||
}
|
||||
|
||||
public static QuantityParam toQuantityParam(IQueryParameterType theParam) {
|
||||
if (theParam instanceof BaseQuantityDt) {
|
||||
BaseQuantityDt param = (BaseQuantityDt) theParam;
|
||||
String systemValue = param.getSystemElement().getValueAsString();
|
||||
String unitsValue = param.getUnitsElement().getValueAsString();
|
||||
ParamPrefixEnum cmpValue = ParamPrefixEnum.forValue(param.getComparatorElement().getValueAsString());
|
||||
BigDecimal valueValue = param.getValueElement().getValue();
|
||||
return new QuantityParam()
|
||||
.setSystem(systemValue)
|
||||
.setUnits(unitsValue)
|
||||
.setPrefix(cmpValue)
|
||||
.setValue(valueValue);
|
||||
} else if (theParam instanceof QuantityParam) {
|
||||
return (QuantityParam) theParam;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid quantity type: " + theParam.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,15 +24,21 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.util.BundleUtil;
|
||||
import ca.uhn.fhir.validation.*;
|
||||
import ca.uhn.fhir.validation.FhirValidator;
|
||||
import ca.uhn.fhir.validation.IValidationContext;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import ca.uhn.fhir.validation.SchemaBaseValidator;
|
||||
import ca.uhn.fhir.validation.SingleValidationMessage;
|
||||
import ca.uhn.fhir.validation.ValidationContext;
|
||||
import com.helger.commons.error.IError;
|
||||
import com.helger.commons.error.list.IErrorList;
|
||||
import com.helger.schematron.ISchematronResource;
|
||||
import com.helger.schematron.SchematronHelper;
|
||||
import com.helger.schematron.svrl.jaxb.SchematronOutputType;
|
||||
import com.helger.schematron.xslt.SchematronResourceSCH;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.oclc.purl.dsdl.svrl.SchematronOutputType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.expansionRefersToUnknownCs=Unknown CodeSystem URI "{0}" referenced from ValueSet
|
||||
ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.valueSetNotYetExpanded=ValueSet "{0}" has not yet been pre-expanded. Performing in-memory expansion without parameters. Current status: {1} | {2}
|
||||
ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.valueSetNotYetExpanded_OffsetNotAllowed=ValueSet expansion can not combine "offset" with "ValueSet.compose.exclude" unless the ValueSet has been pre-expanded. ValueSet "{0}" must be pre-expanded for this operation to work.
|
||||
ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.valueSetExpandedUsingPreExpansion=ValueSet was expanded using a pre-calculated expansion
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingRuleBuilder;
|
|||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
@ -107,11 +108,44 @@ public class RepositoryValidatingInterceptorExamples {
|
|||
ruleBuilder
|
||||
.forResourcesOfType("Patient")
|
||||
.requireValidationToDeclaredProfiles()
|
||||
.dontReject()
|
||||
.neverReject()
|
||||
.tagOnSeverity(ResultSeverityEnum.ERROR, "http://example.com", "validation-failure");
|
||||
//END SNIPPET: requireValidationToDeclaredProfilesTagOnFailure
|
||||
}
|
||||
|
||||
public void requireValidationToDeclaredProfilesAdditionalOptions() {
|
||||
RepositoryValidatingRuleBuilder ruleBuilder = myAppCtx.getBean(RepositoryValidatingRuleBuilder.class);
|
||||
|
||||
//START SNIPPET: requireValidationToDeclaredProfilesAdditionalOptions
|
||||
ruleBuilder
|
||||
.forResourcesOfType("Patient")
|
||||
.requireValidationToDeclaredProfiles()
|
||||
|
||||
// Configure the validator to never reject extensions
|
||||
.allowAnyExtensions()
|
||||
|
||||
// Configure the validator to not perform terminology validation
|
||||
.disableTerminologyChecks()
|
||||
|
||||
// Configure the validator to raise an error if a resource being
|
||||
// validated declares a profile, and the StructureDefinition for
|
||||
// this profile can not be found.
|
||||
.errorOnUnknownProfiles()
|
||||
|
||||
// Configure the validator to suppress the information-level
|
||||
// message that is added to the validation result if a profile
|
||||
// StructureDefinition does not declare a binding for a coded
|
||||
// field.
|
||||
.suppressNoBindingMessage()
|
||||
|
||||
// Configure the validator to suppress the warning-level message
|
||||
// that is added when validating a code that can't be found in a
|
||||
// ValueSet that has an extensible binding.
|
||||
.suppressWarningForExtensibleValueSetValidation();
|
||||
//END SNIPPET: requireValidationToDeclaredProfilesAdditionalOptions
|
||||
}
|
||||
|
||||
|
||||
public void disallowProfiles() {
|
||||
RepositoryValidatingRuleBuilder ruleBuilder = myAppCtx.getBean(RepositoryValidatingRuleBuilder.class);
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
type: add
|
||||
issue: 2054
|
||||
title: "Two new switches have neen added to FhirInstancdValidator to suppress optional warning messages. Thanks
|
||||
to Anders Havn for the pull request!"
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
type: change
|
||||
issue: 2290
|
||||
title: "In the JPA server. the SQL datatype used to index quantities has been changed from `NUMBER(19,2)` to
|
||||
`double precision` (or equivalents depending on platform). This improves the query support for ssearching on
|
||||
very small quantities."
|
|
@ -2,18 +2,22 @@
|
|||
- item:
|
||||
type: "add"
|
||||
title: "The version of a few dependencies have been bumped to the latest versions
|
||||
(dependent HAPI modules listed in brackets):
|
||||
<ul>
|
||||
<li>SLF4j (All Modules): 1.7.28 -> 1.7.30</li>
|
||||
<li>Woodstox (XML FHIR Parser): 4.4.1 -> 6.2.3 (Note that the Maven groupId has changed from <code>org.codehaus.woodstox</code> to <code>com.fasterxml.woodstox</code> and the Maven artifactId has changed from <code>woodstox-core-asl</code> to <code>woodstox-core</code> for this library)</li>
|
||||
<li>Spring (JPA): 5.2.3.RELEASE -> 5.2.9.RELEASE</li>
|
||||
<li>Datasource-Proxy (JPA): 1.5.1 -> 1.7</li>
|
||||
<li>Jetty (JPA Starter): 9.4.30.v20200611 -> 9.4.35.v20201120</li>
|
||||
<li>Guava (JP): 29.0-jre -> 30.1-jre</li>
|
||||
<li>Hibernate ORM (JPA Server): 5.4.22.FINAL -> 5.4.26.FINAL</li>
|
||||
<li>Spring (JPA Server): 5.2.9.RELEASE -> 5.3.2</li>
|
||||
<li>Spring Data (JPA Server): 2.2.0.RELEASE -> 2.4.2</li>
|
||||
<li>Hibernate Search (JPA Server): 5.11.5.FINAL -> 6.0.0.Final</li>
|
||||
<li>Lucene(HAPI FHIR JPA Server): 5.5.5 -> 8.7.0</li>
|
||||
<li>Spring Boot (JPA Starter): 2.2.6.RELEASE -> 2.4.1</li>
|
||||
</ul>"
|
||||
(dependent HAPI modules listed in brackets):
|
||||
* SLF4j (All Modules): 1.7.28 -> 1.7.30
|
||||
* Jackson (All Modules): 2.11.2 -> 2.12.1
|
||||
* Woodstox (XML FHIR Parser): 4.4.1 -> 6.2.3 (Note that the Maven groupId has changed from `org.codehaus.woodstox` to `com.fasterxml.woodstox` and the Maven artifactId has changed from `woodstox-core-asl` to `woodstox-core` for this library)
|
||||
* Spring (JPA): 5.2.3.RELEASE -> 5.2.9.RELEASE
|
||||
* Datasource-Proxy (JPA): 1.5.1 -> 1.7
|
||||
* Apache Commons Collections4 (JPA): 4.3 -> 4.4
|
||||
* Jetty (JPA Starter): 9.4.30.v20200611 -> 9.4.35.v20201120
|
||||
* Guava (JP): 29.0-jre -> 30.1-jre
|
||||
* Hibernate ORM (JPA Server): 5.4.22.FINAL -> 5.4.26.FINAL
|
||||
* Spring (JPA Server): 5.2.9.RELEASE -> 5.3.3
|
||||
* Spring Data (JPA Server): 2.2.0.RELEASE -> 2.4.2
|
||||
* Hibernate Search (JPA Server): 5.11.5.FINAL -> 6.0.0.Final
|
||||
* Lucene(HAPI FHIR JPA Server): 5.5.5 -> 8.7.0
|
||||
* Spring Boot (JPA Starter): 2.2.6.RELEASE -> 2.4.1
|
||||
* JANSI (CLI): 1.18 -> 2.1.1
|
||||
* PH-Schematron (SCH Validator): 5.2.0 -> 5.6.5
|
||||
* PH-Commons (SCH Validator): 5.3.8 -> 9.5.4
|
||||
"
|
||||
|
|
|
@ -64,6 +64,8 @@ Note that this rule alone does not actually enforce validation against the speci
|
|||
}
|
||||
```
|
||||
|
||||
<a name="require-validation"/>
|
||||
|
||||
# Rules: Require Validation to Declared Profiles
|
||||
|
||||
Use the following rule to require that resources of the given type be validated successfully before allowing them to be persisted. For every resource of the given type that is submitted for storage, the `Resource.meta.profile` field will be examined and the resource will be validated against any declarations found there.
|
||||
|
@ -93,6 +95,13 @@ By default, resource updates/changes resulting in failing validation will cause
|
|||
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/RepositoryValidatingInterceptorExamples.java|requireValidationToDeclaredProfilesTagOnFailure}}
|
||||
```
|
||||
|
||||
## Configuring the Validator
|
||||
|
||||
The following snippet shows a number of additional optional settings that can be chained onto the validation rule.
|
||||
|
||||
```java
|
||||
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/RepositoryValidatingInterceptorExamples.java|requireValidationToDeclaredProfilesAdditionalOptions}}
|
||||
```
|
||||
|
||||
# Rules: Disallow Specific Profiles
|
||||
|
||||
|
@ -101,3 +110,7 @@ Rules can declare that a specific profile is not allowed.
|
|||
```java
|
||||
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/RepositoryValidatingInterceptorExamples.java|disallowProfiles}}
|
||||
```
|
||||
|
||||
# Adding Validation Outcome to HTTP Response
|
||||
|
||||
If you have included a [Require Validation](#require-validation) rule to your chain, you can add the `ValidationResultEnrichingInterceptor` to your server if you wish to have validation results added to and OperationOutcome objects that are returned by the server.
|
||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.dao.data;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantityNormalized;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
|
||||
|
@ -27,7 +28,7 @@ import org.springframework.data.jpa.repository.Modifying;
|
|||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface IResourceIndexedSearchParamQuantityNormalizedDao extends JpaRepository<ResourceIndexedSearchParamQuantity, Long> {
|
||||
public interface IResourceIndexedSearchParamQuantityNormalizedDao extends JpaRepository<ResourceIndexedSearchParamQuantityNormalized, Long> {
|
||||
@Modifying
|
||||
@Query("delete from ResourceIndexedSearchParamQuantityNormalized t WHERE t.myResourcePid = :resid")
|
||||
void deleteByResourceId(@Param("resid") Long theResourcePid);
|
||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.interceptor.validation;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -35,7 +36,7 @@ public interface IRepositoryValidatingRule {
|
|||
String getResourceType();
|
||||
|
||||
@Nonnull
|
||||
RuleEvaluation evaluate(@Nonnull IBaseResource theResource);
|
||||
RuleEvaluation evaluate(RequestDetails theRequestDetails, @Nonnull IBaseResource theResource);
|
||||
|
||||
class RuleEvaluation {
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.interceptor.api.Hook;
|
||||
import ca.uhn.fhir.interceptor.api.Interceptor;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||
import ca.uhn.fhir.util.OperationOutcomeUtil;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
|
@ -47,7 +48,7 @@ import java.util.stream.Collectors;
|
|||
public class RepositoryValidatingInterceptor {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(RepositoryValidatingInterceptor.class);
|
||||
private Multimap<String, IRepositoryValidatingRule> myRules = ArrayListMultimap.create();
|
||||
private final Multimap<String, IRepositoryValidatingRule> myRules = ArrayListMultimap.create();
|
||||
private FhirContext myFhirContext;
|
||||
|
||||
/**
|
||||
|
@ -113,25 +114,25 @@ public class RepositoryValidatingInterceptor {
|
|||
* Interceptor hook method. This method should not be called directly.
|
||||
*/
|
||||
@Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED)
|
||||
void create(IBaseResource theResource) {
|
||||
handle(theResource);
|
||||
void create(RequestDetails theRequestDetails, IBaseResource theResource) {
|
||||
handle(theRequestDetails, theResource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interceptor hook method. This method should not be called directly.
|
||||
*/
|
||||
@Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED)
|
||||
void update(IBaseResource theOldResource, IBaseResource theNewResource) {
|
||||
handle(theNewResource);
|
||||
void update(RequestDetails theRequestDetails, IBaseResource theOldResource, IBaseResource theNewResource) {
|
||||
handle(theRequestDetails, theNewResource);
|
||||
}
|
||||
|
||||
private void handle(IBaseResource theNewResource) {
|
||||
private void handle(RequestDetails theRequestDetails, IBaseResource theNewResource) {
|
||||
Validate.notNull(myFhirContext, "No FhirContext has been set for this interceptor of type: %s", getClass());
|
||||
|
||||
String resourceType = myFhirContext.getResourceType(theNewResource);
|
||||
Collection<IRepositoryValidatingRule> rules = myRules.get(resourceType);
|
||||
for (IRepositoryValidatingRule nextRule : rules) {
|
||||
IRepositoryValidatingRule.RuleEvaluation outcome = nextRule.evaluate(theNewResource);
|
||||
IRepositoryValidatingRule.RuleEvaluation outcome = nextRule.evaluate(theRequestDetails, theNewResource);
|
||||
if (!outcome.isPasses()) {
|
||||
handleFailure(outcome);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.jpa.interceptor.validation;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.jpa.validation.ValidatorResourceFetcher;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ValidationResultEnrichingInterceptor;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.text.WordUtils;
|
||||
|
@ -148,13 +149,27 @@ public final class RepositoryValidatingRuleBuilder implements IRuleRoot {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param theProfileUrl
|
||||
* @return
|
||||
* If set, any resources that contain a profile declaration in <code>Resource.meta.profile</code>
|
||||
* matching {@literal theProfileUrl} will be rejected.
|
||||
*
|
||||
* @param theProfileUrl The profile canonical URL
|
||||
*/
|
||||
public FinalizedTypedRule disallowProfile(String theProfileUrl) {
|
||||
return disallowProfiles(theProfileUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a resource validation step using the FHIR Instance Validator and reject the
|
||||
* storage if the validation fails.
|
||||
*
|
||||
* <p>
|
||||
* If the {@link ValidationResultEnrichingInterceptor} is registered against the
|
||||
* {@link ca.uhn.fhir.rest.server.RestfulServer} interceptor registry, the validation results
|
||||
* will be appended to any <code>OperationOutcome</code> resource returned by the server.
|
||||
* </p>
|
||||
*
|
||||
* @see ValidationResultEnrichingInterceptor
|
||||
*/
|
||||
public FinalizedRequireValidationRule requireValidationToDeclaredProfiles() {
|
||||
RequireValidationRule rule = new RequireValidationRule(myFhirContext, myType, myValidationSupport, myValidatorResourceFetcher);
|
||||
myRules.add(rule);
|
||||
|
@ -211,7 +226,7 @@ public final class RepositoryValidatingRuleBuilder implements IRuleRoot {
|
|||
* Specifies that the resource should not be rejected from storage even if it does not pass validation.
|
||||
*/
|
||||
@Nonnull
|
||||
public FinalizedRequireValidationRule dontReject() {
|
||||
public FinalizedRequireValidationRule neverReject() {
|
||||
myRule.dontReject();
|
||||
return this;
|
||||
}
|
||||
|
@ -251,13 +266,13 @@ public final class RepositoryValidatingRuleBuilder implements IRuleRoot {
|
|||
* Specifies that if the validation results in any results with a severity of <code>theSeverity</code> or
|
||||
* greater, the resource will be tagged with the given tag when it is saved.
|
||||
*
|
||||
* @param theSeverity The minimum severity. Must be drawn from values in {@link ResultSeverityEnum} and must not be <code>null</code>
|
||||
* @param theSeverity The minimum severity. Must be drawn from values in {@link ResultSeverityEnum} and must not be <code>null</code>
|
||||
* @param theTagSystem The system for the tag to add. Must not be <code>null</code>
|
||||
* @param theTagCode The code for the tag to add. Must not be <code>null</code>
|
||||
* @param theTagCode The code for the tag to add. Must not be <code>null</code>
|
||||
* @return
|
||||
*/
|
||||
@Nonnull
|
||||
public FinalizedRequireValidationRule tagOnSeverity(@Nonnull String theSeverity,@Nonnull String theTagSystem,@Nonnull String theTagCode) {
|
||||
public FinalizedRequireValidationRule tagOnSeverity(@Nonnull String theSeverity, @Nonnull String theTagSystem, @Nonnull String theTagCode) {
|
||||
ResultSeverityEnum severity = ResultSeverityEnum.fromCode(toLowerCase(theSeverity));
|
||||
return tagOnSeverity(severity, theTagSystem, theTagCode);
|
||||
}
|
||||
|
@ -266,17 +281,68 @@ public final class RepositoryValidatingRuleBuilder implements IRuleRoot {
|
|||
* Specifies that if the validation results in any results with a severity of <code>theSeverity</code> or
|
||||
* greater, the resource will be tagged with the given tag when it is saved.
|
||||
*
|
||||
* @param theSeverity The minimum severity. Must be drawn from values in {@link ResultSeverityEnum} and must not be <code>null</code>
|
||||
* @param theSeverity The minimum severity. Must be drawn from values in {@link ResultSeverityEnum} and must not be <code>null</code>
|
||||
* @param theTagSystem The system for the tag to add. Must not be <code>null</code>
|
||||
* @param theTagCode The code for the tag to add. Must not be <code>null</code>
|
||||
* @param theTagCode The code for the tag to add. Must not be <code>null</code>
|
||||
* @return
|
||||
*/
|
||||
@Nonnull
|
||||
public FinalizedRequireValidationRule tagOnSeverity(@Nonnull ResultSeverityEnum theSeverity,@Nonnull String theTagSystem,@Nonnull String theTagCode) {
|
||||
public FinalizedRequireValidationRule tagOnSeverity(@Nonnull ResultSeverityEnum theSeverity, @Nonnull String theTagSystem, @Nonnull String theTagCode) {
|
||||
myRule.tagOnSeverity(theSeverity, theTagSystem, theTagCode);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the validator to never reject extensions
|
||||
*/
|
||||
@Nonnull
|
||||
public FinalizedRequireValidationRule allowAnyExtensions() {
|
||||
myRule.getValidator().setAnyExtensionsAllowed(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the validator to not perform terminology validation
|
||||
*/
|
||||
@Nonnull
|
||||
public FinalizedRequireValidationRule disableTerminologyChecks() {
|
||||
myRule.getValidator().setNoTerminologyChecks(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the validator to raise an error if a resource being validated
|
||||
* declares a profile, and the StructureDefinition for this profile
|
||||
* can not be found.
|
||||
*/
|
||||
@Nonnull
|
||||
public FinalizedRequireValidationRule errorOnUnknownProfiles() {
|
||||
myRule.getValidator().setErrorForUnknownProfiles(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the validator to suppress the information-level message that
|
||||
* is added to the validation result if a profile StructureDefinition does
|
||||
* not declare a binding for a coded field.
|
||||
*/
|
||||
@Nonnull
|
||||
public FinalizedRequireValidationRule suppressNoBindingMessage() {
|
||||
myRule.getValidator().setNoBindingMsgSuppressed(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the validator to suppress the warning-level message that
|
||||
* is added when validating a code that can't be found in an ValueSet that
|
||||
* has an extensible binding.
|
||||
*/
|
||||
@Nonnull
|
||||
public FinalizedRequireValidationRule suppressWarningForExtensibleValueSetValidation() {
|
||||
myRule.getValidator().setNoExtensibleWarnings(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ package ca.uhn.fhir.jpa.interceptor.validation;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.jpa.validation.ValidatorResourceFetcher;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ValidationResultEnrichingInterceptor;
|
||||
import ca.uhn.fhir.validation.FhirValidator;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import ca.uhn.fhir.validation.SingleValidationMessage;
|
||||
|
@ -58,7 +60,7 @@ class RequireValidationRule extends BaseTypedRule {
|
|||
|
||||
@Nonnull
|
||||
@Override
|
||||
public RuleEvaluation evaluate(@Nonnull IBaseResource theResource) {
|
||||
public RuleEvaluation evaluate(RequestDetails theRequestDetails, @Nonnull IBaseResource theResource) {
|
||||
|
||||
FhirValidator validator = getFhirContext().newValidator();
|
||||
validator.registerValidatorModule(myValidator);
|
||||
|
@ -83,6 +85,8 @@ class RequireValidationRule extends BaseTypedRule {
|
|||
|
||||
}
|
||||
|
||||
ValidationResultEnrichingInterceptor.addValidationResultToRequestDetails(theRequestDetails, outcome);
|
||||
|
||||
return RuleEvaluation.forSuccess(this);
|
||||
}
|
||||
|
||||
|
@ -104,6 +108,22 @@ class RequireValidationRule extends BaseTypedRule {
|
|||
myRejectOnSeverity = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
|
||||
.append("resourceType", getResourceType())
|
||||
.append("rejectOnSeverity", myRejectOnSeverity)
|
||||
.append("tagOnSeverity", myTagOnSeverity)
|
||||
.toString();
|
||||
}
|
||||
|
||||
public FhirInstanceValidator getValidator() {
|
||||
return myValidator;
|
||||
}
|
||||
|
||||
public void setAllowAnyExtensions() {
|
||||
myValidator.setAnyExtensionsAllowed(true);
|
||||
}
|
||||
|
||||
private static class TagOnSeverity {
|
||||
private final int mySeverity;
|
||||
|
@ -133,13 +153,4 @@ class RequireValidationRule extends BaseTypedRule {
|
|||
return ResultSeverityEnum.values()[mySeverity].name() + "/" + myTagSystem + "/" + myTagCode;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
|
||||
.append("resourceType", getResourceType())
|
||||
.append("rejectOnSeverity", myRejectOnSeverity)
|
||||
.append("tagOnSeverity", myTagOnSeverity)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.interceptor.validation;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
|
@ -47,7 +48,7 @@ class RuleDisallowProfile extends BaseTypedRule {
|
|||
|
||||
@Nonnull
|
||||
@Override
|
||||
public RuleEvaluation evaluate(@Nonnull IBaseResource theResource) {
|
||||
public RuleEvaluation evaluate(RequestDetails theRequestDetails, @Nonnull IBaseResource theResource) {
|
||||
for (IPrimitiveType<String> next : theResource.getMeta().getProfile()) {
|
||||
String nextUrl = next.getValueAsString();
|
||||
String nextUrlNormalized = UrlUtil.normalizeCanonicalUrlForComparison(nextUrl);
|
||||
|
|
|
@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.interceptor.validation;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -39,7 +40,7 @@ class RuleRequireProfileDeclaration extends BaseTypedRule {
|
|||
|
||||
@Nonnull
|
||||
@Override
|
||||
public RuleEvaluation evaluate(@Nonnull IBaseResource theResource) {
|
||||
public RuleEvaluation evaluate(RequestDetails theRequestDetails, @Nonnull IBaseResource theResource) {
|
||||
Optional<String> matchingProfile = theResource
|
||||
.getMeta()
|
||||
.getProfile()
|
||||
|
|
|
@ -31,7 +31,9 @@ import ca.uhn.fhir.jpa.dao.predicate.PredicateBuilderToken;
|
|||
import ca.uhn.fhir.jpa.dao.predicate.SearchFilterParser;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||
import ca.uhn.fhir.jpa.model.entity.TagTypeEnum;
|
||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.BaseJoiningPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.CompositeUniqueSearchParameterPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.CoordsPredicateBuilder;
|
||||
|
@ -43,12 +45,12 @@ import ca.uhn.fhir.jpa.search.builder.predicate.ResourceIdPredicateBuilder;
|
|||
import ca.uhn.fhir.jpa.search.builder.predicate.ResourceLinkPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.ResourceTablePredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.SearchParamPresentPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.sql.SearchQueryBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.SourcePredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.StringPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.TagPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.TokenPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.UriPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.sql.SearchQueryBuilder;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.BaseSearchParamExtractor;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
|
@ -185,14 +187,9 @@ public class QueryStack {
|
|||
|
||||
public void addSortOnQuantity(String theResourceName, String theParamName, boolean theAscending) {
|
||||
BaseJoiningPredicateBuilder firstPredicateBuilder = mySqlBuilder.getOrCreateFirstPredicateBuilder();
|
||||
|
||||
QuantityBasePredicateBuilder sortPredicateBuilder = null;
|
||||
if (myModelConfig.isNormalizedQuantitySearchSupported()) {
|
||||
sortPredicateBuilder = mySqlBuilder.addQuantityNormalizedPredicateBuilder(firstPredicateBuilder.getResourceIdColumn());
|
||||
} else {
|
||||
sortPredicateBuilder = mySqlBuilder.addQuantityPredicateBuilder(firstPredicateBuilder.getResourceIdColumn());
|
||||
|
||||
}
|
||||
QuantityBasePredicateBuilder sortPredicateBuilder;
|
||||
sortPredicateBuilder = mySqlBuilder.addQuantityPredicateBuilder(firstPredicateBuilder.getResourceIdColumn());
|
||||
|
||||
Condition hashIdentityPredicate = sortPredicateBuilder.createHashIdentityPredicate(theResourceName, theParamName);
|
||||
mySqlBuilder.addPredicate(hashIdentityPredicate);
|
||||
|
@ -272,33 +269,33 @@ public class QueryStack {
|
|||
return new PredicateBuilderCacheLookupResult<>(cacheHit, (T) retVal);
|
||||
}
|
||||
|
||||
private Condition createPredicateComposite(@Nullable DbColumn theSourceJoinColumn, String theResourceName, RuntimeSearchParam theParamDef, List<? extends IQueryParameterType> theNextAnd, RequestPartitionId theRequestPartitionId) {
|
||||
private Condition createPredicateComposite(@Nullable DbColumn theSourceJoinColumn, String theResourceName, RuntimeSearchParam theParamDef, List<? extends IQueryParameterType> theNextAnd, RequestPartitionId theRequestPartitionId) {
|
||||
|
||||
Condition orCondidtion = null;
|
||||
Condition orCondidtion = null;
|
||||
for (IQueryParameterType next : theNextAnd) {
|
||||
|
||||
|
||||
if (!(next instanceof CompositeParam<?, ?>)) {
|
||||
throw new InvalidRequestException("Invalid type for composite param (must be " + CompositeParam.class.getSimpleName() + ": " + next.getClass());
|
||||
}
|
||||
CompositeParam<?, ?> cp = (CompositeParam<?, ?>) next;
|
||||
|
||||
|
||||
RuntimeSearchParam left = theParamDef.getCompositeOf().get(0);
|
||||
IQueryParameterType leftValue = cp.getLeftValue();
|
||||
Condition leftPredicate = createPredicateCompositePart(theSourceJoinColumn, theResourceName, left, leftValue, theRequestPartitionId);
|
||||
|
||||
|
||||
RuntimeSearchParam right = theParamDef.getCompositeOf().get(1);
|
||||
IQueryParameterType rightValue = cp.getRightValue();
|
||||
Condition rightPredicate = createPredicateCompositePart(theSourceJoinColumn, theResourceName, right, rightValue, theRequestPartitionId);
|
||||
|
||||
|
||||
Condition andCondition = toAndPredicate(leftPredicate, rightPredicate);
|
||||
|
||||
|
||||
if (orCondidtion == null) {
|
||||
orCondidtion = toOrPredicate(andCondition);
|
||||
} else {
|
||||
orCondidtion = toOrPredicate(orCondidtion, andCondition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return orCondidtion;
|
||||
}
|
||||
|
||||
|
@ -414,11 +411,11 @@ public class QueryStack {
|
|||
param.setValueAsQueryToken(null, null, null, theFilter.getValue());
|
||||
return theQueryStack3.createPredicateResourceId(null, Collections.singletonList(Collections.singletonList(param)), theResourceName, theFilter.getOperation(), theRequestPartitionId);
|
||||
} else if (paramName.equals(IAnyResource.SP_RES_LANGUAGE)) {
|
||||
return theQueryStack3.createPredicateLanguage(Collections.singletonList(Collections.singletonList(new StringParam(theFilter.getValue()))), theFilter.getOperation());
|
||||
return theQueryStack3.createPredicateLanguage(Collections.singletonList(Collections.singletonList(new StringParam(theFilter.getValue()))), theFilter.getOperation());
|
||||
} else if (paramName.equals(Constants.PARAM_SOURCE)) {
|
||||
TokenParam param = new TokenParam();
|
||||
param.setValueAsQueryToken(null, null, null, theFilter.getValue());
|
||||
return createPredicateSource(null, Collections.singletonList(param));
|
||||
TokenParam param = new TokenParam();
|
||||
param.setValueAsQueryToken(null, null, null, theFilter.getValue());
|
||||
return createPredicateSource(null, Collections.singletonList(param));
|
||||
} else {
|
||||
RuntimeSearchParam searchParam = mySearchParamRegistry.getActiveSearchParam(theResourceName, paramName);
|
||||
if (searchParam == null) {
|
||||
|
@ -642,20 +639,38 @@ public class QueryStack {
|
|||
List<? extends IQueryParameterType> theList,
|
||||
SearchFilterParser.CompareOperation theOperation,
|
||||
RequestPartitionId theRequestPartitionId) {
|
||||
|
||||
QuantityBasePredicateBuilder join = null;
|
||||
|
||||
if (myModelConfig.isNormalizedQuantitySearchSupported()) {
|
||||
join = createOrReusePredicateBuilder(PredicateBuilderTypeEnum.QUANTITY, theSourceJoinColumn, theSearchParam.getName(), () -> mySqlBuilder.addQuantityNormalizedPredicateBuilder(theSourceJoinColumn)).getResult();
|
||||
} else {
|
||||
join = createOrReusePredicateBuilder(PredicateBuilderTypeEnum.QUANTITY, theSourceJoinColumn, theSearchParam.getName(), () -> mySqlBuilder.addQuantityPredicateBuilder(theSourceJoinColumn)).getResult();
|
||||
}
|
||||
|
||||
if (theList.get(0).getMissing() != null) {
|
||||
QuantityBasePredicateBuilder join = createOrReusePredicateBuilder(PredicateBuilderTypeEnum.QUANTITY, theSourceJoinColumn, theSearchParam.getName(), () -> mySqlBuilder.addQuantityPredicateBuilder(theSourceJoinColumn)).getResult();
|
||||
return join.createPredicateParamMissingForNonReference(theResourceName, theSearchParam.getName(), theList.get(0).getMissing(), theRequestPartitionId);
|
||||
}
|
||||
|
||||
List<QuantityParam> quantityParams = theList
|
||||
.stream()
|
||||
.map(t -> QuantityParam.toQuantityParam(t))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
QuantityBasePredicateBuilder join = null;
|
||||
boolean normalizedSearchEnabled = myModelConfig.getNormalizedQuantitySearchLevel().equals(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
if (normalizedSearchEnabled) {
|
||||
List<QuantityParam> normalizedQuantityParams = quantityParams
|
||||
.stream()
|
||||
.map(t -> UcumServiceUtil.toCanonicalQuantityOrNull(t))
|
||||
.filter(t -> t != null)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (normalizedQuantityParams.size() == quantityParams.size()) {
|
||||
join = createOrReusePredicateBuilder(PredicateBuilderTypeEnum.QUANTITY, theSourceJoinColumn, theSearchParam.getName(), () -> mySqlBuilder.addQuantityNormalizedPredicateBuilder(theSourceJoinColumn)).getResult();
|
||||
quantityParams = normalizedQuantityParams;
|
||||
}
|
||||
}
|
||||
|
||||
if (join == null) {
|
||||
join = createOrReusePredicateBuilder(PredicateBuilderTypeEnum.QUANTITY, theSourceJoinColumn, theSearchParam.getName(), () -> mySqlBuilder.addQuantityPredicateBuilder(theSourceJoinColumn)).getResult();
|
||||
}
|
||||
|
||||
List<Condition> codePredicates = new ArrayList<>();
|
||||
for (IQueryParameterType nextOr : theList) {
|
||||
for (QuantityParam nextOr : quantityParams) {
|
||||
Condition singleCode = join.createPredicateQuantity(nextOr, theResourceName, theSearchParam.getName(), null, join, theOperation, theRequestPartitionId);
|
||||
codePredicates.add(singleCode);
|
||||
}
|
||||
|
@ -923,7 +938,7 @@ public class QueryStack {
|
|||
|
||||
@Nullable
|
||||
public Condition searchForIdsWithAndOr(@Nullable DbColumn theSourceJoinColumn, String theResourceName, String theParamName, List<List<IQueryParameterType>> theAndOrParams, RequestDetails theRequest, RequestPartitionId theRequestPartitionId) {
|
||||
|
||||
|
||||
if (theAndOrParams.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
@ -1054,7 +1069,7 @@ public class QueryStack {
|
|||
return toAndPredicate(andPredicates);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void addPredicateCompositeUnique(String theIndexString, RequestPartitionId theRequestPartitionId) {
|
||||
|
|
|
@ -20,27 +20,10 @@ package ca.uhn.fhir.jpa.search.builder.predicate;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
|
||||
import org.fhir.ucum.Pair;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import com.healthmarketscience.sqlbuilder.BinaryCondition;
|
||||
import com.healthmarketscience.sqlbuilder.ComboCondition;
|
||||
import com.healthmarketscience.sqlbuilder.Condition;
|
||||
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn;
|
||||
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbTable;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.dao.predicate.SearchFilterParser;
|
||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamBaseQuantity;
|
||||
import ca.uhn.fhir.jpa.search.builder.QueryStack;
|
||||
import ca.uhn.fhir.jpa.search.builder.sql.SearchQueryBuilder;
|
||||
|
@ -48,7 +31,18 @@ import ca.uhn.fhir.model.api.IQueryParameterType;
|
|||
import ca.uhn.fhir.model.base.composite.BaseQuantityDt;
|
||||
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
|
||||
import ca.uhn.fhir.rest.param.QuantityParam;
|
||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||
import com.healthmarketscience.sqlbuilder.BinaryCondition;
|
||||
import com.healthmarketscience.sqlbuilder.ComboCondition;
|
||||
import com.healthmarketscience.sqlbuilder.Condition;
|
||||
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn;
|
||||
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbTable;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
|
||||
public abstract class QuantityBasePredicateBuilder extends BaseSearchParamPredicateBuilder {
|
||||
|
@ -59,11 +53,7 @@ public abstract class QuantityBasePredicateBuilder extends BaseSearchParamPredic
|
|||
|
||||
@Autowired
|
||||
private FhirContext myFhirContext;
|
||||
|
||||
@Autowired
|
||||
private ModelConfig myModelConfig;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
|
@ -71,38 +61,13 @@ public abstract class QuantityBasePredicateBuilder extends BaseSearchParamPredic
|
|||
super(theSearchSqlBuilder, theTable);
|
||||
}
|
||||
|
||||
public Condition createPredicateQuantity(IQueryParameterType theParam, String theResourceName, String theParamName, CriteriaBuilder theBuilder, QuantityBasePredicateBuilder theFrom, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||
|
||||
String systemValue;
|
||||
String unitsValue;
|
||||
ParamPrefixEnum cmpValue;
|
||||
BigDecimal valueValue;
|
||||
public Condition createPredicateQuantity(QuantityParam theParam, String theResourceName, String theParamName, CriteriaBuilder theBuilder, QuantityBasePredicateBuilder theFrom, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||
|
||||
if (theParam instanceof BaseQuantityDt) {
|
||||
BaseQuantityDt param = (BaseQuantityDt) theParam;
|
||||
systemValue = param.getSystemElement().getValueAsString();
|
||||
unitsValue = param.getUnitsElement().getValueAsString();
|
||||
cmpValue = ParamPrefixEnum.forValue(param.getComparatorElement().getValueAsString());
|
||||
valueValue = param.getValueElement().getValue();
|
||||
} else if (theParam instanceof QuantityParam) {
|
||||
QuantityParam param = (QuantityParam) theParam;
|
||||
systemValue = param.getSystem();
|
||||
unitsValue = param.getUnits();
|
||||
cmpValue = param.getPrefix();
|
||||
valueValue = param.getValue();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid quantity type: " + theParam.getClass());
|
||||
}
|
||||
String systemValue = theParam.getSystem();
|
||||
String unitsValue = theParam.getUnits();
|
||||
ParamPrefixEnum cmpValue = theParam.getPrefix();
|
||||
BigDecimal valueValue = theParam.getValue();
|
||||
|
||||
if (myModelConfig.isNormalizedQuantitySearchSupported()) {
|
||||
//-- convert the value/unit to the canonical form if any to use by the search
|
||||
Pair canonicalForm = UcumServiceUtil.getCanonicalForm(systemValue, valueValue, unitsValue);
|
||||
if (canonicalForm != null) {
|
||||
valueValue = new BigDecimal(canonicalForm.getValue().asDecimal());
|
||||
unitsValue = canonicalForm.getCode();
|
||||
}
|
||||
}
|
||||
|
||||
Condition hashPredicate;
|
||||
if (!isBlank(systemValue) && !isBlank(unitsValue)) {
|
||||
long hash = ResourceIndexedSearchParamBaseQuantity.calculateHashSystemAndUnits(getPartitionSettings(), theRequestPartitionId, theResourceName, theParamName, systemValue, unitsValue);
|
||||
|
@ -127,5 +92,6 @@ public abstract class QuantityBasePredicateBuilder extends BaseSearchParamPredic
|
|||
|
||||
public DbColumn getColumnValue() {
|
||||
return myColumnValue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -521,6 +521,8 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
/*
|
||||
* ValueSet is pre-expanded in database so let's use that
|
||||
*/
|
||||
String msg = myContext.getLocalizer().getMessage(BaseTermReadSvcImpl.class, "valueSetExpandedUsingPreExpansion");
|
||||
theAccumulator.addMessage(msg);
|
||||
expandConcepts(theAccumulator, termValueSet, theFilter, theAdd);
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,9 @@ import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
|||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.partition.IPartitionLookupSvc;
|
||||
import ca.uhn.fhir.jpa.provider.r4.BaseJpaResourceProviderObservationR4;
|
||||
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
|
||||
import ca.uhn.fhir.jpa.rp.r4.ObservationResourceProvider;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
|
||||
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
|
||||
|
@ -810,7 +812,8 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil
|
|||
|
||||
Optional<ValueSet.ValueSetExpansionContainsComponent> first = stream.findFirst();
|
||||
if (!first.isPresent()) {
|
||||
String failureMessage = String.format("Expanded ValueSet %s did not contain concept [%s|%s|%s] with [%d] designations", theValueSet.getId(), theSystem, theCode, theDisplay, theDesignationCount);
|
||||
String expandedValueSetString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(theValueSet);
|
||||
String failureMessage = String.format("Expanded ValueSet %s did not contain concept [%s|%s|%s] with [%d] designations. Outcome:\n%s", theValueSet.getId(), theSystem, theCode, theDisplay, theDesignationCount, expandedValueSetString);
|
||||
fail(failureMessage);
|
||||
return null;
|
||||
} else {
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.matchesPattern;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantityNormalized;
|
||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.QuantityParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
@ -33,15 +32,20 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.QuantityParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.matchesPattern;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoR4CreateTest.class);
|
||||
|
@ -51,7 +55,7 @@ public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
|||
myDaoConfig.setResourceServerIdStrategy(new DaoConfig().getResourceServerIdStrategy());
|
||||
myDaoConfig.setResourceClientIdStrategy(new DaoConfig().getResourceClientIdStrategy());
|
||||
myDaoConfig.setDefaultSearchParamsCanBeOverridden(new DaoConfig().isDefaultSearchParamsCanBeOverridden());
|
||||
myModelConfig.setNormalizedQuantitySearchNotSupported();
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -337,9 +341,9 @@ public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
public void testCreateWithNormalizedQuantitySearchSupported_AlreadyCanonicalUnit() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
Observation obs = new Observation();
|
||||
obs.setStatus(Observation.ObservationStatus.FINAL);
|
||||
Quantity q = new Quantity();
|
||||
|
@ -348,34 +352,38 @@ public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
|||
q.setSystem("http://unitsofmeasure.org");
|
||||
q.setCode("cm");
|
||||
obs.setValue(q);
|
||||
|
||||
|
||||
ourLog.info("Observation1: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
|
||||
|
||||
assertTrue(myObservationDao.create(obs).getCreated());
|
||||
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.setLoadSynchronous(true);
|
||||
QuantityParam qp = new QuantityParam();
|
||||
qp.setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL);
|
||||
qp.setValue(new BigDecimal("0.012"));
|
||||
qp.setUnits("m");
|
||||
|
||||
map.add(Observation.SP_VALUE_QUANTITY, qp);
|
||||
|
||||
IBundleProvider found = myObservationDao.search(map);
|
||||
List<String> ids = toUnqualifiedVersionlessIdValues(found);
|
||||
|
||||
List<IBaseResource> resources = found.getResources(0, found.size());
|
||||
|
||||
assertEquals(1, ids.size());
|
||||
|
||||
ourLog.info("Observation2: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(resources.get(0)));
|
||||
|
||||
// Same value should be placed in both quantity tables
|
||||
runInTransaction(()->{
|
||||
List<ResourceIndexedSearchParamQuantity> quantityIndexes = myResourceIndexedSearchParamQuantityDao.findAll().stream().filter(t->t.getParamName().equals("value-quantity")).collect(Collectors.toList());
|
||||
assertEquals(1, quantityIndexes.size());
|
||||
assertEquals("1.2", Double.toString(quantityIndexes.get(0).getValue().doubleValue()));
|
||||
assertEquals("http://unitsofmeasure.org", quantityIndexes.get(0).getSystem());
|
||||
assertEquals("cm", quantityIndexes.get(0).getUnits());
|
||||
|
||||
List<ResourceIndexedSearchParamQuantityNormalized> normalizedQuantityIndexes = myResourceIndexedSearchParamQuantityNormalizedDao.findAll().stream().filter(t->t.getParamName().equals("value-quantity")).collect(Collectors.toList());
|
||||
assertEquals(1, normalizedQuantityIndexes.size());
|
||||
assertEquals("0.012", Double.toString(normalizedQuantityIndexes.get(0).getValue()));
|
||||
assertEquals("http://unitsofmeasure.org", normalizedQuantityIndexes.get(0).getSystem());
|
||||
assertEquals("m", normalizedQuantityIndexes.get(0).getUnits());
|
||||
});
|
||||
|
||||
SearchParameterMap map = SearchParameterMap.newSynchronous(Observation.SP_VALUE_QUANTITY, new QuantityParam()
|
||||
.setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL)
|
||||
.setValue(new BigDecimal("0.012"))
|
||||
.setUnits("m")
|
||||
);
|
||||
assertEquals(1, toUnqualifiedVersionlessIdValues(myObservationDao.search(map)).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithNormalizedQuantitySearchSupportedWithVerySmallNumber() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
public void testCreateWithNormalizedQuantitySearchSupported_SmallerThanCanonicalUnit() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
Observation obs = new Observation();
|
||||
obs.setStatus(Observation.ObservationStatus.FINAL);
|
||||
Quantity q = new Quantity();
|
||||
|
@ -384,102 +392,358 @@ public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
|||
q.setSystem("http://unitsofmeasure.org");
|
||||
q.setCode("mm");
|
||||
obs.setValue(q);
|
||||
|
||||
|
||||
ourLog.info("Observation1: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
|
||||
|
||||
myCaptureQueriesListener.clear();
|
||||
assertTrue(myObservationDao.create(obs).getCreated());
|
||||
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.setLoadSynchronous(true);
|
||||
QuantityParam qp = new QuantityParam();
|
||||
qp.setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL);
|
||||
qp.setValue(new BigDecimal("0.0000000012"));
|
||||
qp.setUnits("m");
|
||||
|
||||
map.add(Observation.SP_VALUE_QUANTITY, qp);
|
||||
|
||||
IBundleProvider found = myObservationDao.search(map);
|
||||
List<String> ids = toUnqualifiedVersionlessIdValues(found);
|
||||
|
||||
List<IBaseResource> resources = found.getResources(0, found.size());
|
||||
|
||||
myCaptureQueriesListener.logInsertQueries();
|
||||
|
||||
// Original value should be in Quantity index, normalized should be in normalized table
|
||||
runInTransaction(()->{
|
||||
List<ResourceIndexedSearchParamQuantity> quantityIndexes = myResourceIndexedSearchParamQuantityDao.findAll().stream().filter(t->t.getParamName().equals("value-quantity")).collect(Collectors.toList());
|
||||
assertEquals(1, quantityIndexes.size());
|
||||
double d = quantityIndexes.get(0).getValue().doubleValue();
|
||||
assertEquals("1.2E-6", Double.toString(d));
|
||||
assertEquals("http://unitsofmeasure.org", quantityIndexes.get(0).getSystem());
|
||||
assertEquals("mm", quantityIndexes.get(0).getUnits());
|
||||
|
||||
List<ResourceIndexedSearchParamQuantityNormalized> normalizedQuantityIndexes = myResourceIndexedSearchParamQuantityNormalizedDao.findAll().stream().filter(t->t.getParamName().equals("value-quantity")).collect(Collectors.toList());
|
||||
assertEquals(1, normalizedQuantityIndexes.size());
|
||||
assertEquals("1.2E-9", Double.toString(normalizedQuantityIndexes.get(0).getValue()));
|
||||
assertEquals("http://unitsofmeasure.org", normalizedQuantityIndexes.get(0).getSystem());
|
||||
assertEquals("m", normalizedQuantityIndexes.get(0).getUnits());
|
||||
});
|
||||
|
||||
String searchSql;
|
||||
SearchParameterMap map;
|
||||
List<String> ids;
|
||||
|
||||
// Try with normalized value
|
||||
myCaptureQueriesListener.clear();
|
||||
map = SearchParameterMap.newSynchronous(Observation.SP_VALUE_QUANTITY, new QuantityParam()
|
||||
.setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL)
|
||||
.setValue(new BigDecimal("0.0000000012"))
|
||||
.setUnits("m")
|
||||
);
|
||||
ids = toUnqualifiedVersionlessIdValues(myObservationDao.search(map));
|
||||
searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true,true);
|
||||
assertThat(searchSql, containsString("HFJ_SPIDX_QUANTITY_NRML t0"));
|
||||
assertThat(searchSql, containsString("t0.SP_VALUE = '1.2E-9'"));
|
||||
assertEquals(1, ids.size());
|
||||
|
||||
// Try with non-normalized value
|
||||
myCaptureQueriesListener.clear();
|
||||
map = SearchParameterMap.newSynchronous(Observation.SP_VALUE_QUANTITY, new QuantityParam()
|
||||
.setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL)
|
||||
.setValue(new BigDecimal("0.0000012"))
|
||||
.setUnits("mm")
|
||||
);
|
||||
ids = toUnqualifiedVersionlessIdValues(myObservationDao.search(map));
|
||||
searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true,true);
|
||||
assertThat(searchSql, containsString("HFJ_SPIDX_QUANTITY_NRML t0"));
|
||||
assertThat(searchSql, containsString("t0.SP_VALUE = '1.2E-9'"));
|
||||
assertEquals(1, ids.size());
|
||||
|
||||
// Try with no units value
|
||||
myCaptureQueriesListener.clear();
|
||||
map = SearchParameterMap.newSynchronous(Observation.SP_VALUE_QUANTITY, new QuantityParam()
|
||||
.setValue(new BigDecimal("0.0000012"))
|
||||
);
|
||||
ids = toUnqualifiedVersionlessIdValues(myObservationDao.search(map));
|
||||
searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true,true);
|
||||
assertThat(searchSql, containsString("HFJ_SPIDX_QUANTITY t0"));
|
||||
assertThat(searchSql, containsString("t0.SP_VALUE = '0.0000012'"));
|
||||
assertEquals(1, ids.size());
|
||||
|
||||
ourLog.info("Observation2: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(resources.get(0)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithNormalizedQuantitySearchSupportedWithVerySmallNumber2() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
public void testCreateWithNormalizedQuantitySearchSupported_SmallerThanCanonicalUnit2() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
Observation obs = new Observation();
|
||||
obs.setStatus(Observation.ObservationStatus.FINAL);
|
||||
Quantity q = new Quantity();
|
||||
q.setValueElement(new DecimalType(149597.870691));
|
||||
q.setValueElement(new DecimalType("149597.870691"));
|
||||
q.setUnit("MM");
|
||||
q.setSystem("http://unitsofmeasure.org");
|
||||
q.setCode("mm");
|
||||
obs.setValue(q);
|
||||
|
||||
|
||||
ourLog.info("Observation1: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
|
||||
|
||||
assertTrue(myObservationDao.create(obs).getCreated());
|
||||
|
||||
|
||||
// Original value should be in Quantity index, normalized should be in normalized table
|
||||
runInTransaction(()->{
|
||||
List<ResourceIndexedSearchParamQuantity> quantityIndexes = myResourceIndexedSearchParamQuantityDao.findAll().stream().filter(t->t.getParamName().equals("value-quantity")).collect(Collectors.toList());
|
||||
assertEquals(1, quantityIndexes.size());
|
||||
assertEquals("149597.870691", Double.toString(quantityIndexes.get(0).getValue().doubleValue()));
|
||||
assertEquals("http://unitsofmeasure.org", quantityIndexes.get(0).getSystem());
|
||||
assertEquals("mm", quantityIndexes.get(0).getUnits());
|
||||
|
||||
List<ResourceIndexedSearchParamQuantityNormalized> normalizedQuantityIndexes = myResourceIndexedSearchParamQuantityNormalizedDao.findAll().stream().filter(t->t.getParamName().equals("value-quantity")).collect(Collectors.toList());
|
||||
assertEquals(1, normalizedQuantityIndexes.size());
|
||||
assertEquals("149.597870691", Double.toString(normalizedQuantityIndexes.get(0).getValue()));
|
||||
assertEquals("http://unitsofmeasure.org", normalizedQuantityIndexes.get(0).getSystem());
|
||||
assertEquals("m", normalizedQuantityIndexes.get(0).getUnits());
|
||||
});
|
||||
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.setLoadSynchronous(true);
|
||||
QuantityParam qp = new QuantityParam();
|
||||
qp.setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL);
|
||||
qp.setValue(new BigDecimal("149.597870691"));
|
||||
qp.setUnits("m");
|
||||
|
||||
|
||||
map.add(Observation.SP_VALUE_QUANTITY, qp);
|
||||
|
||||
|
||||
IBundleProvider found = myObservationDao.search(map);
|
||||
List<String> ids = toUnqualifiedVersionlessIdValues(found);
|
||||
|
||||
List<IBaseResource> resources = found.getResources(0, found.size());
|
||||
|
||||
|
||||
List<IBaseResource> resources = found.getResources(0, found.sizeOrThrowNpe());
|
||||
|
||||
assertEquals(1, ids.size());
|
||||
|
||||
|
||||
ourLog.info("Observation2: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(resources.get(0)));
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithNormalizedQuantitySearchSupportedWithLargeNumber() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
public void testCreateWithNormalizedQuantitySearchSupported_LargerThanCanonicalUnit() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
Observation obs = new Observation();
|
||||
obs.setStatus(Observation.ObservationStatus.FINAL);
|
||||
Quantity q = new Quantity();
|
||||
q.setValueElement(new DecimalType("95.7412345"));
|
||||
q.setUnit("kg/dL");
|
||||
q.setSystem("http://unitsofmeasure.org");
|
||||
q.setCode("kg/dL");
|
||||
obs.setValue(q);
|
||||
|
||||
ourLog.info("Observation1: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
|
||||
assertTrue(myObservationDao.create(obs).getCreated());
|
||||
|
||||
// Original value should be in Quantity index, normalized should be in normalized table
|
||||
runInTransaction(()->{
|
||||
List<ResourceIndexedSearchParamQuantity> quantityIndexes = myResourceIndexedSearchParamQuantityDao.findAll().stream().filter(t->t.getParamName().equals("value-quantity")).collect(Collectors.toList());
|
||||
assertEquals(1, quantityIndexes.size());
|
||||
assertEquals("95.7412345", Double.toString(quantityIndexes.get(0).getValue().doubleValue()));
|
||||
assertEquals("http://unitsofmeasure.org", quantityIndexes.get(0).getSystem());
|
||||
assertEquals("kg/dL", quantityIndexes.get(0).getUnits());
|
||||
|
||||
List<ResourceIndexedSearchParamQuantityNormalized> normalizedQuantityIndexes = myResourceIndexedSearchParamQuantityNormalizedDao.findAll().stream().filter(t->t.getParamName().equals("value-quantity")).collect(Collectors.toList());
|
||||
assertEquals(1, normalizedQuantityIndexes.size());
|
||||
assertEquals("9.57412345E8", Double.toString(normalizedQuantityIndexes.get(0).getValue()));
|
||||
assertEquals("http://unitsofmeasure.org", normalizedQuantityIndexes.get(0).getSystem());
|
||||
assertEquals("g.m-3", normalizedQuantityIndexes.get(0).getUnits());
|
||||
});
|
||||
|
||||
SearchParameterMap map = SearchParameterMap.newSynchronous(Observation.SP_VALUE_QUANTITY, new QuantityParam()
|
||||
.setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL)
|
||||
.setValue(new BigDecimal("957412345"))
|
||||
.setUnits("g.m-3")
|
||||
);
|
||||
assertEquals(1, toUnqualifiedVersionlessIdValues(myObservationDao.search(map)).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithNormalizedQuantitySearchSupported_NonCanonicalUnit() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
Observation obs = new Observation();
|
||||
obs.setStatus(Observation.ObservationStatus.FINAL);
|
||||
Quantity q = new Quantity();
|
||||
q.setValueElement(new DecimalType(95.7412345));
|
||||
q.setUnit("kg/dL");
|
||||
q.setSystem("http://unitsofmeasure.org");
|
||||
q.setSystem("http://example.com");
|
||||
q.setCode("kg/dL");
|
||||
obs.setValue(q);
|
||||
|
||||
|
||||
ourLog.info("Observation1: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
|
||||
|
||||
assertTrue(myObservationDao.create(obs).getCreated());
|
||||
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.setLoadSynchronous(true);
|
||||
QuantityParam qp = new QuantityParam();
|
||||
qp.setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL);
|
||||
qp.setValue(new BigDecimal("957412345"));
|
||||
qp.setUnits("g.m-3");
|
||||
|
||||
map.add(Observation.SP_VALUE_QUANTITY, qp);
|
||||
|
||||
IBundleProvider found = myObservationDao.search(map);
|
||||
List<String> ids = toUnqualifiedVersionlessIdValues(found);
|
||||
|
||||
List<IBaseResource> resources = found.getResources(0, found.size());
|
||||
|
||||
|
||||
// Original value should be in Quantity index, normalized should be in normalized table
|
||||
runInTransaction(() -> {
|
||||
List<ResourceIndexedSearchParamQuantity> quantityIndexes = myResourceIndexedSearchParamQuantityDao.findAll().stream().filter(t -> t.getParamName().equals("value-quantity")).collect(Collectors.toList());
|
||||
assertEquals(1, quantityIndexes.size());
|
||||
assertEquals("95.7412345", Double.toString(quantityIndexes.get(0).getValue().doubleValue()));
|
||||
assertEquals("http://example.com", quantityIndexes.get(0).getSystem());
|
||||
assertEquals("kg/dL", quantityIndexes.get(0).getUnits());
|
||||
|
||||
List<ResourceIndexedSearchParamQuantityNormalized> normalizedQuantityIndexes = myResourceIndexedSearchParamQuantityNormalizedDao.findAll().stream().filter(t -> t.getParamName().equals("value-quantity")).collect(Collectors.toList());
|
||||
assertEquals(0, normalizedQuantityIndexes.size());
|
||||
});
|
||||
|
||||
List<String> ids;
|
||||
|
||||
// Search should succeed using non-normalized table
|
||||
myCaptureQueriesListener.clear();
|
||||
SearchParameterMap map = SearchParameterMap.newSynchronous(Observation.SP_VALUE_QUANTITY, new QuantityParam()
|
||||
.setSystem("http://example.com")
|
||||
.setValue(95.7412345)
|
||||
.setUnits("kg/dL")
|
||||
);
|
||||
ids = toUnqualifiedVersionlessIdValues(myObservationDao.search(map));
|
||||
String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true,true);
|
||||
assertThat(searchSql, containsString("HFJ_SPIDX_QUANTITY t0"));
|
||||
assertThat(searchSql, containsString("t0.SP_VALUE = '95.7412345'"));
|
||||
assertEquals(1, ids.size());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateWithNormalizedQuantityStorageSupported_SmallerThanCanonicalUnit() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_STORAGE_SUPPORTED);
|
||||
Observation obs = new Observation();
|
||||
obs.setStatus(Observation.ObservationStatus.FINAL);
|
||||
Quantity q = new Quantity();
|
||||
q.setValueElement(new DecimalType(0.0000012));
|
||||
q.setUnit("MM");
|
||||
q.setSystem("http://unitsofmeasure.org");
|
||||
q.setCode("mm");
|
||||
obs.setValue(q);
|
||||
|
||||
ourLog.info("Observation1: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
|
||||
myCaptureQueriesListener.clear();
|
||||
assertTrue(myObservationDao.create(obs).getCreated());
|
||||
myCaptureQueriesListener.logInsertQueries();
|
||||
|
||||
// Original value should be in Quantity index, normalized should be in normalized table
|
||||
runInTransaction(()->{
|
||||
List<ResourceIndexedSearchParamQuantity> quantityIndexes = myResourceIndexedSearchParamQuantityDao.findAll().stream().filter(t->t.getParamName().equals("value-quantity")).collect(Collectors.toList());
|
||||
assertEquals(1, quantityIndexes.size());
|
||||
double d = quantityIndexes.get(0).getValue().doubleValue();
|
||||
assertEquals("1.2E-6", Double.toString(d));
|
||||
assertEquals("http://unitsofmeasure.org", quantityIndexes.get(0).getSystem());
|
||||
assertEquals("mm", quantityIndexes.get(0).getUnits());
|
||||
|
||||
List<ResourceIndexedSearchParamQuantityNormalized> normalizedQuantityIndexes = myResourceIndexedSearchParamQuantityNormalizedDao.findAll().stream().filter(t->t.getParamName().equals("value-quantity")).collect(Collectors.toList());
|
||||
assertEquals(1, normalizedQuantityIndexes.size());
|
||||
assertEquals("1.2E-9", Double.toString(normalizedQuantityIndexes.get(0).getValue()));
|
||||
assertEquals("http://unitsofmeasure.org", normalizedQuantityIndexes.get(0).getSystem());
|
||||
assertEquals("m", normalizedQuantityIndexes.get(0).getUnits());
|
||||
});
|
||||
|
||||
String searchSql;
|
||||
SearchParameterMap map;
|
||||
List<String> ids;
|
||||
|
||||
// Try with normalized value
|
||||
myCaptureQueriesListener.clear();
|
||||
map = SearchParameterMap.newSynchronous(Observation.SP_VALUE_QUANTITY, new QuantityParam()
|
||||
.setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL)
|
||||
.setValue(new BigDecimal("0.0000000012"))
|
||||
.setUnits("m")
|
||||
);
|
||||
ids = toUnqualifiedVersionlessIdValues(myObservationDao.search(map));
|
||||
searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true,true);
|
||||
assertThat(searchSql, containsString("HFJ_SPIDX_QUANTITY t0"));
|
||||
assertThat(searchSql, containsString("t0.SP_VALUE = '1.2E-9'"));
|
||||
assertEquals(0, ids.size());
|
||||
|
||||
// Try with non-normalized value
|
||||
myCaptureQueriesListener.clear();
|
||||
map = SearchParameterMap.newSynchronous(Observation.SP_VALUE_QUANTITY, new QuantityParam()
|
||||
.setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL)
|
||||
.setValue(new BigDecimal("0.0000012"))
|
||||
.setUnits("mm")
|
||||
);
|
||||
ids = toUnqualifiedVersionlessIdValues(myObservationDao.search(map));
|
||||
searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true,true);
|
||||
assertThat(searchSql, containsString("HFJ_SPIDX_QUANTITY t0"));
|
||||
assertThat(searchSql, containsString("t0.SP_VALUE = '0.0000012'"));
|
||||
assertEquals(1, ids.size());
|
||||
|
||||
// Try with no units value
|
||||
myCaptureQueriesListener.clear();
|
||||
map = SearchParameterMap.newSynchronous(Observation.SP_VALUE_QUANTITY, new QuantityParam()
|
||||
.setValue(new BigDecimal("0.0000012"))
|
||||
);
|
||||
ids = toUnqualifiedVersionlessIdValues(myObservationDao.search(map));
|
||||
searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true,true);
|
||||
assertThat(searchSql, containsString("HFJ_SPIDX_QUANTITY t0"));
|
||||
assertThat(searchSql, containsString("t0.SP_VALUE = '0.0000012'"));
|
||||
assertEquals(1, ids.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithNormalizedQuantitySearchNotSupported_SmallerThanCanonicalUnit() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED);
|
||||
Observation obs = new Observation();
|
||||
obs.setStatus(Observation.ObservationStatus.FINAL);
|
||||
Quantity q = new Quantity();
|
||||
q.setValueElement(new DecimalType(0.0000012));
|
||||
q.setUnit("MM");
|
||||
q.setSystem("http://unitsofmeasure.org");
|
||||
q.setCode("mm");
|
||||
obs.setValue(q);
|
||||
|
||||
ourLog.info("Observation1: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
|
||||
myCaptureQueriesListener.clear();
|
||||
assertTrue(myObservationDao.create(obs).getCreated());
|
||||
myCaptureQueriesListener.logInsertQueries();
|
||||
|
||||
// Original value should be in Quantity index, no normalized should be in normalized table
|
||||
runInTransaction(()->{
|
||||
List<ResourceIndexedSearchParamQuantity> quantityIndexes = myResourceIndexedSearchParamQuantityDao.findAll().stream().filter(t->t.getParamName().equals("value-quantity")).collect(Collectors.toList());
|
||||
assertEquals(1, quantityIndexes.size());
|
||||
double d = quantityIndexes.get(0).getValue().doubleValue();
|
||||
assertEquals("1.2E-6", Double.toString(d));
|
||||
assertEquals("http://unitsofmeasure.org", quantityIndexes.get(0).getSystem());
|
||||
assertEquals("mm", quantityIndexes.get(0).getUnits());
|
||||
|
||||
List<ResourceIndexedSearchParamQuantityNormalized> normalizedQuantityIndexes = myResourceIndexedSearchParamQuantityNormalizedDao.findAll().stream().filter(t->t.getParamName().equals("value-quantity")).collect(Collectors.toList());
|
||||
assertEquals(0, normalizedQuantityIndexes.size());
|
||||
});
|
||||
|
||||
String searchSql;
|
||||
SearchParameterMap map;
|
||||
List<String> ids;
|
||||
|
||||
// Try with normalized value
|
||||
myCaptureQueriesListener.clear();
|
||||
map = SearchParameterMap.newSynchronous(Observation.SP_VALUE_QUANTITY, new QuantityParam()
|
||||
.setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL)
|
||||
.setValue(new BigDecimal("0.0000000012"))
|
||||
.setUnits("m")
|
||||
);
|
||||
ids = toUnqualifiedVersionlessIdValues(myObservationDao.search(map));
|
||||
searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true,true);
|
||||
assertThat(searchSql, containsString("HFJ_SPIDX_QUANTITY t0"));
|
||||
assertThat(searchSql, containsString("t0.SP_VALUE = '1.2E-9'"));
|
||||
assertEquals(0, ids.size());
|
||||
|
||||
// Try with non-normalized value
|
||||
myCaptureQueriesListener.clear();
|
||||
map = SearchParameterMap.newSynchronous(Observation.SP_VALUE_QUANTITY, new QuantityParam()
|
||||
.setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL)
|
||||
.setValue(new BigDecimal("0.0000012"))
|
||||
.setUnits("mm")
|
||||
);
|
||||
ids = toUnqualifiedVersionlessIdValues(myObservationDao.search(map));
|
||||
searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true,true);
|
||||
assertThat(searchSql, containsString("HFJ_SPIDX_QUANTITY t0"));
|
||||
assertThat(searchSql, containsString("t0.SP_VALUE = '0.0000012'"));
|
||||
assertEquals(1, ids.size());
|
||||
|
||||
// Try with no units value
|
||||
myCaptureQueriesListener.clear();
|
||||
map = SearchParameterMap.newSynchronous(Observation.SP_VALUE_QUANTITY, new QuantityParam()
|
||||
.setValue(new BigDecimal("0.0000012"))
|
||||
);
|
||||
ids = toUnqualifiedVersionlessIdValues(myObservationDao.search(map));
|
||||
searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true,true);
|
||||
assertThat(searchSql, containsString("HFJ_SPIDX_QUANTITY t0"));
|
||||
assertThat(searchSql, containsString("t0.SP_VALUE = '0.0000012'"));
|
||||
assertEquals(1, ids.size());
|
||||
|
||||
ourLog.info("Observation2: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(resources.get(0)));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import ca.uhn.fhir.interceptor.api.IAnonymousInterceptor;
|
|||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
|
@ -86,8 +87,8 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
@AfterEach
|
||||
public void after() {
|
||||
myDaoConfig.setValidateSearchParameterExpressionsOnSave(new DaoConfig().isValidateSearchParameterExpressionsOnSave());
|
||||
myModelConfig.setNormalizedQuantitySearchNotSupported();
|
||||
}
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void beforeDisableResultReuse() {
|
||||
|
@ -117,8 +118,8 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
|
||||
@Test
|
||||
public void testStoreSearchParamWithBracketsInExpressionNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
myDaoConfig.setMarkResourcesForReindexingUponSearchParameterChange(true);
|
||||
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
|
@ -138,8 +139,8 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
|
||||
@Test
|
||||
public void testStoreSearchParamWithBracketsInExpressionNormalizedQuantityStorageSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantityStorageSupported();
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_STORAGE_SUPPORTED);
|
||||
myDaoConfig.setMarkResourcesForReindexingUponSearchParameterChange(true);
|
||||
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.DateParam;
|
||||
|
@ -10,7 +11,16 @@ import ca.uhn.fhir.rest.param.StringParam;
|
|||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.DateType;
|
||||
import org.hl7.fhir.r4.model.DecimalType;
|
||||
import org.hl7.fhir.r4.model.Location;
|
||||
import org.hl7.fhir.r4.model.MedicationRequest;
|
||||
import org.hl7.fhir.r4.model.Observation;
|
||||
import org.hl7.fhir.r4.model.Organization;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Quantity;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.r4.model.Task;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -21,8 +31,12 @@ import java.util.List;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsInRelativeOrder;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class FhirResourceDaoR4SearchMissingTest extends BaseJpaR4Test {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoR4SearchMissingTest.class);
|
||||
|
@ -31,10 +45,10 @@ public class FhirResourceDaoR4SearchMissingTest extends BaseJpaR4Test {
|
|||
public void beforeResetMissing() {
|
||||
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
|
||||
}
|
||||
|
||||
|
||||
@AfterEach
|
||||
public void afterResetSearch() {
|
||||
myModelConfig.setNormalizedQuantitySearchNotSupported();
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -80,9 +94,9 @@ public class FhirResourceDaoR4SearchMissingTest extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testIndexMissingFieldsDisabledDontCreateIndexesWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
|
||||
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.DISABLED);
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
Organization org = new Organization();
|
||||
org.setActive(true);
|
||||
myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
@ -94,12 +108,12 @@ public class FhirResourceDaoR4SearchMissingTest extends BaseJpaR4Test {
|
|||
assertThat(myResourceIndexedSearchParamQuantityDao.findAll(), empty());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIndexMissingFieldsDisabledDontCreateIndexesWithNormalizedQuantityStorageSupported() {
|
||||
|
||||
|
||||
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.DISABLED);
|
||||
myModelConfig.setNormalizedQuantityStorageSupported();
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_STORAGE_SUPPORTED);
|
||||
Organization org = new Organization();
|
||||
org.setActive(true);
|
||||
myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
@ -111,7 +125,7 @@ public class FhirResourceDaoR4SearchMissingTest extends BaseJpaR4Test {
|
|||
assertThat(myResourceIndexedSearchParamQuantityDao.findAll(), empty());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void testSearchResourceReferenceMissingChain() {
|
||||
|
@ -221,8 +235,8 @@ public class FhirResourceDaoR4SearchMissingTest extends BaseJpaR4Test {
|
|||
String locId = myLocationDao.create(new Location(), mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
String locId2 = myLocationDao.create(new Location().setPosition(new Location.LocationPositionComponent(new DecimalType(10), new DecimalType(10))), mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
runInTransaction(()->{
|
||||
ourLog.info("Coords:\n * {}", myResourceIndexedSearchParamCoordsDao.findAll().stream().map(t->t.toString()).collect(Collectors.joining("\n * ")));
|
||||
runInTransaction(() -> {
|
||||
ourLog.info("Coords:\n * {}", myResourceIndexedSearchParamCoordsDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * ")));
|
||||
});
|
||||
|
||||
{
|
||||
|
@ -309,8 +323,8 @@ public class FhirResourceDaoR4SearchMissingTest extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testSearchWithMissingQuantityWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
IIdType notMissing;
|
||||
IIdType missing;
|
||||
{
|
||||
|
@ -324,6 +338,12 @@ public class FhirResourceDaoR4SearchMissingTest extends BaseJpaR4Test {
|
|||
obs.setValue(new Quantity(123));
|
||||
notMissing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
runInTransaction(() -> {
|
||||
ourLog.info("Quantity Indexes:\n * {}", myResourceIndexedSearchParamQuantityDao.findAll().stream().filter(t -> t.getParamName().equals("value-quantity")).map(t -> t.toString()).collect(Collectors.joining("\n * ")));
|
||||
ourLog.info("Normalized Quantity Indexes:\n * {}", myResourceIndexedSearchParamQuantityNormalizedDao.findAll().stream().filter(t -> t.getParamName().equals("value-quantity")).map(t -> t.toString()).collect(Collectors.joining("\n * ")));
|
||||
});
|
||||
|
||||
// Quantity Param
|
||||
{
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
|
@ -341,17 +361,19 @@ public class FhirResourceDaoR4SearchMissingTest extends BaseJpaR4Test {
|
|||
QuantityParam param = new QuantityParam();
|
||||
param.setMissing(true);
|
||||
params.add(Observation.SP_VALUE_QUANTITY, param);
|
||||
myCaptureQueriesListener.clear();
|
||||
List<IIdType> patients = toUnqualifiedVersionlessIds(myObservationDao.search(params));
|
||||
myCaptureQueriesListener.logSelectQueries();
|
||||
assertThat(patients, containsInRelativeOrder(missing));
|
||||
assertThat(patients, not(containsInRelativeOrder(notMissing)));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchWithMissingQuantityWithNormalizedQuantityStorageSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantityStorageSupported();
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_STORAGE_SUPPORTED);
|
||||
IIdType notMissing;
|
||||
IIdType missing;
|
||||
{
|
||||
|
@ -386,10 +408,10 @@ public class FhirResourceDaoR4SearchMissingTest extends BaseJpaR4Test {
|
|||
assertThat(patients, containsInRelativeOrder(missing));
|
||||
assertThat(patients, not(containsInRelativeOrder(notMissing)));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchWithMissingReference() {
|
||||
IIdType orgId = myOrganizationDao.create(new Organization(), mySrd).getId().toUnqualifiedVersionless();
|
||||
|
|
|
@ -34,6 +34,7 @@ import java.util.stream.Collectors;
|
|||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
|
@ -185,8 +186,8 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
myDaoConfig.setAllowContainsSearches(new DaoConfig().isAllowContainsSearches());
|
||||
myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds());
|
||||
myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields());
|
||||
myModelConfig.setNormalizedQuantitySearchNotSupported();
|
||||
}
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void beforeDisableCacheReuse() {
|
||||
|
@ -1236,8 +1237,8 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testIndexNoDuplicatesQuantityWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
Substance res = new Substance();
|
||||
res.addInstance().getQuantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("m").setValue(123);
|
||||
res.addInstance().getQuantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("m").setValue(123);
|
||||
|
@ -1246,20 +1247,6 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
IIdType id = mySubstanceDao.create(res, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
runInTransaction(() -> {
|
||||
Class<ResourceIndexedSearchParamQuantity> type = ResourceIndexedSearchParamQuantity.class;
|
||||
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
|
||||
ourLog.info(toStringMultiline(results));
|
||||
assertEquals(2, results.size());
|
||||
});
|
||||
|
||||
runInTransaction(() -> {
|
||||
Class<ResourceIndexedSearchParamQuantityNormalized> type = ResourceIndexedSearchParamQuantityNormalized.class;
|
||||
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
|
||||
ourLog.info(toStringMultiline(results));
|
||||
assertEquals(2, results.size());
|
||||
});
|
||||
|
||||
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
||||
mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 12300, UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm"))));
|
||||
assertThat(actual, contains(id));
|
||||
|
@ -1268,26 +1255,12 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testQuantityWithNormalizedQuantitySearchSupported_InvalidUCUMCode() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
Substance res = new Substance();
|
||||
res.addInstance().getQuantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("FOO").setValue(123);
|
||||
|
||||
IIdType id = mySubstanceDao.create(res, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
runInTransaction(() -> {
|
||||
Class<ResourceIndexedSearchParamQuantity> type = ResourceIndexedSearchParamQuantity.class;
|
||||
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
|
||||
ourLog.info(toStringMultiline(results));
|
||||
assertEquals(1, results.size());
|
||||
});
|
||||
|
||||
runInTransaction(() -> {
|
||||
Class<ResourceIndexedSearchParamQuantityNormalized> type = ResourceIndexedSearchParamQuantityNormalized.class;
|
||||
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
|
||||
ourLog.info(toStringMultiline(results));
|
||||
assertEquals(1, results.size());
|
||||
});
|
||||
|
||||
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
||||
mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 123, UcumServiceUtil.UCUM_CODESYSTEM_URL, "FOO"))));
|
||||
|
@ -1297,27 +1270,13 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testQuantityWithNormalizedQuantitySearchSupported_NotUCUM() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
Substance res = new Substance();
|
||||
res.addInstance().getQuantity().setSystem("http://bar").setCode("FOO").setValue(123);
|
||||
|
||||
IIdType id = mySubstanceDao.create(res, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
runInTransaction(() -> {
|
||||
Class<ResourceIndexedSearchParamQuantity> type = ResourceIndexedSearchParamQuantity.class;
|
||||
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
|
||||
ourLog.info(toStringMultiline(results));
|
||||
assertEquals(1, results.size());
|
||||
});
|
||||
|
||||
runInTransaction(() -> {
|
||||
Class<ResourceIndexedSearchParamQuantityNormalized> type = ResourceIndexedSearchParamQuantityNormalized.class;
|
||||
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
|
||||
ourLog.info(toStringMultiline(results));
|
||||
assertEquals(1, results.size());
|
||||
});
|
||||
|
||||
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
||||
mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 123, "http://bar", "FOO"))));
|
||||
assertThat(actual, contains(id));
|
||||
|
@ -1326,8 +1285,8 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testIndexNoDuplicatesQuantityWithNormalizedQuantityStorageSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantityStorageSupported();
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_STORAGE_SUPPORTED);
|
||||
Substance res = new Substance();
|
||||
res.addInstance().getQuantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("m").setValue(123);
|
||||
res.addInstance().getQuantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("m").setValue(123);
|
||||
|
@ -1336,20 +1295,6 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
IIdType id = mySubstanceDao.create(res, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
runInTransaction(() -> {
|
||||
Class<ResourceIndexedSearchParamQuantity> type = ResourceIndexedSearchParamQuantity.class;
|
||||
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
|
||||
ourLog.info(toStringMultiline(results));
|
||||
assertEquals(2, results.size());
|
||||
});
|
||||
|
||||
runInTransaction(() -> {
|
||||
Class<ResourceIndexedSearchParamQuantityNormalized> type = ResourceIndexedSearchParamQuantityNormalized.class;
|
||||
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
|
||||
ourLog.info(toStringMultiline(results));
|
||||
assertEquals(2, results.size());
|
||||
});
|
||||
|
||||
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
||||
mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 123, UcumServiceUtil.UCUM_CODESYSTEM_URL, "m"))));
|
||||
assertThat(actual, contains(id));
|
||||
|
@ -2753,8 +2698,8 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testSearchByMoneyParamWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
ChargeItem ci = new ChargeItem();
|
||||
ci.getPriceOverride().setValue(123).setCurrency("$");
|
||||
|
||||
|
@ -3119,8 +3064,8 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testSearchQuantityWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
Condition c1 = new Condition();
|
||||
c1.setAbatement(new Range().setLow(new SimpleQuantity().setValue(1L)).setHigh(new SimpleQuantity().setValue(1L)));
|
||||
String id1 = myConditionDao.create(c1).getId().toUnqualifiedVersionless().getValue();
|
||||
|
|
|
@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.dao.r4;
|
|||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
|
||||
|
@ -143,8 +144,8 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
|||
myDaoConfig.setFetchSizeDefaultMaximum(new DaoConfig().getFetchSizeDefaultMaximum());
|
||||
myDaoConfig.setAllowContainsSearches(new DaoConfig().isAllowContainsSearches());
|
||||
myDaoConfig.setDisableHashBasedSearches(false);
|
||||
myModelConfig.setNormalizedQuantitySearchNotSupported();
|
||||
}
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void beforeInitialize() {
|
||||
|
@ -1193,8 +1194,8 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testComponentQuantityWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
Observation o1 = new Observation();
|
||||
o1.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm")))
|
||||
|
@ -1216,8 +1217,8 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testComponentQuantityWithNormalizedQuantityStorageSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantityStorageSupported();
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_STORAGE_SUPPORTED);
|
||||
Observation o1 = new Observation();
|
||||
o1.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm")))
|
||||
|
@ -1292,8 +1293,8 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testSearchCompositeParamQuantityWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
Observation o1 = new Observation();
|
||||
o1.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("code1")))
|
||||
|
|
|
@ -7,6 +7,7 @@ import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
|||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.JpaResourceDao;
|
||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceEncodingEnum;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
|
@ -161,8 +162,8 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
|||
myDaoConfig.setEnforceReferentialIntegrityOnDelete(new DaoConfig().isEnforceReferentialIntegrityOnDelete());
|
||||
myDaoConfig.setEnforceReferenceTargetTypes(new DaoConfig().isEnforceReferenceTargetTypes());
|
||||
myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields());
|
||||
myModelConfig.setNormalizedQuantitySearchNotSupported();
|
||||
}
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
|
@ -581,8 +582,8 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testChoiceParamQuantityWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
Observation o3 = new Observation();
|
||||
o3.getCode().addCoding().setSystem("foo").setCode("testChoiceParam03");
|
||||
o3.setValue(new Quantity(QuantityComparator.GREATER_THAN, 123.0, UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm", "cm")); // 0.0123m
|
||||
|
@ -682,8 +683,8 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testChoiceParamQuantityPrecisionWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
Observation o3 = new Observation();
|
||||
o3.getCode().addCoding().setSystem("foo").setCode("testChoiceParam03");
|
||||
o3.setValue(new Quantity(null, 123.01, UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm", "cm")); // 0.012301 m
|
||||
|
@ -3500,9 +3501,10 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testSortByQuantityWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
@Disabled
|
||||
public void testSortByQuantityWithNormalizedQuantitySearchFullSupported() {
|
||||
|
||||
// myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_FULL_SUPPORTED);
|
||||
Observation res;
|
||||
|
||||
res = new Observation();
|
||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.dao.r4;
|
|||
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
||||
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceEncodingEnum;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
|
@ -23,7 +24,6 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
|||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
|
@ -61,7 +61,6 @@ import org.hl7.fhir.r4.model.Reference;
|
|||
import org.hl7.fhir.r4.model.Resource;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
|
@ -110,8 +109,8 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest {
|
|||
public void after() {
|
||||
myDaoConfig.setAllowInlineMatchUrlReferences(false);
|
||||
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
|
||||
myModelConfig.setNormalizedQuantitySearchNotSupported();
|
||||
}
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void beforeDisableResultReuse() {
|
||||
|
@ -3131,7 +3130,7 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest {
|
|||
@Test
|
||||
public void testTransactionWithConditionalUpdateDoesntUpdateIfNoChangeWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier()
|
||||
.setSystem("http://acme.org")
|
||||
|
|
|
@ -1,20 +1,29 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static java.util.Comparator.comparing;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
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 org.hl7.fhir.dstu2.model.SimpleQuantity;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
|
||||
import ca.uhn.fhir.jpa.cache.ResourceChangeResult;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantityNormalized;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.ISearchParamExtractor;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.PathAndRef;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorR4;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ReadOnlySearchParamCache;
|
||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||
import ca.uhn.fhir.util.HapiExtensions;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.hl7.fhir.r4.model.BooleanType;
|
||||
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||
import org.hl7.fhir.r4.model.Coding;
|
||||
|
@ -24,47 +33,30 @@ import org.hl7.fhir.r4.model.Extension;
|
|||
import org.hl7.fhir.r4.model.Observation;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Quantity;
|
||||
import org.hl7.fhir.r4.model.Range;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.r4.model.SearchParameter;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
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 ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
|
||||
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.jpa.cache.ResourceChangeResult;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantityNormalized;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.ISearchParamExtractor;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.PathAndRef;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorR4;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ReadOnlySearchParamCache;
|
||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||
import ca.uhn.fhir.util.HapiExtensions;
|
||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||
import static java.util.Comparator.comparing;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
public class SearchParamExtractorR4Test {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(SearchParamExtractorR4Test.class);
|
||||
private static FhirContext ourCtx = FhirContext.forCached(FhirVersionEnum.R4);
|
||||
private static IValidationSupport ourValidationSupport;
|
||||
private MySearchParamRegistry mySearchParamRegistry;
|
||||
private PartitionSettings myPartitionSettings;
|
||||
|
||||
|
@ -81,7 +73,7 @@ public class SearchParamExtractorR4Test {
|
|||
Observation obs = new Observation();
|
||||
obs.addCategory().addCoding().setSystem("SYSTEM").setCode("CODE");
|
||||
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), new PartitionSettings(), ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), new PartitionSettings(), ourCtx, mySearchParamRegistry);
|
||||
Set<BaseResourceIndexedSearchParam> tokens = extractor.extractSearchParamTokens(obs);
|
||||
assertEquals(1, tokens.size());
|
||||
ResourceIndexedSearchParamToken token = (ResourceIndexedSearchParamToken) tokens.iterator().next();
|
||||
|
@ -95,7 +87,7 @@ public class SearchParamExtractorR4Test {
|
|||
SearchParameter sp = new SearchParameter();
|
||||
sp.addUseContext().setCode(new Coding().setSystem("http://system").setCode("code"));
|
||||
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), new PartitionSettings(), ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), new PartitionSettings(), ourCtx, mySearchParamRegistry);
|
||||
Set<BaseResourceIndexedSearchParam> tokens = extractor.extractSearchParamTokens(sp);
|
||||
assertEquals(1, tokens.size());
|
||||
ResourceIndexedSearchParamToken token = (ResourceIndexedSearchParamToken) tokens.iterator().next();
|
||||
|
@ -109,7 +101,7 @@ public class SearchParamExtractorR4Test {
|
|||
Observation obs = new Observation();
|
||||
obs.getCode().addCoding().setSystem("http://system").setCode("code").setDisplay("Help Im a Bug");
|
||||
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), myPartitionSettings, ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), myPartitionSettings, ourCtx, mySearchParamRegistry);
|
||||
|
||||
List<BaseResourceIndexedSearchParam> tokens = extractor.extractSearchParamTokens(obs)
|
||||
.stream()
|
||||
|
@ -138,7 +130,7 @@ public class SearchParamExtractorR4Test {
|
|||
Observation obs = new Observation();
|
||||
obs.getCode().addCoding().setSystem("http://system").setCode("code").setDisplay("Help Im a Bug");
|
||||
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), myPartitionSettings, ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), myPartitionSettings, ourCtx, mySearchParamRegistry);
|
||||
|
||||
List<BaseResourceIndexedSearchParam> tokens = extractor.extractSearchParamTokens(obs)
|
||||
.stream()
|
||||
|
@ -162,7 +154,7 @@ public class SearchParamExtractorR4Test {
|
|||
Observation obs = new Observation();
|
||||
obs.getCode().addCoding().setSystem("http://system").setCode("code").setDisplay("Help Im a Bug");
|
||||
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(modelConfig, myPartitionSettings, ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(modelConfig, myPartitionSettings, ourCtx, mySearchParamRegistry);
|
||||
|
||||
List<BaseResourceIndexedSearchParam> tokens = extractor.extractSearchParamTokens(obs)
|
||||
.stream()
|
||||
|
@ -191,7 +183,7 @@ public class SearchParamExtractorR4Test {
|
|||
Observation obs = new Observation();
|
||||
obs.getCode().addCoding().setSystem("http://system").setCode("code").setDisplay("Help Im a Bug");
|
||||
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(modelConfig, myPartitionSettings, ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(modelConfig, myPartitionSettings, ourCtx, mySearchParamRegistry);
|
||||
|
||||
List<BaseResourceIndexedSearchParam> tokens = extractor.extractSearchParamTokens(obs)
|
||||
.stream()
|
||||
|
@ -216,7 +208,7 @@ public class SearchParamExtractorR4Test {
|
|||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("sys").setValue("val").getType().setText("Help Im a Bug");
|
||||
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), myPartitionSettings, ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), myPartitionSettings, ourCtx, mySearchParamRegistry);
|
||||
|
||||
List<BaseResourceIndexedSearchParam> tokens = extractor.extractSearchParamTokens(obs)
|
||||
.stream()
|
||||
|
@ -246,7 +238,7 @@ public class SearchParamExtractorR4Test {
|
|||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("sys").setValue("val").getType().setText("Help Im a Bug");
|
||||
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), myPartitionSettings, ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), myPartitionSettings, ourCtx, mySearchParamRegistry);
|
||||
|
||||
List<BaseResourceIndexedSearchParam> tokens = extractor.extractSearchParamTokens(obs)
|
||||
.stream()
|
||||
|
@ -267,7 +259,7 @@ public class SearchParamExtractorR4Test {
|
|||
Encounter enc = new Encounter();
|
||||
enc.addLocation().setLocation(new Reference("Location/123"));
|
||||
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), new PartitionSettings(), ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), new PartitionSettings(), ourCtx, mySearchParamRegistry);
|
||||
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam("Encounter", "location");
|
||||
assertNotNull(param);
|
||||
ISearchParamExtractor.SearchParamSet<PathAndRef> links = extractor.extractResourceLinks(enc);
|
||||
|
@ -282,7 +274,7 @@ public class SearchParamExtractorR4Test {
|
|||
Consent consent = new Consent();
|
||||
consent.setSource(new Reference().setReference("Consent/999"));
|
||||
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), new PartitionSettings(), ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), new PartitionSettings(), ourCtx, mySearchParamRegistry);
|
||||
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam("Consent", Consent.SP_SOURCE_REFERENCE);
|
||||
assertNotNull(param);
|
||||
ISearchParamExtractor.SearchParamSet<PathAndRef> links = extractor.extractResourceLinks(consent);
|
||||
|
@ -297,7 +289,7 @@ public class SearchParamExtractorR4Test {
|
|||
Patient p = new Patient();
|
||||
p.addIdentifier().setSystem("sys").setValue("val");
|
||||
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), new PartitionSettings(), ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), new PartitionSettings(), ourCtx, mySearchParamRegistry);
|
||||
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam("Patient", Patient.SP_IDENTIFIER);
|
||||
assertNotNull(param);
|
||||
ISearchParamExtractor.SearchParamSet<BaseResourceIndexedSearchParam> params = extractor.extractSearchParamTokens(p, param);
|
||||
|
@ -319,7 +311,7 @@ public class SearchParamExtractorR4Test {
|
|||
Patient patient = new Patient();
|
||||
patient.addExtension("http://patext", new Reference("Organization/AAA"));
|
||||
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), new PartitionSettings(), ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), new PartitionSettings(), ourCtx, mySearchParamRegistry);
|
||||
ISearchParamExtractor.SearchParamSet<PathAndRef> links = extractor.extractResourceLinks(patient);
|
||||
assertEquals(1, links.size());
|
||||
|
||||
|
@ -335,7 +327,7 @@ public class SearchParamExtractorR4Test {
|
|||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("code2")))
|
||||
.setValue(new Quantity().setSystem("http://bar").setCode("code2").setValue(200));
|
||||
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), new PartitionSettings(), ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), new PartitionSettings(), ourCtx, mySearchParamRegistry);
|
||||
Set<ResourceIndexedSearchParamQuantity> links = extractor.extractSearchParamQuantity(o1);
|
||||
ourLog.info("Links:\n {}", links.stream().map(t -> t.toString()).collect(Collectors.joining("\n ")));
|
||||
assertEquals(4, links.size());
|
||||
|
@ -343,44 +335,44 @@ public class SearchParamExtractorR4Test {
|
|||
|
||||
@Test
|
||||
public void testExtractComponentQuantityWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
|
||||
ModelConfig modelConfig = new ModelConfig();
|
||||
|
||||
modelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
|
||||
modelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
|
||||
Observation o1 = new Observation();
|
||||
o1.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("code1")))
|
||||
.setValue(new Quantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm").setValue(200));
|
||||
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(modelConfig, new PartitionSettings(), ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(modelConfig, new PartitionSettings(), ourCtx, mySearchParamRegistry);
|
||||
Set<ResourceIndexedSearchParamQuantityNormalized> links = extractor.extractSearchParamQuantityNormalized(o1);
|
||||
ourLog.info("Links:\n {}", links.stream().map(t -> t.toString()).collect(Collectors.joining("\n ")));
|
||||
assertEquals(2, links.size());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testExtractComponentQuantityValueWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
|
||||
ModelConfig modelConfig = new ModelConfig();
|
||||
|
||||
modelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
|
||||
modelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
|
||||
Observation o1 = new Observation();
|
||||
|
||||
|
||||
o1.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("code1")))
|
||||
.setValue(new Quantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm").setValue(200));
|
||||
|
||||
RuntimeSearchParam existingCodeSp = mySearchParamRegistry.getActiveSearchParams("Observation").get("component-value-quantity");
|
||||
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(modelConfig, new PartitionSettings(), ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(modelConfig, new PartitionSettings(), ourCtx, mySearchParamRegistry);
|
||||
List<String> list = extractor.extractParamValuesAsStrings(existingCodeSp, o1);
|
||||
|
||||
assertEquals(1, list.size());
|
||||
|
||||
assertEquals(2, list.size());
|
||||
}
|
||||
|
||||
|
||||
private static class MySearchParamRegistry implements ISearchParamRegistry {
|
||||
|
||||
|
||||
|
@ -457,9 +449,4 @@ public class SearchParamExtractorR4Test {
|
|||
}
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
ourValidationSupport = new DefaultProfileValidationSupport(ourCtx);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
package ca.uhn.fhir.jpa.interceptor.validation;
|
||||
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.jpa.config.BaseConfig;
|
||||
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
|
||||
import ca.uhn.fhir.jpa.rp.r4.ObservationResourceProvider;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.PreferReturnEnum;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ValidationResultEnrichingInterceptor;
|
||||
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
|
||||
import org.hl7.fhir.r4.model.Observation;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
public class RepositoryValidatingInterceptorHttpR4Test extends BaseJpaR4Test {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(RepositoryValidatingInterceptorHttpR4Test.class);
|
||||
@Autowired
|
||||
protected ObservationResourceProvider myObservationResourceProvider;
|
||||
private RepositoryValidatingInterceptor myValInterceptor;
|
||||
@RegisterExtension
|
||||
protected RestfulServerExtension myRestfulServerExtension = new RestfulServerExtension(FhirVersionEnum.R4);
|
||||
@Autowired
|
||||
private ApplicationContext myApplicationContext;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
myValInterceptor = new RepositoryValidatingInterceptor();
|
||||
myValInterceptor.setFhirContext(myFhirCtx);
|
||||
myInterceptorRegistry.registerInterceptor(myValInterceptor);
|
||||
|
||||
myRestfulServerExtension.getRestfulServer().registerProvider(myObservationResourceProvider);
|
||||
myRestfulServerExtension.getRestfulServer().getInterceptorService().registerInterceptor(new ValidationResultEnrichingInterceptor());
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void after() {
|
||||
myInterceptorRegistry.unregisterInterceptorsIf(t -> t instanceof RepositoryValidatingInterceptor);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidationOutcomeAddedToRequestResponse() {
|
||||
List<IRepositoryValidatingRule> rules = newRuleBuilder()
|
||||
.forResourcesOfType("Observation")
|
||||
.requireValidationToDeclaredProfiles()
|
||||
.withBestPracticeWarningLevel("WARNING")
|
||||
.build();
|
||||
myValInterceptor.setRules(rules);
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.getCode().addCoding().setSystem("http://foo").setCode("123").setDisplay("help im a bug");
|
||||
obs.setStatus(Observation.ObservationStatus.AMENDED);
|
||||
|
||||
MethodOutcome outcome = myRestfulServerExtension
|
||||
.getFhirClient()
|
||||
.create()
|
||||
.resource(obs)
|
||||
.prefer(PreferReturnEnum.OPERATION_OUTCOME)
|
||||
.execute();
|
||||
|
||||
String operationOutcomeEncoded = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getOperationOutcome());
|
||||
ourLog.info("Outcome: {}", operationOutcomeEncoded);
|
||||
assertThat(operationOutcomeEncoded, containsString("All observations should have a subject"));
|
||||
|
||||
}
|
||||
|
||||
private RepositoryValidatingRuleBuilder newRuleBuilder() {
|
||||
return myApplicationContext.getBean(BaseConfig.REPOSITORY_VALIDATING_RULE_BUILDER, RepositoryValidatingRuleBuilder.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -15,7 +15,6 @@ import org.hl7.fhir.r4.model.OperationOutcome;
|
|||
import org.hl7.fhir.r4.model.Parameters;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.hl7.fhir.r4.model.UrlType;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -44,6 +43,7 @@ public class RepositoryValidatingInterceptorR4Test extends BaseJpaR4Test {
|
|||
myValInterceptor = new RepositoryValidatingInterceptor();
|
||||
myValInterceptor.setFhirContext(myFhirCtx);
|
||||
myInterceptorRegistry.registerInterceptor(myValInterceptor);
|
||||
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
@ -264,13 +264,40 @@ public class RepositoryValidatingInterceptorR4Test extends BaseJpaR4Test {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequireValidation_AdditionalOptions() {
|
||||
List<IRepositoryValidatingRule> rules = newRuleBuilder()
|
||||
.forResourcesOfType("Observation")
|
||||
.requireValidationToDeclaredProfiles()
|
||||
.withBestPracticeWarningLevel("IGNORE")
|
||||
.allowAnyExtensions()
|
||||
.disableTerminologyChecks()
|
||||
.errorOnUnknownProfiles()
|
||||
.suppressNoBindingMessage()
|
||||
.suppressWarningForExtensibleValueSetValidation()
|
||||
.build();
|
||||
|
||||
myValInterceptor.setRules(rules);
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.getCode().addCoding().setSystem("http://foo").setCode("123").setDisplay("help im a bug");
|
||||
obs.setStatus(Observation.ObservationStatus.AMENDED);
|
||||
try {
|
||||
IIdType id = myObservationDao.create(obs).getId();
|
||||
assertEquals("1", id.getVersionIdPart());
|
||||
} catch (PreconditionFailedException e) {
|
||||
// should not happen
|
||||
fail(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequireValidation_FailNoRejectAndTag() {
|
||||
List<IRepositoryValidatingRule> rules = newRuleBuilder()
|
||||
.forResourcesOfType("Observation")
|
||||
.requireValidationToDeclaredProfiles()
|
||||
.withBestPracticeWarningLevel("IGNORE")
|
||||
.dontReject()
|
||||
.neverReject()
|
||||
.tagOnSeverity(ResultSeverityEnum.ERROR, "http://foo", "validation-error")
|
||||
.build();
|
||||
myValInterceptor.setRules(rules);
|
||||
|
|
|
@ -35,6 +35,7 @@ import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
|||
import ca.uhn.fhir.util.HapiExtensions;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
@ -65,6 +66,7 @@ import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
|
|||
import org.hl7.fhir.dstu3.model.Bundle.SearchEntryMode;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||
import org.hl7.fhir.dstu3.model.CodeType;
|
||||
import org.hl7.fhir.dstu3.model.CodeableConcept;
|
||||
import org.hl7.fhir.dstu3.model.Coding;
|
||||
import org.hl7.fhir.dstu3.model.Condition;
|
||||
import org.hl7.fhir.dstu3.model.DateTimeType;
|
||||
|
@ -79,6 +81,7 @@ import org.hl7.fhir.dstu3.model.Enumerations;
|
|||
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
|
||||
import org.hl7.fhir.dstu3.model.Extension;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.dstu3.model.Identifier;
|
||||
import org.hl7.fhir.dstu3.model.ImagingStudy;
|
||||
import org.hl7.fhir.dstu3.model.InstantType;
|
||||
import org.hl7.fhir.dstu3.model.IntegerType;
|
||||
|
@ -110,8 +113,10 @@ import org.hl7.fhir.dstu3.model.StructureDefinition;
|
|||
import org.hl7.fhir.dstu3.model.Subscription;
|
||||
import org.hl7.fhir.dstu3.model.Subscription.SubscriptionChannelType;
|
||||
import org.hl7.fhir.dstu3.model.Subscription.SubscriptionStatus;
|
||||
import org.hl7.fhir.dstu3.model.Task;
|
||||
import org.hl7.fhir.dstu3.model.UnsignedIntType;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||
import org.hl7.fhir.dstu3.model.codesystems.DeviceStatus;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
@ -235,6 +240,56 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
|||
assertEquals(0, returnedBundle.getEntry().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuppressNoExtensibleWarnings() {
|
||||
RequestValidatingInterceptor interceptor = new RequestValidatingInterceptor();
|
||||
interceptor.setFailOnSeverity(ResultSeverityEnum.INFORMATION);
|
||||
FhirInstanceValidator val = new FhirInstanceValidator(myValidationSupport);
|
||||
val.setNoExtensibleWarnings(true);
|
||||
interceptor.addValidatorModule(val);
|
||||
|
||||
ourRestServer.registerInterceptor(interceptor);
|
||||
try {
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
Coding codingCode = codeableConcept.addCoding();
|
||||
codingCode.setCode(DeviceStatus.ACTIVE.toCode());
|
||||
codingCode.setSystem(DeviceStatus.ACTIVE.getSystem());
|
||||
|
||||
Device device = new Device();
|
||||
Identifier identifier = device.addIdentifier();
|
||||
identifier.setType(codeableConcept); // Not valid against valueset with 'Extensible' binding strength
|
||||
ourClient.create().resource(device).execute().getId();
|
||||
} finally {
|
||||
ourRestServer.unregisterInterceptor(interceptor);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuppressNoBindingMessage() {
|
||||
RequestValidatingInterceptor interceptor = new RequestValidatingInterceptor();
|
||||
interceptor.setFailOnSeverity(ResultSeverityEnum.INFORMATION);
|
||||
FhirInstanceValidator val = new FhirInstanceValidator(myValidationSupport);
|
||||
val.setNoBindingMsgSuppressed(true);
|
||||
interceptor.addValidatorModule(val);
|
||||
|
||||
ourRestServer.registerInterceptor(interceptor);
|
||||
try {
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
Coding codingCode = codeableConcept.addCoding();
|
||||
codingCode.setSystem(DeviceStatus.ACTIVE.toCode());
|
||||
codingCode.setSystem(DeviceStatus.ACTIVE.getSystem());
|
||||
|
||||
Task task = new Task();
|
||||
task.setStatus(Task.TaskStatus.DRAFT);
|
||||
task.setIntent(Task.TaskIntent.FILLERORDER);
|
||||
task.setCode(codeableConcept); // Task.code has no source/binding
|
||||
|
||||
ourClient.create().resource(task).execute().getId();
|
||||
} finally {
|
||||
ourRestServer.unregisterInterceptor(interceptor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See #872
|
||||
*/
|
||||
|
|
|
@ -5,6 +5,7 @@ import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
|||
import ca.uhn.fhir.jpa.api.model.ExpungeOptions;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
|
||||
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||
import ca.uhn.fhir.jpa.search.PersistedJpaSearchFirstPageBundleProvider;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
|
@ -62,8 +63,8 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
|
|||
@AfterEach
|
||||
public void afterDisableExpunge() {
|
||||
myDaoConfig.setExpungeEnabled(new DaoConfig().isExpungeEnabled());
|
||||
myModelConfig.setNormalizedQuantitySearchNotSupported();
|
||||
}
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void beforeEnableExpunge() {
|
||||
|
@ -402,7 +403,7 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
|
|||
|
||||
@Test
|
||||
public void testExpungeSystemEverythingWithNormalizedQuantitySearchSupported() {
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
createStandardPatients();
|
||||
|
||||
mySystemDao.expunge(new ExpungeOptions()
|
||||
|
@ -424,7 +425,7 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
|
|||
|
||||
@Test
|
||||
public void testExpungeSystemEverythingWithNormalizedQuantityStorageSupported() {
|
||||
myModelConfig.setNormalizedQuantityStorageSupported();
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_STORAGE_SUPPORTED);
|
||||
createStandardPatients();
|
||||
|
||||
mySystemDao.expunge(new ExpungeOptions()
|
||||
|
|
|
@ -47,6 +47,7 @@ import java.util.Set;
|
|||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
@ -217,9 +218,9 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
mySearchCoordinatorSvcRaw.setSyncSizeForUnitTests(SearchCoordinatorSvcImpl.DEFAULT_SYNC_SIZE);
|
||||
mySearchCoordinatorSvcRaw.setNeverUseLocalSearchForUnitTests(false);
|
||||
mySearchCoordinatorSvcRaw.cancelAllActiveSearches();
|
||||
myDaoConfig.getModelConfig().setNormalizedQuantitySearchNotSupported();
|
||||
myDaoConfig.getModelConfig().setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED);
|
||||
|
||||
myClient.unregisterInterceptor(myCapturingInterceptor);
|
||||
myClient.unregisterInterceptor(myCapturingInterceptor);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
|
@ -4085,8 +4086,8 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
|
||||
@Test
|
||||
public void testSearchWithNormalizedQuantitySearchSupported() throws Exception {
|
||||
|
||||
myDaoConfig.getModelConfig().setNormalizedQuantitySearchSupported();
|
||||
|
||||
myDaoConfig.getModelConfig().setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
IIdType pid0;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
|
@ -4167,8 +4168,8 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
|
||||
@Test
|
||||
public void testSearchWithNormalizedQuantitySearchSupported_CombineUCUMOrNonUCUM() throws Exception {
|
||||
|
||||
myDaoConfig.getModelConfig().setNormalizedQuantitySearchSupported();
|
||||
|
||||
myDaoConfig.getModelConfig().setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
IIdType pid0;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
|
@ -4222,11 +4223,17 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
ourLog.info("Observation: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
}
|
||||
|
||||
// > 1m
|
||||
String uri = ourServerBase + "/Observation?value-quantity=" + UrlUtil.escapeUrlParam("100|http://unitsofmeasure.org|cm,100|http://foo|cm");
|
||||
|
||||
ourLog.info("uri = " + uri);
|
||||
List<String> ids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
|
||||
String uri;
|
||||
List<String> ids;
|
||||
|
||||
// With non-normalized
|
||||
uri = ourServerBase + "/Observation?value-quantity=" + UrlUtil.escapeUrlParam("100|http://unitsofmeasure.org|cm,100|http://foo|cm");
|
||||
ids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
|
||||
assertEquals(1, ids.size());
|
||||
|
||||
// With normalized
|
||||
uri = ourServerBase + "/Observation?value-quantity=" + UrlUtil.escapeUrlParam("1|http://unitsofmeasure.org|m,100|http://foo|cm");
|
||||
ids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
|
||||
assertEquals(2, ids.size());
|
||||
}
|
||||
|
||||
|
@ -6044,8 +6051,8 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
|
||||
@Test
|
||||
public void testUpdateWithNormalizedQuantitySearchSupported() throws Exception {
|
||||
|
||||
myDaoConfig.getModelConfig().setNormalizedQuantitySearchSupported();
|
||||
|
||||
myDaoConfig.getModelConfig().setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
IIdType pid0;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
|
|
|
@ -4,6 +4,7 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
|
||||
import ca.uhn.fhir.jpa.config.TestR4Config;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||
|
@ -103,8 +104,8 @@ public class InMemorySubscriptionMatcherR4Test {
|
|||
|
||||
@AfterEach
|
||||
public void after() throws Exception {
|
||||
myModelConfig.setNormalizedQuantitySearchNotSupported();
|
||||
}
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
private void assertMatched(Resource resource, SearchParameterMap params) {
|
||||
InMemoryMatchResult result = match(resource, params);
|
||||
|
@ -249,8 +250,8 @@ public class InMemorySubscriptionMatcherR4Test {
|
|||
|
||||
@Test
|
||||
public void testSearchWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
|
||||
Observation o1 = new Observation();
|
||||
o1.addComponent()
|
||||
|
@ -282,8 +283,8 @@ public class InMemorySubscriptionMatcherR4Test {
|
|||
|
||||
@Test
|
||||
public void testSearchWithNormalizedQuantitySearchSupported_InvalidUCUMUnit() {
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
|
||||
Observation o1 = new Observation();
|
||||
o1.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://bar").setCode("foo")))
|
||||
|
@ -298,8 +299,8 @@ public class InMemorySubscriptionMatcherR4Test {
|
|||
|
||||
@Test
|
||||
public void testSearchWithNormalizedQuantitySearchSupported_NoSystem() {
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
|
||||
Observation o1 = new Observation();
|
||||
o1.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://bar").setCode("foo")))
|
||||
|
@ -314,9 +315,9 @@ public class InMemorySubscriptionMatcherR4Test {
|
|||
|
||||
@Test
|
||||
public void testSearchWithNormalizedQuantitySearchSupported_NotUcumSystem() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
|
||||
Observation o1 = new Observation();
|
||||
o1.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("cm")))
|
||||
|
|
|
@ -655,6 +655,11 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
|
|||
CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId);
|
||||
ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem));
|
||||
|
||||
// If this ever fails, it just means that new codes have been added to the
|
||||
// code system used by this test, so the numbers below may also need to be
|
||||
// updated
|
||||
assertEquals(24, codeSystem.getConcept().size());
|
||||
|
||||
ValueSet valueSet = myValueSetDao.read(myExtensionalVsId);
|
||||
ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet));
|
||||
|
||||
|
@ -662,9 +667,11 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
|
|||
|
||||
ValueSetExpansionOptions options = new ValueSetExpansionOptions()
|
||||
.setOffset(0)
|
||||
.setCount(23);
|
||||
.setCount(24);
|
||||
ValueSet expandedValueSet = myTermSvc.expandValueSet(options, valueSet);
|
||||
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
||||
String expandedValueSetString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet);
|
||||
ourLog.info("Expanded ValueSet:\n" + expandedValueSetString);
|
||||
assertThat(expandedValueSetString, containsString("ValueSet was expanded using a pre-calculated expansion"));
|
||||
|
||||
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
||||
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffset(), expandedValueSet.getExpansion().getOffset());
|
||||
|
@ -672,9 +679,9 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
|
|||
assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName());
|
||||
assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue());
|
||||
assertEquals("count", expandedValueSet.getExpansion().getParameter().get(1).getName());
|
||||
assertEquals(23, expandedValueSet.getExpansion().getParameter().get(1).getValueIntegerType().getValue().intValue());
|
||||
assertEquals(24, expandedValueSet.getExpansion().getParameter().get(1).getValueIntegerType().getValue().intValue());
|
||||
|
||||
assertEquals(23, expandedValueSet.getExpansion().getContains().size());
|
||||
assertEquals(24, expandedValueSet.getExpansion().getContains().size());
|
||||
|
||||
ValueSet.ValueSetExpansionContainsComponent concept = assertExpandedValueSetContainsConcept(expandedValueSet, "http://acme.org", "8450-9", "Systolic blood pressure--expiration", 2);
|
||||
|
||||
|
|
|
@ -256,6 +256,8 @@ public class JdbcUtils {
|
|||
return new ColumnType(ColumnTypeEnum.BLOB, length);
|
||||
case Types.CLOB:
|
||||
return new ColumnType(ColumnTypeEnum.CLOB, length);
|
||||
case Types.DOUBLE:
|
||||
return new ColumnType(ColumnTypeEnum.DOUBLE, length);
|
||||
default:
|
||||
throw new IllegalArgumentException("Don't know how to handle datatype " + dataType + " for column " + theColumnName + " on table " + theTableName);
|
||||
}
|
||||
|
|
|
@ -22,14 +22,14 @@ package ca.uhn.fhir.jpa.migrate.taskdef;
|
|||
|
||||
public enum ColumnTypeEnum {
|
||||
|
||||
LONG,
|
||||
STRING,
|
||||
DATE_ONLY,
|
||||
DATE_TIMESTAMP,
|
||||
BOOLEAN,
|
||||
FLOAT,
|
||||
INT,
|
||||
BLOB,
|
||||
CLOB
|
||||
|
||||
LONG,
|
||||
STRING,
|
||||
DATE_ONLY,
|
||||
DATE_TIMESTAMP,
|
||||
BOOLEAN,
|
||||
FLOAT,
|
||||
INT,
|
||||
BLOB,
|
||||
CLOB,
|
||||
DOUBLE;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,14 @@ public class ColumnTypeToDriverTypeToSqlType {
|
|||
setColumnType(ColumnTypeEnum.FLOAT, DriverTypeEnum.ORACLE_12C, "float");
|
||||
setColumnType(ColumnTypeEnum.FLOAT, DriverTypeEnum.POSTGRES_9_4, "float");
|
||||
|
||||
setColumnType(ColumnTypeEnum.DOUBLE, DriverTypeEnum.H2_EMBEDDED, "double");
|
||||
setColumnType(ColumnTypeEnum.DOUBLE, DriverTypeEnum.DERBY_EMBEDDED, "double");
|
||||
setColumnType(ColumnTypeEnum.DOUBLE, DriverTypeEnum.MARIADB_10_1, "double precision");
|
||||
setColumnType(ColumnTypeEnum.DOUBLE, DriverTypeEnum.MYSQL_5_7, "double precision");
|
||||
setColumnType(ColumnTypeEnum.DOUBLE, DriverTypeEnum.MSSQL_2012, "double precision");
|
||||
setColumnType(ColumnTypeEnum.DOUBLE, DriverTypeEnum.ORACLE_12C, "double precision");
|
||||
setColumnType(ColumnTypeEnum.DOUBLE, DriverTypeEnum.POSTGRES_9_4, "float8");
|
||||
|
||||
setColumnType(ColumnTypeEnum.LONG, DriverTypeEnum.H2_EMBEDDED, "bigint");
|
||||
setColumnType(ColumnTypeEnum.LONG, DriverTypeEnum.DERBY_EMBEDDED, "bigint");
|
||||
setColumnType(ColumnTypeEnum.LONG, DriverTypeEnum.MARIADB_10_1, "bigint");
|
||||
|
|
|
@ -119,6 +119,10 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
|||
.addForeignKey("20210111.3", "FKRCJOVMUH5KC0O6FVBLE319PYV")
|
||||
.toColumn("RES_ID")
|
||||
.references("HFJ_RESOURCE", "RES_ID");
|
||||
|
||||
Builder.BuilderWithTableName quantityTable = version.onTable("HFJ_SPIDX_QUANTITY");
|
||||
quantityTable.modifyColumn("20210116.1", "SP_VALUE").nullable().failureAllowed().withType(ColumnTypeEnum.DOUBLE);
|
||||
|
||||
}
|
||||
|
||||
protected void init520() {
|
||||
|
|
|
@ -90,7 +90,7 @@ public class ModelConfig {
|
|||
private IPrimitiveType<Date> myPeriodIndexEndOfTime;
|
||||
|
||||
private NormalizedQuantitySearchLevel myNormalizedQuantitySearchLevel;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
|
@ -576,6 +576,47 @@ public class ModelConfig {
|
|||
myPeriodIndexEndOfTime = thePeriodIndexEndOfTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles whether Quantity searches support value normalization when using valid UCUM coded values.
|
||||
*
|
||||
* <p>
|
||||
* The default value is {@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED} which is current behavior.
|
||||
* </p>
|
||||
* <p>
|
||||
* Here is the UCUM service support level
|
||||
* <ul>
|
||||
* <li>{@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED}, default, Quantity is stored in {@link ResourceIndexedSearchParamQuantity} only and it is used by searching.</li>
|
||||
* <li>{@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_STORAGE_SUPPORTED}, Quantity is stored in both {@link ResourceIndexedSearchParamQuantity} and {@link ResourceIndexedSearchParamQuantityNormalized}, but {@link ResourceIndexedSearchParamQuantity} is used by searching.</li>
|
||||
* <li>{@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_SEARCH_SUPPORTED}, Quantity is stored in both {@link ResourceIndexedSearchParamQuantity} and {@link ResourceIndexedSearchParamQuantityNormalized}, {@link ResourceIndexedSearchParamQuantityNormalized} is used by searching.</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @since 5.3.0
|
||||
*/
|
||||
public NormalizedQuantitySearchLevel getNormalizedQuantitySearchLevel() {
|
||||
return myNormalizedQuantitySearchLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles whether Quantity searches support value normalization when using valid UCUM coded values.
|
||||
*
|
||||
* <p>
|
||||
* The default value is {@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED} which is current behavior.
|
||||
* </p>
|
||||
* <p>
|
||||
* Here is the UCUM service support level
|
||||
* <ul>
|
||||
* <li>{@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED}, default, Quantity is stored in {@link ResourceIndexedSearchParamQuantity} only and it is used by searching.</li>
|
||||
* <li>{@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_STORAGE_SUPPORTED}, Quantity is stored in both {@link ResourceIndexedSearchParamQuantity} and {@link ResourceIndexedSearchParamQuantityNormalized}, but {@link ResourceIndexedSearchParamQuantity} is used by searching.</li>
|
||||
* <li>{@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_SEARCH_SUPPORTED}, Quantity is stored in both {@link ResourceIndexedSearchParamQuantity} and {@link ResourceIndexedSearchParamQuantityNormalized}, {@link ResourceIndexedSearchParamQuantityNormalized} is used by searching.</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @since 5.3.0
|
||||
*/
|
||||
public void setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel theNormalizedQuantitySearchLevel) {
|
||||
myNormalizedQuantitySearchLevel = theNormalizedQuantitySearchLevel;
|
||||
}
|
||||
|
||||
private static void validateTreatBaseUrlsAsLocal(String theUrl) {
|
||||
Validate.notBlank(theUrl, "Base URL must not be null or empty");
|
||||
|
@ -589,43 +630,4 @@ public class ModelConfig {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the UCUM service support level
|
||||
*
|
||||
* <p>
|
||||
* The default value is {@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED} which is current behavior.
|
||||
* </p>
|
||||
* <p>
|
||||
* Here is the UCUM service support level
|
||||
* <ul>
|
||||
* <li>{@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED}, default, Quantity is stored in {@link ResourceIndexedSearchParamQuantity} only and it is used by searching.</li>
|
||||
* <li>{@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_STORAGE_SUPPORTED}, Quantity is stored in both {@link ResourceIndexedSearchParamQuantity} and {@link ResourceIndexedSearchParamQuantityNormalized}, but {@link ResourceIndexedSearchParamQuantity} is used by searching.</li>
|
||||
* <li>{@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_SEARCH_SUPPORTED}, Quantity is stored in both {@link ResourceIndexedSearchParamQuantity} and {@link ResourceIndexedSearchParamQuantityNormalized}, {@link ResourceIndexedSearchParamQuantityNormalized} is used by searching.</li>
|
||||
* <li>{@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_SEARCH_FULL_SUPPORTED}, Quantity is stored in only in {@link ResourceIndexedSearchParamQuantityNormalized}, {@link ResourceIndexedSearchParamQuantityNormalized} is used by searching. NOTE: this option is not supported yet.</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @since 5.3.0
|
||||
*/
|
||||
public NormalizedQuantitySearchLevel getNormalizedQuantitySearchLevel() {
|
||||
return myNormalizedQuantitySearchLevel;
|
||||
}
|
||||
public void setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel theNormalizedQuantitySearchLevel) {
|
||||
myNormalizedQuantitySearchLevel = theNormalizedQuantitySearchLevel;
|
||||
}
|
||||
public boolean isNormalizedQuantitySearchSupported() {
|
||||
return myNormalizedQuantitySearchLevel.equals(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||
}
|
||||
public boolean isNormalizedQuantityStorageSupported() {
|
||||
return myNormalizedQuantitySearchLevel.equals(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_STORAGE_SUPPORTED);
|
||||
}
|
||||
public void setNormalizedQuantitySearchNotSupported() {
|
||||
myNormalizedQuantitySearchLevel = NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED;
|
||||
}
|
||||
public void setNormalizedQuantityStorageSupported() {
|
||||
myNormalizedQuantitySearchLevel = NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_STORAGE_SUPPORTED;
|
||||
}
|
||||
public void setNormalizedQuantitySearchSupported() {
|
||||
myNormalizedQuantitySearchLevel = NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,5 +53,6 @@ public enum NormalizedQuantitySearchLevel {
|
|||
* The existing non normalized quantity will be not supported
|
||||
* NOTE: this option is not supported in this release
|
||||
*/
|
||||
// When this is enabled, we can enable testSortByQuantityWithNormalizedQuantitySearchFullSupported()
|
||||
//NORMALIZED_QUANTITY_SEARCH_FULL_SUPPORTED,
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ public class ResourceIndexedSearchParamQuantity extends ResourceIndexedSearchPar
|
|||
|
||||
@Column(name = "SP_VALUE", nullable = true)
|
||||
@ScaledNumberField
|
||||
public BigDecimal myValue;
|
||||
public Double myValue;
|
||||
|
||||
public ResourceIndexedSearchParamQuantity() {
|
||||
super();
|
||||
|
@ -99,11 +99,11 @@ public class ResourceIndexedSearchParamQuantity extends ResourceIndexedSearchPar
|
|||
}
|
||||
|
||||
public BigDecimal getValue() {
|
||||
return myValue;
|
||||
return myValue != null ? new BigDecimal(myValue) : null;
|
||||
}
|
||||
|
||||
public ResourceIndexedSearchParamQuantity setValue(BigDecimal theValue) {
|
||||
myValue = theValue;
|
||||
myValue = theValue != null ? theValue.doubleValue() : null;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@ import org.apache.commons.lang3.builder.EqualsBuilder;
|
|||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import org.fhir.ucum.Pair;
|
||||
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField;
|
||||
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.ScaledNumberField;
|
||||
|
||||
|
||||
|
@ -84,23 +83,14 @@ public class ResourceIndexedSearchParamQuantityNormalized extends ResourceIndexe
|
|||
super();
|
||||
}
|
||||
|
||||
public ResourceIndexedSearchParamQuantityNormalized(PartitionSettings thePartitionSettings, String theResourceType, String theParamName, BigDecimal theValue, String theSystem, String theUnits) {
|
||||
public ResourceIndexedSearchParamQuantityNormalized(PartitionSettings thePartitionSettings, String theResourceType, String theParamName, double theValue, String theSystem, String theUnits) {
|
||||
this();
|
||||
setPartitionSettings(thePartitionSettings);
|
||||
setResourceType(theResourceType);
|
||||
setParamName(theParamName);
|
||||
setSystem(theSystem);
|
||||
|
||||
//-- convert the value/unit to the canonical form if any, otherwise store the original value/units pair
|
||||
Pair canonicalForm = UcumServiceUtil.getCanonicalForm(theSystem, theValue, theUnits);
|
||||
if (canonicalForm != null) {
|
||||
setValue(Double.parseDouble(canonicalForm.getValue().asDecimal()));
|
||||
setUnits(canonicalForm.getCode());
|
||||
} else {
|
||||
setValue(theValue);
|
||||
setUnits(theUnits);
|
||||
}
|
||||
|
||||
setValue(theValue);
|
||||
setUnits(theUnits);
|
||||
calculateHashes();
|
||||
}
|
||||
|
||||
|
@ -123,17 +113,13 @@ public class ResourceIndexedSearchParamQuantityNormalized extends ResourceIndexe
|
|||
public ResourceIndexedSearchParamQuantityNormalized setValue(Double theValue) {
|
||||
myValue = theValue;
|
||||
return this;
|
||||
}
|
||||
public void setValue(BigDecimal theValue) {
|
||||
if (theValue != null)
|
||||
myValue = theValue.doubleValue();
|
||||
}
|
||||
public BigDecimal getValueBigDecimal() {
|
||||
if (myValue == null)
|
||||
return null;
|
||||
return new BigDecimal(myValue);
|
||||
|
||||
public ResourceIndexedSearchParamQuantityNormalized setValue(double theValue) {
|
||||
myValue = theValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
//-- myId
|
||||
@Override
|
||||
public Long getId() {
|
||||
|
|
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.jpa.model.util;
|
|||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import ca.uhn.fhir.rest.param.QuantityParam;
|
||||
import org.fhir.ucum.Decimal;
|
||||
import org.fhir.ucum.Pair;
|
||||
import org.fhir.ucum.UcumEssenceService;
|
||||
|
@ -32,6 +33,8 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import ca.uhn.fhir.util.ClasspathUtil;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* It's a wrapper of UcumEssenceService
|
||||
*
|
||||
|
@ -85,7 +88,7 @@ public class UcumServiceUtil {
|
|||
return null;
|
||||
|
||||
init();
|
||||
Pair theCanonicalPair = null;
|
||||
Pair theCanonicalPair;
|
||||
|
||||
try {
|
||||
Decimal theDecimal = new Decimal(theValue.toPlainString(), theValue.precision());
|
||||
|
@ -97,4 +100,19 @@ public class UcumServiceUtil {
|
|||
return theCanonicalPair;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static QuantityParam toCanonicalQuantityOrNull(QuantityParam theQuantityParam) {
|
||||
Pair canonicalForm = getCanonicalForm(theQuantityParam.getSystem(), theQuantityParam.getValue(), theQuantityParam.getUnits());
|
||||
if (canonicalForm != null) {
|
||||
BigDecimal valueValue = new BigDecimal(canonicalForm.getValue().asDecimal());
|
||||
String unitsValue = canonicalForm.getCode();
|
||||
return new QuantityParam()
|
||||
.setSystem(theQuantityParam.getSystem())
|
||||
.setValue(valueValue)
|
||||
.setUnits(unitsValue)
|
||||
.setPrefix(theQuantityParam.getPrefix());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,34 +1,13 @@
|
|||
package ca.uhn.fhir.jpa.model.entity;
|
||||
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
|
||||
public class ResourceIndexedSearchParamQuantityNormalizedTest {
|
||||
|
||||
private ResourceIndexedSearchParamQuantityNormalized createParam(String theParamName, String theValue, String theSystem, String theUnits) {
|
||||
ResourceIndexedSearchParamQuantityNormalized token = new ResourceIndexedSearchParamQuantityNormalized(new PartitionSettings(), "Observation", theParamName, new BigDecimal(theValue), theSystem, theUnits);
|
||||
token.setResource(new ResourceTable().setResourceType("Patient"));
|
||||
return token;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHashFunctions() {
|
||||
ResourceIndexedSearchParamQuantityNormalized token = createParam("Quanity", "123.001", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm");
|
||||
token.calculateHashes();
|
||||
|
||||
// Make sure our hashing function gives consistent results
|
||||
assertEquals(5219730978980909111L, token.getHashIdentity().longValue());
|
||||
assertEquals(-2454931617586657338L, token.getHashIdentityAndUnits().longValue());
|
||||
assertEquals(878263047209296227L, token.getHashIdentitySystemAndUnits().longValue());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
|
@ -46,37 +25,5 @@ public class ResourceIndexedSearchParamQuantityNormalizedTest {
|
|||
assertNotEquals(val1, "");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUcum() {
|
||||
|
||||
//-- system is ucum
|
||||
ResourceIndexedSearchParamQuantityNormalized token1 = createParam("Quanity", "123.001", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm");
|
||||
token1.calculateHashes();
|
||||
|
||||
assertEquals("m", token1.getUnits());
|
||||
assertEquals(Double.parseDouble("1.23001"), token1.getValue());
|
||||
|
||||
//-- small number
|
||||
token1 = createParam("Quanity", "0.000001", UcumServiceUtil.UCUM_CODESYSTEM_URL, "mm");
|
||||
token1.calculateHashes();
|
||||
|
||||
assertEquals("m", token1.getUnits());
|
||||
assertEquals(Double.parseDouble("0.000000001"), token1.getValue());
|
||||
|
||||
|
||||
// -- non ucum system
|
||||
ResourceIndexedSearchParamQuantityNormalized token2 = createParam("Quanity", "123.001", "http://abc.org", "cm");
|
||||
token2.calculateHashes();
|
||||
|
||||
assertEquals("cm", token2.getUnits());
|
||||
assertEquals(Double.parseDouble("123.001"), token2.getValue());
|
||||
|
||||
// -- unsupported ucum code
|
||||
ResourceIndexedSearchParamQuantityNormalized token3 = createParam("Quanity", "123.001", UcumServiceUtil.UCUM_CODESYSTEM_URL, "unknown");
|
||||
token3.calculateHashes();
|
||||
|
||||
assertEquals("unknown", token3.getUnits());
|
||||
assertEquals(Double.parseDouble("123.001"), token3.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import ca.uhn.fhir.context.RuntimeSearchParam;
|
|||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
||||
|
@ -38,6 +39,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantityNormalized
|
|||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri;
|
||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.model.primitive.BoundCodeDt;
|
||||
|
@ -49,7 +51,7 @@ import com.google.common.collect.Sets;
|
|||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hibernate.search.engine.spatial.GeoPoint;
|
||||
import org.fhir.ucum.Pair;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseEnumeration;
|
||||
|
@ -78,7 +80,6 @@ import java.util.TreeSet;
|
|||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static ca.uhn.fhir.jpa.searchparam.extractor.GeopointNormalizer.normalizeLongitude;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.trim;
|
||||
|
@ -201,10 +202,14 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
|||
extractor = createReferenceExtractor();
|
||||
return extractReferenceParamsAsQueryTokens(theSearchParam, theResource, extractor);
|
||||
case QUANTITY:
|
||||
if (myModelConfig.isNormalizedQuantitySearchSupported())
|
||||
extractor = createQuantityNormalizedExtractor(theResource);
|
||||
else
|
||||
if (myModelConfig.getNormalizedQuantitySearchLevel().equals(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED)) {
|
||||
extractor = new CompositeExtractor(
|
||||
createQuantityExtractor(theResource),
|
||||
createQuantityNormalizedExtractor(theResource)
|
||||
);
|
||||
} else {
|
||||
extractor = createQuantityExtractor(theResource);
|
||||
}
|
||||
break;
|
||||
case URI:
|
||||
extractor = createUriExtractor(theResource);
|
||||
|
@ -216,6 +221,7 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
|||
default:
|
||||
throw new UnsupportedOperationException("Type " + theSearchParam.getParamType() + " not supported for extraction");
|
||||
}
|
||||
|
||||
return extractParamsAsQueryTokens(theSearchParam, theResource, extractor);
|
||||
}
|
||||
|
||||
|
@ -377,14 +383,14 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
|||
return extractSearchParams(theResource, extractor, RestSearchParameterTypeEnum.QUANTITY);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public SearchParamSet<ResourceIndexedSearchParamQuantityNormalized> extractSearchParamQuantityNormalized(IBaseResource theResource) {
|
||||
IExtractor<ResourceIndexedSearchParamQuantityNormalized> extractor = createQuantityNormalizedExtractor(theResource);
|
||||
return extractSearchParams(theResource, extractor, RestSearchParameterTypeEnum.QUANTITY);
|
||||
}
|
||||
|
||||
private IExtractor<ResourceIndexedSearchParamQuantity> createQuantityExtractor(IBaseResource theResource) {
|
||||
|
||||
private IExtractor<ResourceIndexedSearchParamQuantity> createQuantityExtractor(IBaseResource theResource) {
|
||||
return (params, searchParam, value, path) -> {
|
||||
if (value.getClass().equals(myLocationPositionDefinition.getImplementingClass())) {
|
||||
return;
|
||||
|
@ -394,7 +400,7 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
|||
String resourceType = toRootTypeName(theResource);
|
||||
switch (nextType) {
|
||||
case "Quantity":
|
||||
addQuantity_Quantity(resourceType, params, searchParam, value);
|
||||
addQuantity_Quantity(resourceType, params, searchParam, value);
|
||||
break;
|
||||
case "Money":
|
||||
addQuantity_Money(resourceType, params, searchParam, value);
|
||||
|
@ -406,11 +412,11 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
|||
addUnexpectedDatatypeWarning(params, searchParam, value);
|
||||
break;
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private IExtractor<ResourceIndexedSearchParamQuantityNormalized> createQuantityNormalizedExtractor(IBaseResource theResource) {
|
||||
|
||||
|
||||
return (params, searchParam, value, path) -> {
|
||||
if (value.getClass().equals(myLocationPositionDefinition.getImplementingClass())) {
|
||||
return;
|
||||
|
@ -434,7 +440,7 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SearchParamSet<ResourceIndexedSearchParamString> extractSearchParamStrings(IBaseResource theResource) {
|
||||
IExtractor<ResourceIndexedSearchParamString> extractor = createStringExtractor(theResource);
|
||||
|
@ -546,24 +552,31 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
|||
String code = extractValueAsString(myQuantityCodeValueChild, theValue);
|
||||
|
||||
ResourceIndexedSearchParamQuantity nextEntity = new ResourceIndexedSearchParamQuantity(myPartitionSettings, theResourceType, theSearchParam.getName(), nextValueValue, system, code);
|
||||
|
||||
theParams.add(nextEntity);
|
||||
|
||||
theParams.add(nextEntity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void addQuantity_QuantityNormalized(String theResourceType, Set<ResourceIndexedSearchParamQuantityNormalized> theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
|
||||
|
||||
|
||||
private void addQuantity_QuantityNormalized(String theResourceType, Set<ResourceIndexedSearchParamQuantityNormalized> theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
|
||||
Optional<IPrimitiveType<BigDecimal>> valueField = myQuantityValueValueChild.getAccessor().getFirstValueOrNull(theValue);
|
||||
if (valueField.isPresent() && valueField.get().getValue() != null) {
|
||||
BigDecimal nextValueValue = valueField.get().getValue();
|
||||
String system = extractValueAsString(myQuantitySystemValueChild, theValue);
|
||||
String code = extractValueAsString(myQuantityCodeValueChild, theValue);
|
||||
|
||||
ResourceIndexedSearchParamQuantityNormalized nextEntity = new ResourceIndexedSearchParamQuantityNormalized(myPartitionSettings, theResourceType, theSearchParam.getName(), nextValueValue, system, code);
|
||||
theParams.add(nextEntity);
|
||||
//-- convert the value/unit to the canonical form if any
|
||||
Pair canonicalForm = UcumServiceUtil.getCanonicalForm(system, nextValueValue, code);
|
||||
if (canonicalForm != null) {
|
||||
double canonicalValue = Double.parseDouble(canonicalForm.getValue().asDecimal());
|
||||
String canonicalUnits = canonicalForm.getCode();
|
||||
ResourceIndexedSearchParamQuantityNormalized nextEntity = new ResourceIndexedSearchParamQuantityNormalized(myPartitionSettings, theResourceType, theSearchParam.getName(), canonicalValue, system, canonicalUnits);
|
||||
theParams.add(nextEntity);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void addQuantity_Money(String theResourceType, Set<ResourceIndexedSearchParamQuantity> theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
|
||||
Optional<IPrimitiveType<BigDecimal>> valueField = myMoneyValueChild.getAccessor().getFirstValueOrNull(theValue);
|
||||
if (valueField.isPresent() && valueField.get().getValue() != null) {
|
||||
|
@ -572,14 +585,14 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
|||
String nextValueString = "urn:iso:std:iso:4217";
|
||||
String nextValueCode = extractValueAsString(myMoneyCurrencyChild, theValue);
|
||||
String searchParamName = theSearchParam.getName();
|
||||
|
||||
|
||||
ResourceIndexedSearchParamQuantity nextEntity = new ResourceIndexedSearchParamQuantity(myPartitionSettings, theResourceType, searchParamName, nextValueValue, nextValueString, nextValueCode);
|
||||
theParams.add(nextEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void addQuantity_MoneyNormalized(String theResourceType, Set<ResourceIndexedSearchParamQuantityNormalized> theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
|
||||
|
||||
private void addQuantity_MoneyNormalized(String theResourceType, Set<ResourceIndexedSearchParamQuantityNormalized> theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
|
||||
Optional<IPrimitiveType<BigDecimal>> valueField = myMoneyValueChild.getAccessor().getFirstValueOrNull(theValue);
|
||||
if (valueField.isPresent() && valueField.get().getValue() != null) {
|
||||
BigDecimal nextValueValue = valueField.get().getValue();
|
||||
|
@ -587,22 +600,22 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
|||
String nextValueString = "urn:iso:std:iso:4217";
|
||||
String nextValueCode = extractValueAsString(myMoneyCurrencyChild, theValue);
|
||||
String searchParamName = theSearchParam.getName();
|
||||
|
||||
ResourceIndexedSearchParamQuantityNormalized nextEntityNormalized = new ResourceIndexedSearchParamQuantityNormalized(myPartitionSettings, theResourceType, searchParamName, nextValueValue, nextValueString, nextValueCode);
|
||||
theParams.add(nextEntityNormalized);
|
||||
|
||||
ResourceIndexedSearchParamQuantityNormalized nextEntityNormalized = new ResourceIndexedSearchParamQuantityNormalized(myPartitionSettings, theResourceType, searchParamName, nextValueValue.doubleValue(), nextValueString, nextValueCode);
|
||||
theParams.add(nextEntityNormalized);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void addQuantity_Range(String theResourceType, Set<ResourceIndexedSearchParamQuantity> theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
|
||||
Optional<IBase> low = myRangeLowValueChild.getAccessor().getFirstValueOrNull(theValue);
|
||||
low.ifPresent(theIBase -> addQuantity_Quantity(theResourceType, theParams, theSearchParam, theIBase));
|
||||
|
||||
Optional<IBase> high = myRangeHighValueChild.getAccessor().getFirstValueOrNull(theValue);
|
||||
high.ifPresent(theIBase -> addQuantity_Quantity(theResourceType, theParams, theSearchParam, theIBase));
|
||||
high.ifPresent(theIBase -> addQuantity_Quantity(theResourceType, theParams, theSearchParam, theIBase));
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void addQuantity_RangeNormalized(String theResourceType, Set<ResourceIndexedSearchParamQuantityNormalized> theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
|
||||
Optional<IBase> low = myRangeLowValueChild.getAccessor().getFirstValueOrNull(theValue);
|
||||
low.ifPresent(theIBase -> addQuantity_QuantityNormalized(theResourceType, theParams, theSearchParam, theIBase));
|
||||
|
@ -610,7 +623,7 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
|||
Optional<IBase> high = myRangeHighValueChild.getAccessor().getFirstValueOrNull(theValue);
|
||||
high.ifPresent(theIBase -> addQuantity_QuantityNormalized(theResourceType, theParams, theSearchParam, theIBase));
|
||||
}
|
||||
|
||||
|
||||
private void addToken_Identifier(String theResourceType, Set<BaseResourceIndexedSearchParam> theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
|
||||
String system = extractValueAsString(myIdentifierSystemValueChild, theValue);
|
||||
String value = extractValueAsString(myIdentifierValueValueChild, theValue);
|
||||
|
@ -1163,11 +1176,27 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
|||
@FunctionalInterface
|
||||
private interface IExtractor<T> {
|
||||
|
||||
|
||||
void extract(SearchParamSet<T> theParams, RuntimeSearchParam theSearchParam, IBase theValue, String thePath);
|
||||
|
||||
}
|
||||
|
||||
private static class CompositeExtractor<T> implements IExtractor<T> {
|
||||
|
||||
private final IExtractor<T> myExtractor0;
|
||||
private final IExtractor<T> myExtractor1;
|
||||
|
||||
private CompositeExtractor(IExtractor<T> theExtractor0, IExtractor<T> theExtractor1) {
|
||||
myExtractor0 = theExtractor0;
|
||||
myExtractor1 = theExtractor1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extract(SearchParamSet<T> theParams, RuntimeSearchParam theSearchParam, IBase theValue, String thePath) {
|
||||
myExtractor0.extract(theParams, theSearchParam, theValue, thePath);
|
||||
myExtractor1.extract(theParams, theSearchParam, theValue, thePath);
|
||||
}
|
||||
}
|
||||
|
||||
private class ResourceLinkExtractor implements IExtractor<PathAndRef> {
|
||||
|
||||
private PathAndRef myPathAndRef = null;
|
||||
|
|
|
@ -25,6 +25,7 @@ import ca.uhn.fhir.context.RuntimeSearchParam;
|
|||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
|
@ -36,9 +37,14 @@ import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
|||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||
import ca.uhn.fhir.rest.param.QuantityParam;
|
||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Streams;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -51,6 +57,7 @@ import java.util.Map;
|
|||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.compare;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
@ -158,21 +165,30 @@ public final class ResourceIndexedSearchParams {
|
|||
return myPopulatedResourceLinkParameters;
|
||||
}
|
||||
|
||||
public boolean matchParam(ModelConfig theModelConfig, String theResourceName, String theParamName, RuntimeSearchParam theParamDef, IQueryParameterType theParam) {
|
||||
public boolean matchParam(ModelConfig theModelConfig, String theResourceName, String theParamName, RuntimeSearchParam theParamDef, IQueryParameterType theValue) {
|
||||
|
||||
if (theParamDef == null) {
|
||||
return false;
|
||||
}
|
||||
Collection<? extends BaseResourceIndexedSearchParam> resourceParams;
|
||||
Collection<? extends BaseResourceIndexedSearchParam> resourceParams = null;
|
||||
IQueryParameterType value = theValue;
|
||||
switch (theParamDef.getParamType()) {
|
||||
case TOKEN:
|
||||
resourceParams = myTokenParams;
|
||||
break;
|
||||
case QUANTITY:
|
||||
if (theModelConfig.isNormalizedQuantitySearchSupported())
|
||||
resourceParams = myQuantityNormalizedParams;
|
||||
else
|
||||
resourceParams = myQuantityParams;
|
||||
if (theModelConfig.getNormalizedQuantitySearchLevel().equals(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED)) {
|
||||
QuantityParam quantity = QuantityParam.toQuantityParam(theValue);
|
||||
QuantityParam normalized = UcumServiceUtil.toCanonicalQuantityOrNull(quantity);
|
||||
if (normalized != null) {
|
||||
resourceParams = myQuantityNormalizedParams;
|
||||
value = normalized;
|
||||
}
|
||||
}
|
||||
|
||||
if (resourceParams == null) {
|
||||
resourceParams = myQuantityParams;
|
||||
}
|
||||
break;
|
||||
case STRING:
|
||||
resourceParams = myStringParams;
|
||||
|
@ -187,7 +203,7 @@ public final class ResourceIndexedSearchParams {
|
|||
resourceParams = myDateParams;
|
||||
break;
|
||||
case REFERENCE:
|
||||
return matchResourceLinks(theModelConfig, theResourceName, theParamName, theParam, theParamDef.getPath());
|
||||
return matchResourceLinks(theModelConfig, theResourceName, theParamName, value, theParamDef.getPath());
|
||||
case COMPOSITE:
|
||||
case HAS:
|
||||
case SPECIAL:
|
||||
|
@ -197,11 +213,16 @@ public final class ResourceIndexedSearchParams {
|
|||
if (resourceParams == null) {
|
||||
return false;
|
||||
}
|
||||
Predicate<BaseResourceIndexedSearchParam> namedParamPredicate = param ->
|
||||
param.getParamName().equalsIgnoreCase(theParamName) &&
|
||||
param.matches(theParam);
|
||||
|
||||
return resourceParams.stream().anyMatch(namedParamPredicate);
|
||||
for (BaseResourceIndexedSearchParam nextParam : resourceParams) {
|
||||
if (nextParam.getParamName().equalsIgnoreCase(theParamName)) {
|
||||
if (nextParam.matches(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -275,10 +296,7 @@ public final class ResourceIndexedSearchParams {
|
|||
public void findMissingSearchParams(PartitionSettings thePartitionSettings, ModelConfig theModelConfig, ResourceTable theEntity, Set<Entry<String, RuntimeSearchParam>> theActiveSearchParams) {
|
||||
findMissingSearchParams(thePartitionSettings, theModelConfig, theEntity, theActiveSearchParams, RestSearchParameterTypeEnum.STRING, myStringParams);
|
||||
findMissingSearchParams(thePartitionSettings, theModelConfig, theEntity, theActiveSearchParams, RestSearchParameterTypeEnum.NUMBER, myNumberParams);
|
||||
if (theModelConfig.isNormalizedQuantitySearchSupported())
|
||||
findMissingSearchParams(thePartitionSettings, theModelConfig, theEntity, theActiveSearchParams, RestSearchParameterTypeEnum.QUANTITY, myQuantityNormalizedParams);
|
||||
else
|
||||
findMissingSearchParams(thePartitionSettings, theModelConfig, theEntity, theActiveSearchParams, RestSearchParameterTypeEnum.QUANTITY, myQuantityParams);
|
||||
findMissingSearchParams(thePartitionSettings, theModelConfig, theEntity, theActiveSearchParams, RestSearchParameterTypeEnum.QUANTITY, myQuantityParams);
|
||||
findMissingSearchParams(thePartitionSettings, theModelConfig, theEntity, theActiveSearchParams, RestSearchParameterTypeEnum.DATE, myDateParams);
|
||||
findMissingSearchParams(thePartitionSettings, theModelConfig, theEntity, theActiveSearchParams, RestSearchParameterTypeEnum.URI, myUriParams);
|
||||
findMissingSearchParams(thePartitionSettings, theModelConfig, theEntity, theActiveSearchParams, RestSearchParameterTypeEnum.TOKEN, myTokenParams);
|
||||
|
@ -309,10 +327,7 @@ public final class ResourceIndexedSearchParams {
|
|||
param = new ResourceIndexedSearchParamNumber();
|
||||
break;
|
||||
case QUANTITY:
|
||||
if (theModelConfig.isNormalizedQuantitySearchSupported())
|
||||
param = new ResourceIndexedSearchParamQuantityNormalized();
|
||||
else
|
||||
param = new ResourceIndexedSearchParamQuantity();
|
||||
param = new ResourceIndexedSearchParamQuantity();
|
||||
break;
|
||||
case STRING:
|
||||
param = new ResourceIndexedSearchParamString()
|
||||
|
|
|
@ -21,7 +21,6 @@ package ca.uhn.fhir.jpa.searchparam.extractor;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
|
@ -50,9 +49,9 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
|
|||
|
||||
// This constructor is used by tests
|
||||
@VisibleForTesting
|
||||
public SearchParamExtractorDstu3(ModelConfig theModelConfig, PartitionSettings thePartitionSettings, FhirContext theCtx, IValidationSupport theValidationSupport, ISearchParamRegistry theSearchParamRegistry) {
|
||||
public SearchParamExtractorDstu3(ModelConfig theModelConfig, PartitionSettings thePartitionSettings, FhirContext theCtx, ISearchParamRegistry theSearchParamRegistry) {
|
||||
super(theModelConfig, thePartitionSettings, theCtx, theSearchParamRegistry);
|
||||
initFhirPathEngine(theValidationSupport);
|
||||
initFhirPathEngine();
|
||||
start();
|
||||
}
|
||||
|
||||
|
@ -75,13 +74,12 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
|
|||
public void start() {
|
||||
super.start();
|
||||
if (myFhirPathEngine == null) {
|
||||
IValidationSupport support = myApplicationContext.getBean(IValidationSupport.class);
|
||||
initFhirPathEngine(support);
|
||||
initFhirPathEngine();
|
||||
}
|
||||
}
|
||||
|
||||
public void initFhirPathEngine(IValidationSupport theSupport) {
|
||||
IWorkerContext worker = new HapiWorkerContext(getContext(), theSupport);
|
||||
public void initFhirPathEngine() {
|
||||
IWorkerContext worker = new HapiWorkerContext(getContext(), getContext().getValidationSupport());
|
||||
myFhirPathEngine = new FHIRPathEngine(worker);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ package ca.uhn.fhir.jpa.searchparam.extractor;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
|
@ -62,9 +61,9 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements
|
|||
|
||||
// This constructor is used by tests
|
||||
@VisibleForTesting
|
||||
public SearchParamExtractorR4(ModelConfig theModelConfig, PartitionSettings thePartitionSettings, FhirContext theCtx, IValidationSupport theValidationSupport, ISearchParamRegistry theSearchParamRegistry) {
|
||||
public SearchParamExtractorR4(ModelConfig theModelConfig, PartitionSettings thePartitionSettings, FhirContext theCtx, ISearchParamRegistry theSearchParamRegistry) {
|
||||
super(theModelConfig, thePartitionSettings, theCtx, theSearchParamRegistry);
|
||||
initFhirPath(theValidationSupport);
|
||||
initFhirPath();
|
||||
start();
|
||||
}
|
||||
|
||||
|
@ -82,13 +81,12 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements
|
|||
public void start() {
|
||||
super.start();
|
||||
if (myFhirPathEngine == null) {
|
||||
IValidationSupport support = myApplicationContext.getBean(IValidationSupport.class);
|
||||
initFhirPath(support);
|
||||
initFhirPath();
|
||||
}
|
||||
}
|
||||
|
||||
public void initFhirPath(IValidationSupport theSupport) {
|
||||
IWorkerContext worker = new HapiWorkerContext(getContext(), theSupport);
|
||||
public void initFhirPath() {
|
||||
IWorkerContext worker = new HapiWorkerContext(getContext(), getContext().getValidationSupport());
|
||||
myFhirPathEngine = new FHIRPathEngine(worker);
|
||||
myFhirPathEngine.setHostServices(new SearchParamExtractorR4HostServices());
|
||||
}
|
||||
|
@ -96,7 +94,7 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements
|
|||
|
||||
private static class SearchParamExtractorR4HostServices implements FHIRPathEngine.IEvaluationContext {
|
||||
|
||||
private Map<String, Base> myResourceTypeToStub = Collections.synchronizedMap(new HashMap<>());
|
||||
private final Map<String, Base> myResourceTypeToStub = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
@Override
|
||||
public Base resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException {
|
||||
|
|
|
@ -21,8 +21,6 @@ package ca.uhn.fhir.jpa.searchparam.extractor;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
|
@ -58,9 +56,9 @@ public class SearchParamExtractorR5 extends BaseSearchParamExtractor implements
|
|||
/**
|
||||
* Constructor for unit tests
|
||||
*/
|
||||
public SearchParamExtractorR5(ModelConfig theModelConfig, PartitionSettings thePartitionSettings, FhirContext theCtx, DefaultProfileValidationSupport theDefaultProfileValidationSupport, ISearchParamRegistry theSearchParamRegistry) {
|
||||
public SearchParamExtractorR5(ModelConfig theModelConfig, PartitionSettings thePartitionSettings, FhirContext theCtx, ISearchParamRegistry theSearchParamRegistry) {
|
||||
super(theModelConfig, thePartitionSettings, theCtx, theSearchParamRegistry);
|
||||
initFhirPath(theDefaultProfileValidationSupport);
|
||||
initFhirPath();
|
||||
start();
|
||||
}
|
||||
|
||||
|
@ -69,13 +67,12 @@ public class SearchParamExtractorR5 extends BaseSearchParamExtractor implements
|
|||
public void start() {
|
||||
super.start();
|
||||
if (myFhirPathEngine == null) {
|
||||
IValidationSupport support = myApplicationContext.getBean(IValidationSupport.class);
|
||||
initFhirPath(support);
|
||||
initFhirPath();
|
||||
}
|
||||
}
|
||||
|
||||
public void initFhirPath(IValidationSupport theSupport) {
|
||||
IWorkerContext worker = new HapiWorkerContext(getContext(), theSupport);
|
||||
public void initFhirPath() {
|
||||
IWorkerContext worker = new HapiWorkerContext(getContext(), getContext().getValidationSupport());
|
||||
myFhirPathEngine = new FHIRPathEngine(worker);
|
||||
myFhirPathEngine.setHostServices(new SearchParamExtractorR5HostServices());
|
||||
}
|
||||
|
@ -88,7 +85,7 @@ public class SearchParamExtractorR5 extends BaseSearchParamExtractor implements
|
|||
|
||||
private static class SearchParamExtractorR5HostServices implements FHIRPathEngine.IEvaluationContext {
|
||||
|
||||
private Map<String, Base> myResourceTypeToStub = Collections.synchronizedMap(new HashMap<>());
|
||||
private final Map<String, Base> myResourceTypeToStub = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
@Override
|
||||
public Base resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException {
|
||||
|
|
|
@ -31,6 +31,7 @@ import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
|||
import ca.uhn.fhir.jpa.model.cross.IResourceLookup;
|
||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
||||
|
@ -119,8 +120,8 @@ public class SearchParamExtractorService {
|
|||
ISearchParamExtractor.SearchParamSet<ResourceIndexedSearchParamQuantity> quantities = extractSearchParamQuantity(theResource);
|
||||
handleWarnings(theRequestDetails, myInterceptorBroadcaster, quantities);
|
||||
theParams.myQuantityParams.addAll(quantities);
|
||||
|
||||
if (myModelConfig.isNormalizedQuantityStorageSupported()|| myModelConfig.isNormalizedQuantitySearchSupported()) {
|
||||
|
||||
if (myModelConfig.getNormalizedQuantitySearchLevel().equals(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_STORAGE_SUPPORTED) || myModelConfig.getNormalizedQuantitySearchLevel().equals(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED)) {
|
||||
ISearchParamExtractor.SearchParamSet<ResourceIndexedSearchParamQuantityNormalized> quantitiesNormalized = extractSearchParamQuantityNormalized(theResource);
|
||||
handleWarnings(theRequestDetails, myInterceptorBroadcaster, quantitiesNormalized);
|
||||
theParams.myQuantityNormalizedParams.addAll(quantitiesNormalized);
|
||||
|
|
|
@ -9,9 +9,6 @@ import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
|||
import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorDstu3;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport;
|
||||
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
||||
import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -23,7 +20,6 @@ import java.util.stream.Collectors;
|
|||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
@ -43,9 +39,8 @@ public class IndexStressTest {
|
|||
FhirContext ctx = FhirContext.forDstu3();
|
||||
IValidationSupport mockValidationSupport = mock(IValidationSupport.class);
|
||||
when(mockValidationSupport.getFhirContext()).thenReturn(ctx);
|
||||
IValidationSupport validationSupport = new CachingValidationSupport(new ValidationSupportChain(new DefaultProfileValidationSupport(ctx), mockValidationSupport));
|
||||
ISearchParamRegistry searchParamRegistry = mock(ISearchParamRegistry.class);
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ctx, validationSupport, searchParamRegistry);
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ctx, searchParamRegistry);
|
||||
extractor.start();
|
||||
|
||||
Map<String, RuntimeSearchParam> spMap = ctx
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
package ca.uhn.fhir.jpa.searchparam.extractor;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
|
||||
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.jpa.cache.ResourceChangeResult;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||
|
@ -33,7 +32,6 @@ import org.hl7.fhir.dstu3.model.Observation;
|
|||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.dstu3.model.Questionnaire;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.text.Normalizer;
|
||||
|
@ -51,8 +49,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||
|
||||
public class SearchParamExtractorDstu3Test {
|
||||
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
private static IValidationSupport ourValidationSupport;
|
||||
private static FhirContext ourCtx = FhirContext.forCached(FhirVersionEnum.DSTU3);
|
||||
|
||||
@Test
|
||||
public void testParamWithOrInPath() {
|
||||
|
@ -61,7 +58,7 @@ public class SearchParamExtractorDstu3Test {
|
|||
|
||||
ISearchParamRegistry searchParamRegistry = new MySearchParamRegistry();
|
||||
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, ourValidationSupport, searchParamRegistry);
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, searchParamRegistry);
|
||||
extractor.start();
|
||||
Set<BaseResourceIndexedSearchParam> tokens = extractor.extractSearchParamTokens(obs);
|
||||
assertEquals(1, tokens.size());
|
||||
|
@ -84,7 +81,7 @@ public class SearchParamExtractorDstu3Test {
|
|||
|
||||
ISearchParamRegistry searchParamRegistry = new MySearchParamRegistry();
|
||||
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, ourValidationSupport, searchParamRegistry);
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, searchParamRegistry);
|
||||
extractor.start();
|
||||
Set<ResourceIndexedSearchParamString> params = extractor.extractSearchParamStrings(questionnaire);
|
||||
assertEquals(1, params.size());
|
||||
|
@ -102,7 +99,7 @@ public class SearchParamExtractorDstu3Test {
|
|||
|
||||
ISearchParamRegistry searchParamRegistry = new MySearchParamRegistry();
|
||||
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, ourValidationSupport, searchParamRegistry);
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, searchParamRegistry);
|
||||
extractor.start();
|
||||
Set<ResourceIndexedSearchParamNumber> params = extractor.extractSearchParamNumber(enc);
|
||||
assertEquals(1, params.size());
|
||||
|
@ -120,7 +117,7 @@ public class SearchParamExtractorDstu3Test {
|
|||
|
||||
ISearchParamRegistry searchParamRegistry = new MySearchParamRegistry();
|
||||
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, ourValidationSupport, searchParamRegistry);
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, searchParamRegistry);
|
||||
extractor.start();
|
||||
Set<ResourceIndexedSearchParamNumber> params = extractor.extractSearchParamNumber(enc);
|
||||
assertEquals(1, params.size());
|
||||
|
@ -132,7 +129,7 @@ public class SearchParamExtractorDstu3Test {
|
|||
public void testEmptyPath() {
|
||||
|
||||
MySearchParamRegistry searchParamRegistry = new MySearchParamRegistry();
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, ourValidationSupport, searchParamRegistry);
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, searchParamRegistry);
|
||||
extractor.start();
|
||||
|
||||
searchParamRegistry.addSearchParam(new RuntimeSearchParam("foo", "foo", "", RestSearchParameterTypeEnum.STRING, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE));
|
||||
|
@ -148,7 +145,7 @@ public class SearchParamExtractorDstu3Test {
|
|||
public void testStringMissingResourceType() {
|
||||
|
||||
MySearchParamRegistry searchParamRegistry = new MySearchParamRegistry();
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, ourValidationSupport, searchParamRegistry);
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, searchParamRegistry);
|
||||
extractor.start();
|
||||
|
||||
searchParamRegistry.addSearchParam(new RuntimeSearchParam("foo", "foo", "communication.language.coding.system | communication.language.coding.code", RestSearchParameterTypeEnum.STRING, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE));
|
||||
|
@ -165,7 +162,7 @@ public class SearchParamExtractorDstu3Test {
|
|||
public void testInvalidType() {
|
||||
|
||||
MySearchParamRegistry searchParamRegistry = new MySearchParamRegistry();
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, ourValidationSupport, searchParamRegistry);
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, searchParamRegistry);
|
||||
extractor.start();
|
||||
|
||||
{
|
||||
|
@ -216,7 +213,7 @@ public class SearchParamExtractorDstu3Test {
|
|||
|
||||
ISearchParamRegistry searchParamRegistry = new MySearchParamRegistry();
|
||||
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, ourValidationSupport, searchParamRegistry);
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, searchParamRegistry);
|
||||
extractor.start();
|
||||
ISearchParamExtractor.SearchParamSet<BaseResourceIndexedSearchParam> coords = extractor.extractSearchParamTokens(loc);
|
||||
assertEquals(1, coords.size());
|
||||
|
@ -227,7 +224,7 @@ public class SearchParamExtractorDstu3Test {
|
|||
|
||||
private static class MySearchParamRegistry implements ISearchParamRegistry {
|
||||
|
||||
private List<RuntimeSearchParam> myAddedSearchParams = new ArrayList<>();
|
||||
private final List<RuntimeSearchParam> myAddedSearchParams = new ArrayList<>();
|
||||
|
||||
public void addSearchParam(RuntimeSearchParam... theSearchParam) {
|
||||
myAddedSearchParams.clear();
|
||||
|
@ -306,9 +303,4 @@ public class SearchParamExtractorDstu3Test {
|
|||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
ourValidationSupport = new DefaultProfileValidationSupport(ourCtx);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ import ca.uhn.fhir.context.RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition;
|
|||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
|
||||
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
||||
import ca.uhn.fhir.jpa.cache.ResourceChangeResult;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
|
@ -66,15 +65,15 @@ public class SearchParamExtractorMegaTest {
|
|||
|
||||
ctx = FhirContext.forDstu3();
|
||||
searchParamRegistry = new MySearchParamRegistry(ctx);
|
||||
process(ctx, new SearchParamExtractorDstu3(new ModelConfig(), partitionSettings, ctx, new DefaultProfileValidationSupport(ctx), searchParamRegistry));
|
||||
process(ctx, new SearchParamExtractorDstu3(new ModelConfig(), partitionSettings, ctx, searchParamRegistry));
|
||||
|
||||
ctx = FhirContext.forR4();
|
||||
searchParamRegistry = new MySearchParamRegistry(ctx);
|
||||
process(ctx, new SearchParamExtractorR4(new ModelConfig(), partitionSettings, ctx, new DefaultProfileValidationSupport(ctx), searchParamRegistry));
|
||||
process(ctx, new SearchParamExtractorR4(new ModelConfig(), partitionSettings, ctx, searchParamRegistry));
|
||||
|
||||
ctx = FhirContext.forR5();
|
||||
searchParamRegistry = new MySearchParamRegistry(ctx);
|
||||
process(ctx, new SearchParamExtractorR5(new ModelConfig(), partitionSettings, ctx, new DefaultProfileValidationSupport(ctx), searchParamRegistry));
|
||||
process(ctx, new SearchParamExtractorR5(new ModelConfig(), partitionSettings, ctx, searchParamRegistry));
|
||||
}
|
||||
|
||||
private void process(FhirContext theCtx, BaseSearchParamExtractor theExtractor) throws Exception {
|
||||
|
|
|
@ -45,7 +45,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
* request with an {@link UnprocessableEntityException HTTP 422 Unprocessable Entity}.
|
||||
*/
|
||||
@Interceptor
|
||||
public abstract class BaseValidatingInterceptor<T> {
|
||||
public abstract class BaseValidatingInterceptor<T> extends ValidationResultEnrichingInterceptor {
|
||||
|
||||
/**
|
||||
* Default value:<br/>
|
||||
|
|
|
@ -31,8 +31,6 @@ import ca.uhn.fhir.rest.server.method.ResourceParameter;
|
|||
import ca.uhn.fhir.validation.FhirValidator;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import ca.uhn.fhir.validation.ValidationResult;
|
||||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
@ -51,11 +49,6 @@ public class RequestValidatingInterceptor extends BaseValidatingInterceptor<Stri
|
|||
* X-HAPI-Request-Validation
|
||||
*/
|
||||
public static final String DEFAULT_RESPONSE_HEADER_NAME = "X-FHIR-Request-Validation";
|
||||
/**
|
||||
* A {@link RequestDetails#getUserData() user data} entry will be created with this
|
||||
* key which contains the {@link ValidationResult} from validating the request.
|
||||
*/
|
||||
public static final String REQUEST_VALIDATION_RESULT = RequestValidatingInterceptor.class.getName() + "_REQUEST_VALIDATION_RESULT";
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RequestValidatingInterceptor.class);
|
||||
private boolean myAddValidationResultsToResponseOperationOutcome = true;
|
||||
|
||||
|
@ -82,8 +75,9 @@ public class RequestValidatingInterceptor extends BaseValidatingInterceptor<Stri
|
|||
|
||||
ValidationResult validationResult = validate(requestText, theRequestDetails);
|
||||
|
||||
// The JPA server will use this
|
||||
theRequestDetails.getUserData().put(REQUEST_VALIDATION_RESULT, validationResult);
|
||||
if (myAddValidationResultsToResponseOperationOutcome) {
|
||||
addValidationResultToRequestDetails(theRequestDetails, validationResult);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -110,25 +104,6 @@ public class RequestValidatingInterceptor extends BaseValidatingInterceptor<Stri
|
|||
myAddValidationResultsToResponseOperationOutcome = theAddValidationResultsToResponseOperationOutcome;
|
||||
}
|
||||
|
||||
@Hook(Pointcut.SERVER_OUTGOING_RESPONSE)
|
||||
public boolean outgoingResponse(RequestDetails theRequestDetails, IBaseResource theResponseObject) {
|
||||
if (myAddValidationResultsToResponseOperationOutcome) {
|
||||
if (theResponseObject instanceof IBaseOperationOutcome) {
|
||||
IBaseOperationOutcome oo = (IBaseOperationOutcome) theResponseObject;
|
||||
|
||||
if (theRequestDetails != null) {
|
||||
ValidationResult validationResult = (ValidationResult) theRequestDetails.getUserData().get(RequestValidatingInterceptor.REQUEST_VALIDATION_RESULT);
|
||||
if (validationResult != null) {
|
||||
validationResult.populateOperationOutcome(oo);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
String provideDefaultResponseHeaderName() {
|
||||
return DEFAULT_RESPONSE_HEADER_NAME;
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
package ca.uhn.fhir.rest.server.interceptor;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Server Framework
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2021 Smile CDR, Inc.
|
||||
* %%
|
||||
* 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.interceptor.api.Hook;
|
||||
import ca.uhn.fhir.interceptor.api.Interceptor;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.validation.ValidationResult;
|
||||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Interceptor
|
||||
public class ValidationResultEnrichingInterceptor {
|
||||
|
||||
/**
|
||||
* A {@link RequestDetails#getUserData() user data} entry will be created with this
|
||||
* key which contains the {@link ValidationResult} from validating the request.
|
||||
*/
|
||||
public static final String REQUEST_VALIDATION_RESULT = ValidationResultEnrichingInterceptor.class.getName() + "_REQUEST_VALIDATION_RESULT";
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Hook(Pointcut.SERVER_OUTGOING_RESPONSE)
|
||||
public boolean addValidationResultsToOperationOutcome(RequestDetails theRequestDetails, IBaseResource theResponseObject) {
|
||||
if (theResponseObject instanceof IBaseOperationOutcome) {
|
||||
IBaseOperationOutcome oo = (IBaseOperationOutcome) theResponseObject;
|
||||
|
||||
if (theRequestDetails != null) {
|
||||
List<ValidationResult> validationResult = (List<ValidationResult>) theRequestDetails.getUserData().remove(REQUEST_VALIDATION_RESULT);
|
||||
if (validationResult != null) {
|
||||
for (ValidationResult next : validationResult) {
|
||||
next.populateOperationOutcome(oo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void addValidationResultToRequestDetails(@Nullable RequestDetails theRequestDetails, @Nonnull ValidationResult theValidationResult) {
|
||||
if (theRequestDetails != null) {
|
||||
List<ValidationResult> results = (List<ValidationResult>) theRequestDetails.getUserData().computeIfAbsent(REQUEST_VALIDATION_RESULT, t -> new ArrayList<>(2));
|
||||
results.add(theValidationResult);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,15 +9,14 @@ import fr.inria.lille.shexjava.schema.parsing.GenParser;
|
|||
import fr.inria.lille.shexjava.validation.RecursiveValidation;
|
||||
import fr.inria.lille.shexjava.validation.ValidationAlgorithm;
|
||||
import org.apache.commons.rdf.api.Graph;
|
||||
import org.apache.commons.rdf.api.IRI;
|
||||
import org.apache.commons.rdf.api.RDFTerm;
|
||||
import org.apache.commons.rdf.rdf4j.RDF4J;
|
||||
import org.eclipse.rdf4j.model.Model;
|
||||
import org.eclipse.rdf4j.model.impl.SimpleIRI;
|
||||
import org.eclipse.rdf4j.rio.RDFFormat;
|
||||
import org.eclipse.rdf4j.rio.Rio;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.Base;
|
||||
import org.hl7.fhir.r4.model.DomainResource;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
@ -25,8 +24,10 @@ import org.springframework.core.io.Resource;
|
|||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
@ -53,6 +54,15 @@ public class RDFParserTest extends BaseTest {
|
|||
fhirSchema = GenParser.parseSchema(schemaFile, Collections.emptyList());
|
||||
}
|
||||
|
||||
// If we can't round-trip JSON, we skip the Turtle round-trip test.
|
||||
private static ArrayList<String> jsonRoundTripErrors = new ArrayList<String>();
|
||||
@AfterAll
|
||||
static void reportJsonRoundTripErrors() {
|
||||
System.out.println(jsonRoundTripErrors.size() + " tests disqualified because of JSON round-trip errors");
|
||||
for (String e : jsonRoundTripErrors)
|
||||
System.out.println(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test method has a method source for each JSON file in the resources/rdf-test-input directory (see #getInputFiles).
|
||||
* Each input file is expected to be a JSON representation of an R4 FHIR resource.
|
||||
|
@ -62,71 +72,48 @@ public class RDFParserTest extends BaseTest {
|
|||
* 3. Perform a graph validation on the resulting RDF using ShEx and ShEx-java -- ensure validation passed
|
||||
* 4. Parse the RDF string into the HAPI object model -- ensure resource instance is not null
|
||||
* 5. Perform deep equals comparison of JSON-originated instance and RDF-originated instance -- ensure equality
|
||||
* @param inputFile -- path to resource file to be tested
|
||||
* @param referenceFilePath -- path to resource file to be tested
|
||||
* @throws IOException -- thrown when parsing RDF string into graph model
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("getInputFiles")
|
||||
public void testRDFRoundTrip(String inputFile) throws IOException {
|
||||
FileInputStream inputStream = new FileInputStream(inputFile);
|
||||
IBaseResource resource;
|
||||
String resourceType;
|
||||
// Parse JSON input as Resource
|
||||
resource = ourCtx.newJsonParser().parseResource(inputStream);
|
||||
assertNotNull(resource);
|
||||
resourceType = resource.fhirType();
|
||||
|
||||
// Write the resource out to an RDF String
|
||||
String rdfContent = ourCtx.newRDFParser().encodeResourceToString(resource);
|
||||
assertNotNull(rdfContent);
|
||||
public void testRDFRoundTrip(String referenceFilePath) throws IOException {
|
||||
String referenceFileName = referenceFilePath.substring(referenceFilePath.lastIndexOf("/")+1);
|
||||
IBaseResource referenceResource = parseJson(new FileInputStream(referenceFilePath));
|
||||
String referenceJson = serializeJson(ourCtx, referenceResource);
|
||||
|
||||
// Perform ShEx validation on RDF
|
||||
RDF4J factory = new RDF4J();
|
||||
GlobalFactory.RDFFactory = factory; //set the global factory used in shexjava
|
||||
String turtleString = serializeRdf(ourCtx, referenceResource);
|
||||
validateRdf(turtleString, referenceFileName, referenceResource);
|
||||
|
||||
// load the model
|
||||
String baseIRI = "http://a.example.shex/";
|
||||
Model data = Rio.parse(new StringReader(rdfContent), baseIRI, RDFFormat.TURTLE);
|
||||
// If we can round-trip JSON
|
||||
IBaseResource viaJsonResource = parseJson(new ByteArrayInputStream(referenceJson.getBytes()));
|
||||
if (((Base)viaJsonResource).equalsDeep((Base)referenceResource)) {
|
||||
|
||||
String rootSubjectIri = null;
|
||||
for (org.eclipse.rdf4j.model.Resource resourceStream : data.subjects()) {
|
||||
if (resourceStream instanceof SimpleIRI) {
|
||||
Model filteredModel = data.filter(resourceStream, factory.getValueFactory().createIRI(NODE_ROLE_IRI), factory.getValueFactory().createIRI(TREE_ROOT_IRI), (org.eclipse.rdf4j.model.Resource)null);
|
||||
if (filteredModel != null && filteredModel.subjects().size() == 1) {
|
||||
Optional<org.eclipse.rdf4j.model.Resource> rootResource = filteredModel.subjects().stream().findFirst();
|
||||
if (rootResource.isPresent()) {
|
||||
rootSubjectIri = rootResource.get().stringValue();
|
||||
break;
|
||||
}
|
||||
// Parse RDF content as resource
|
||||
IBaseResource viaTurtleResource = parseRdf(ourCtx, new StringReader(turtleString));
|
||||
assertNotNull(viaTurtleResource);
|
||||
|
||||
}
|
||||
// Compare original JSON-based resource against RDF-based resource
|
||||
String viaTurtleJson = serializeJson(ourCtx, viaTurtleResource);
|
||||
if (!((Base)viaTurtleResource).equalsDeep((Base)referenceResource)) {
|
||||
String failMessage = referenceFileName + ": failed to round-trip Turtle ";
|
||||
if (referenceJson.equals(viaTurtleJson))
|
||||
throw new Error(failMessage
|
||||
+ "\nttl: " + turtleString
|
||||
+ "\nexp: " + referenceJson);
|
||||
else
|
||||
assertEquals(referenceJson, viaTurtleJson, failMessage + "\nttl: " + turtleString);
|
||||
}
|
||||
}
|
||||
|
||||
// create the graph
|
||||
Graph dataGraph = factory.asGraph(data);
|
||||
|
||||
// choose focus node and shapelabel
|
||||
IRI focusNode = factory.createIRI(rootSubjectIri);
|
||||
Label shapeLabel = new Label(factory.createIRI(FHIR_SHAPE_PREFIX + resourceType));
|
||||
|
||||
ValidationAlgorithm validation = new RecursiveValidation(fhirSchema, dataGraph);
|
||||
validation.validate(focusNode, shapeLabel);
|
||||
boolean result = validation.getTyping().isConformant(focusNode, shapeLabel);
|
||||
assertTrue(result);
|
||||
|
||||
// Parse RDF content as resource
|
||||
IBaseResource parsedResource = ourCtx.newRDFParser().parseResource(new StringReader(rdfContent));
|
||||
assertNotNull(parsedResource);
|
||||
|
||||
// Compare original JSON-based resource against RDF-based resource
|
||||
if (parsedResource instanceof DomainResource) {
|
||||
// This is a hack because this initializes the collection if it is empty
|
||||
((DomainResource) parsedResource).getContained();
|
||||
boolean deepEquals = ((Base)parsedResource).equalsDeep((Base)resource);
|
||||
assertTrue(deepEquals);
|
||||
} else {
|
||||
ourLog.warn("Input JSON did not yield a DomainResource");
|
||||
String gotString = serializeJson(ourCtx, viaJsonResource);
|
||||
String skipMessage = referenceFileName + ": failed to round-trip JSON" +
|
||||
(referenceJson.equals(gotString)
|
||||
? "\ngot: " + gotString + "\nexp: " + referenceJson
|
||||
: "\nsome inequality not visible in: " + referenceJson);
|
||||
System.out.println(referenceFileName + " skipped");
|
||||
// Specific messages are printed at end of run.
|
||||
jsonRoundTripErrors.add(skipMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,11 +122,98 @@ public class RDFParserTest extends BaseTest {
|
|||
List<String> resourceList = new ArrayList<>();
|
||||
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(cl);
|
||||
Resource[] resources = resolver.getResources("classpath:rdf-test-input/*.json") ;
|
||||
for (Resource resource: resources){
|
||||
for (Resource resource: resources)
|
||||
resourceList.add(resource.getFile().getPath());
|
||||
}
|
||||
|
||||
return resourceList.stream();
|
||||
}
|
||||
|
||||
// JSON functions
|
||||
public IBaseResource parseJson(InputStream inputStream) {
|
||||
IParser refParser = ourCtx.newJsonParser();
|
||||
refParser.setStripVersionsFromReferences(false);
|
||||
// parser.setDontStripVersionsFromReferencesAtPaths();
|
||||
IBaseResource ret = refParser.parseResource(inputStream);
|
||||
assertNotNull(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public String serializeJson(FhirContext ctx, IBaseResource resource) {
|
||||
IParser jsonParser = ctx.newJsonParser();
|
||||
jsonParser.setStripVersionsFromReferences(false);
|
||||
String ret = jsonParser.encodeResourceToString(resource);
|
||||
assertNotNull(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Rdf (Turtle) functions
|
||||
public IBaseResource parseRdf(FhirContext ctx, StringReader inputStream) {
|
||||
IParser refParser = ctx.newRDFParser();
|
||||
IBaseResource ret = refParser.parseResource(inputStream);
|
||||
assertNotNull(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public String serializeRdf(FhirContext ctx, IBaseResource resource) {
|
||||
IParser rdfParser = ourCtx.newRDFParser();
|
||||
rdfParser.setStripVersionsFromReferences(false);
|
||||
rdfParser.setServerBaseUrl("http://a.example/fhir/");
|
||||
String ret = rdfParser.encodeResourceToString(resource);
|
||||
assertNotNull(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void validateRdf(String rdfContent, String referenceFileName, IBaseResource referenceResource) throws IOException {
|
||||
String baseIRI = "http://a.example/shex/";
|
||||
RDF4J factory = new RDF4J();
|
||||
GlobalFactory.RDFFactory = factory; //set the global factory used in shexjava
|
||||
Model data = Rio.parse(new StringReader(rdfContent), baseIRI, RDFFormat.TURTLE);
|
||||
FixedShapeMapEntry fixedMapEntry = new FixedShapeMapEntry(factory, data, referenceResource.fhirType(), baseIRI);
|
||||
Graph dataGraph = factory.asGraph(data); // create the graph
|
||||
ValidationAlgorithm validation = new RecursiveValidation(fhirSchema, dataGraph);
|
||||
validation.validate(fixedMapEntry.node, fixedMapEntry.shape);
|
||||
boolean result = validation.getTyping().isConformant(fixedMapEntry.node, fixedMapEntry.shape);
|
||||
assertTrue(result,
|
||||
referenceFileName + ": failed to validate " + fixedMapEntry
|
||||
+ "\n" + referenceFileName
|
||||
+ "\n" + rdfContent
|
||||
);
|
||||
}
|
||||
|
||||
// Shape Expressions functions
|
||||
class FixedShapeMapEntry {
|
||||
RDFTerm node;
|
||||
Label shape;
|
||||
|
||||
FixedShapeMapEntry(RDF4J factory, Model data, String resourceType, String baseIRI) {
|
||||
String rootSubjectIri = null;
|
||||
// StmtIterator i = data.listStatements();
|
||||
for (org.eclipse.rdf4j.model.Resource resourceStream : data.subjects()) {
|
||||
// if (resourceStream instanceof SimpleIRI) {
|
||||
Model filteredModel = data.filter(resourceStream, factory.getValueFactory().createIRI(NODE_ROLE_IRI), factory.getValueFactory().createIRI(TREE_ROOT_IRI), (org.eclipse.rdf4j.model.Resource)null);
|
||||
if (filteredModel != null && filteredModel.subjects().size() == 1) {
|
||||
Optional<org.eclipse.rdf4j.model.Resource> rootResource = filteredModel.subjects().stream().findFirst();
|
||||
if (rootResource.isPresent()) {
|
||||
rootSubjectIri = rootResource.get().stringValue();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
// choose focus node and shapelabel
|
||||
this.node = rootSubjectIri.indexOf(":") == -1
|
||||
? factory.createBlankNode(rootSubjectIri)
|
||||
: factory.createIRI(rootSubjectIri);
|
||||
Label shapeLabel = new Label(factory.createIRI(FHIR_SHAPE_PREFIX + resourceType));
|
||||
// this.node = focusNode;
|
||||
this.shape = shapeLabel;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "<" + node.toString() + ">@" + shape.toPrettyString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
# Why is this disabled?
|
||||
|
||||
| file | reason |
|
||||
| - | - |
|
||||
| [bundle-response](bundle-response.json) | [entry\[0\].response.outcome.issue](bundle-response.json#L50-L61) is not in [R4 Resource](http://hl7.org/fhir/resource.html#Resource) |
|
|
@ -13267,7 +13267,7 @@ fhirvs:contact-point-use ["home" "work" "temp" "old" "mobile"]
|
|||
fhirvs:immunization-status ["completed" "entered-in-error" "not-done"]
|
||||
|
||||
# This value set includes all possible codes from BCP-13 (http://tools.ietf.org/html/bcp13)
|
||||
fhirvs:mimetypes EXTERNAL
|
||||
fhirvs:mimetypes .
|
||||
|
||||
# The use of an address.
|
||||
fhirvs:address-use ["home" "work" "temp" "old" "billing"]
|
||||
|
|
|
@ -29,6 +29,8 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta
|
|||
private BestPracticeWarningLevel myBestPracticeWarningLevel;
|
||||
private IValidationSupport myValidationSupport;
|
||||
private boolean noTerminologyChecks = false;
|
||||
private boolean noExtensibleWarnings = false;
|
||||
private boolean noBindingMsgSuppressed = false;
|
||||
private volatile VersionSpecificWorkerContextWrapper myWrappedWorkerContext;
|
||||
private boolean errorForUnknownProfiles;
|
||||
private boolean assumeValidRestReferences;
|
||||
|
@ -184,6 +186,34 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta
|
|||
noTerminologyChecks = theNoTerminologyChecks;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to {@literal true} (default is false) no extensible warnings suppressed
|
||||
*/
|
||||
public boolean isNoExtensibleWarnings() {
|
||||
return noExtensibleWarnings;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to {@literal true} (default is false) no extensible warnings is suppressed
|
||||
*/
|
||||
public void setNoExtensibleWarnings(final boolean theNoExtensibleWarnings) {
|
||||
noExtensibleWarnings = theNoExtensibleWarnings;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to {@literal true} (default is false) no binding message is suppressed
|
||||
*/
|
||||
public boolean isNoBindingMsgSuppressed() {
|
||||
return noBindingMsgSuppressed;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to {@literal true} (default is false) no binding message is suppressed
|
||||
*/
|
||||
public void setNoBindingMsgSuppressed(final boolean theNoBindingMsgSuppressed) {
|
||||
noBindingMsgSuppressed = theNoBindingMsgSuppressed;
|
||||
}
|
||||
|
||||
public List<String> getExtensionDomains() {
|
||||
return myExtensionDomains;
|
||||
}
|
||||
|
@ -198,6 +228,8 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta
|
|||
.setErrorForUnknownProfiles(isErrorForUnknownProfiles())
|
||||
.setExtensionDomains(getExtensionDomains())
|
||||
.setNoTerminologyChecks(isNoTerminologyChecks())
|
||||
.setNoExtensibleWarnings(isNoExtensibleWarnings())
|
||||
.setNoBindingMsgSuppressed(isNoBindingMsgSuppressed())
|
||||
.setValidatorResourceFetcher(getValidatorResourceFetcher())
|
||||
.setAssumeValidRestReferences(isAssumeValidRestReferences())
|
||||
.validate(wrappedWorkerContext, theValidationCtx);
|
||||
|
|
|
@ -38,6 +38,8 @@ class ValidatorWrapper {
|
|||
private boolean myErrorForUnknownProfiles;
|
||||
private boolean myNoTerminologyChecks;
|
||||
private boolean myAssumeValidRestReferences;
|
||||
private boolean myNoExtensibleWarnings;
|
||||
private boolean myNoBindingMsgSuppressed;
|
||||
private Collection<? extends String> myExtensionDomains;
|
||||
private IResourceValidator.IValidatorResourceFetcher myValidatorResourceFetcher;
|
||||
|
||||
|
@ -77,6 +79,16 @@ class ValidatorWrapper {
|
|||
return this;
|
||||
}
|
||||
|
||||
public ValidatorWrapper setNoExtensibleWarnings(boolean theNoExtensibleWarnings) {
|
||||
myNoExtensibleWarnings = theNoExtensibleWarnings;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ValidatorWrapper setNoBindingMsgSuppressed(boolean theNoBindingMsgSuppressed) {
|
||||
myNoBindingMsgSuppressed = theNoBindingMsgSuppressed;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ValidatorWrapper setExtensionDomains(Collection<? extends String> theExtensionDomains) {
|
||||
myExtensionDomains = theExtensionDomains;
|
||||
return this;
|
||||
|
@ -105,6 +117,8 @@ class ValidatorWrapper {
|
|||
v.setErrorForUnknownProfiles(myErrorForUnknownProfiles);
|
||||
v.getExtensionDomains().addAll(myExtensionDomains);
|
||||
v.setFetcher(myValidatorResourceFetcher);
|
||||
v.setNoExtensibleWarnings(myNoExtensibleWarnings);
|
||||
v.setNoBindingMsgSuppressed(myNoBindingMsgSuppressed);
|
||||
v.setAllowXsiLocation(true);
|
||||
|
||||
List<ValidationMessage> messages = new ArrayList<>();
|
||||
|
|
26
pom.xml
26
pom.xml
|
@ -531,6 +531,10 @@
|
|||
<id>basecade</id>
|
||||
<name>Anders Havn</name>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>vedion</id>
|
||||
<name>Anders Havn</name>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>zaewonyx</id>
|
||||
</developer>
|
||||
|
@ -744,7 +748,7 @@
|
|||
<jaxb_core_version>2.3.0.1</jaxb_core_version>
|
||||
<jaxb_runtime_version>2.3.1</jaxb_runtime_version>
|
||||
<jena_version>3.16.0</jena_version>
|
||||
<jersey_version>2.25.1</jersey_version>
|
||||
<jersey_version>3.0.0</jersey_version>
|
||||
<!-- 9.4.17 seems to have issues -->
|
||||
<jetty_version>9.4.35.v20201120</jetty_version>
|
||||
<jsr305_version>3.0.2</jsr305_version>
|
||||
|
@ -758,19 +762,19 @@
|
|||
<hibernate_validator_version>6.1.5.Final</hibernate_validator_version>
|
||||
<httpcore_version>4.4.13</httpcore_version>
|
||||
<httpclient_version>4.5.13</httpclient_version>
|
||||
<jackson_version>2.11.2</jackson_version>
|
||||
<jackson_version>2.12.1</jackson_version>
|
||||
<jackson_databind_version>2.11.2</jackson_databind_version>
|
||||
<maven_assembly_plugin_version>3.1.0</maven_assembly_plugin_version>
|
||||
<maven_license_plugin_version>1.8</maven_license_plugin_version>
|
||||
<resteasy_version>4.0.0.Beta3</resteasy_version>
|
||||
<ph_schematron_version>5.2.0</ph_schematron_version>
|
||||
<ph_commons_version>9.3.8</ph_commons_version>
|
||||
<ph_schematron_version>5.6.5</ph_schematron_version>
|
||||
<ph_commons_version>9.5.4</ph_commons_version>
|
||||
<plexus_compiler_api_version>2.8.8</plexus_compiler_api_version>
|
||||
<servicemix_saxon_version>9.8.0-15</servicemix_saxon_version>
|
||||
<servicemix_xmlresolver_version>1.2_5</servicemix_xmlresolver_version>
|
||||
<slf4j_version>1.7.30</slf4j_version>
|
||||
<log4j_to_slf4j_version>2.11.1</log4j_to_slf4j_version>
|
||||
<spring_version>5.3.2</spring_version>
|
||||
<spring_version>5.3.3</spring_version>
|
||||
<!-- FYI: Spring Data JPA 2.1.9 causes test failures due to unexpected cascading deletes -->
|
||||
<spring_data_version>2.4.2</spring_data_version>
|
||||
<spring_batch_version>4.2.3.RELEASE</spring_batch_version>
|
||||
|
@ -888,6 +892,12 @@
|
|||
<groupId>com.helger</groupId>
|
||||
<artifactId>ph-schematron</artifactId>
|
||||
<version>${ph_schematron_version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.helger</groupId>
|
||||
|
@ -927,7 +937,7 @@
|
|||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-collections4</artifactId>
|
||||
<version>4.3</version>
|
||||
<version>4.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
|
@ -1351,7 +1361,7 @@
|
|||
<dependency>
|
||||
<groupId>org.fusesource.jansi</groupId>
|
||||
<artifactId>jansi</artifactId>
|
||||
<version>1.18</version>
|
||||
<version>2.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish</groupId>
|
||||
|
@ -1956,7 +1966,7 @@
|
|||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.5</version>
|
||||
<version>0.8.6</version>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>ca/uhn/fhir/model/dstu2/**/*.class</exclude>
|
||||
|
|
Loading…
Reference in New Issue