mirror of
https://github.com/hapifhir/hapi-fhir.git
synced 2025-03-25 01:18:37 +00:00
UCUM Service Support (#2261)
* Added UcumServiceUtil * Removed ucum-essense.xml * Added ucum service existing test cases passed * Added more test cases * Merge branch 'master' into ft-ucum-support # Please enter a commit message to explain why this merge is necessary, # especially if it merges an updated upstream into a topic branch. # # Lines starting with '#' will be ignored, and an empty message aborts # the commit. * Added back extractReferenceParamsAsQueryTokens * Added changelog and migration script * Added length for the string type * Moved UCUM util to hapi-fhir-jpaserver-model * Renamed UCUM support to Normalized Quantity Search Support * Moved setNormalizedQuantitySearchNotSupported to AfterEach * Changed migrate task to 530 * Removed comments * Fixed in memory search issue and added more test cases * Fixed the version order * License header updates * Updated based on review comments * Updated the migration task based on review comments * Fixed RES_TYPE with type String and length 100 * Changed myParamsQuantityNormalizedPopulated type to Boolean class
This commit is contained in:
parent
88b01a3bb4
commit
f6d4a40388
@ -0,0 +1,5 @@
|
||||
---
|
||||
type: add
|
||||
issue: 2261
|
||||
title: "Optionally supports storage and search in canonical form of the quantity value which is defined by 'http://unitsofmeasure.org';
|
||||
please check ModelConfig for the configuration. No changes were made to the existing behaviour."
|
@ -92,6 +92,7 @@ import ca.uhn.fhir.jpa.search.builder.predicate.DatePredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.ForcedIdPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.NumberPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.QuantityPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.QuantityNormalizedPredicateBuilder;
|
||||
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;
|
||||
@ -551,6 +552,12 @@ public abstract class BaseConfig {
|
||||
return new QuantityPredicateBuilder(theSearchBuilder);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Scope("prototype")
|
||||
public QuantityNormalizedPredicateBuilder newQuantityNormalizedPredicateBuilder(SearchQueryBuilder theSearchBuilder) {
|
||||
return new QuantityNormalizedPredicateBuilder(theSearchBuilder);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Scope("prototype")
|
||||
public ResourceLinkPredicateBuilder newResourceLinkPredicateBuilder(QueryStack theQueryStack, SearchQueryBuilder theSearchBuilder, boolean theReversed) {
|
||||
|
@ -0,0 +1,34 @@
|
||||
package ca.uhn.fhir.jpa.dao.data;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* 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 org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
|
||||
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> {
|
||||
@Modifying
|
||||
@Query("delete from ResourceIndexedSearchParamQuantityNormalized t WHERE t.myResourcePid = :resid")
|
||||
void deleteByResourceId(@Param("resid") Long theResourcePid);
|
||||
}
|
@ -53,6 +53,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
||||
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.entity.ResourceIndexedSearchParamUri;
|
||||
@ -126,6 +127,7 @@ public class ExpungeEverythingService {
|
||||
counter.addAndGet(expungeEverythingByType(ResourceIndexedSearchParamDate.class));
|
||||
counter.addAndGet(expungeEverythingByType(ResourceIndexedSearchParamNumber.class));
|
||||
counter.addAndGet(expungeEverythingByType(ResourceIndexedSearchParamQuantity.class));
|
||||
counter.addAndGet(expungeEverythingByType(ResourceIndexedSearchParamQuantityNormalized.class));
|
||||
counter.addAndGet(expungeEverythingByType(ResourceIndexedSearchParamString.class));
|
||||
counter.addAndGet(expungeEverythingByType(ResourceIndexedSearchParamToken.class));
|
||||
counter.addAndGet(expungeEverythingByType(ResourceIndexedSearchParamUri.class));
|
||||
|
@ -33,6 +33,7 @@ import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamCoordsDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamDateDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamNumberDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamQuantityDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamQuantityNormalizedDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamStringDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamTokenDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao;
|
||||
@ -90,6 +91,8 @@ public class ResourceExpungeService implements IResourceExpungeService {
|
||||
@Autowired
|
||||
private IResourceIndexedSearchParamQuantityDao myResourceIndexedSearchParamQuantityDao;
|
||||
@Autowired
|
||||
private IResourceIndexedSearchParamQuantityNormalizedDao myResourceIndexedSearchParamQuantityNormalizedDao;
|
||||
@Autowired
|
||||
private IResourceIndexedSearchParamCoordsDao myResourceIndexedSearchParamCoordsDao;
|
||||
@Autowired
|
||||
private IResourceIndexedSearchParamNumberDao myResourceIndexedSearchParamNumberDao;
|
||||
@ -279,6 +282,9 @@ public class ResourceExpungeService implements IResourceExpungeService {
|
||||
if (resource == null || resource.isParamsQuantityPopulated()) {
|
||||
myResourceIndexedSearchParamQuantityDao.deleteByResourceId(theResourceId);
|
||||
}
|
||||
if (resource == null || resource.isParamsQuantityNormalizedPopulated()) {
|
||||
myResourceIndexedSearchParamQuantityNormalizedDao.deleteByResourceId(theResourceId);
|
||||
}
|
||||
if (resource == null || resource.isParamsStringPopulated()) {
|
||||
myResourceIndexedSearchParamStringDao.deleteByResourceId(theResourceId);
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ public class ResourceTableFKProvider {
|
||||
retval.add(new ResourceForeignKey("HFJ_SPIDX_DATE", "RES_ID"));
|
||||
retval.add(new ResourceForeignKey("HFJ_SPIDX_NUMBER", "RES_ID"));
|
||||
retval.add(new ResourceForeignKey("HFJ_SPIDX_QUANTITY", "RES_ID"));
|
||||
retval.add(new ResourceForeignKey("HFJ_SPIDX_QUANTITY_NRML", "RES_ID"));
|
||||
retval.add(new ResourceForeignKey("HFJ_SPIDX_STRING", "RES_ID"));
|
||||
retval.add(new ResourceForeignKey("HFJ_SPIDX_TOKEN", "RES_ID"));
|
||||
retval.add(new ResourceForeignKey("HFJ_SPIDX_URI", "RES_ID"));
|
||||
|
@ -56,6 +56,7 @@ public class DaoSearchParamSynchronizer {
|
||||
synchronize(theEntity, retVal, theParams.myTokenParams, existingParams.myTokenParams);
|
||||
synchronize(theEntity, retVal, theParams.myNumberParams, existingParams.myNumberParams);
|
||||
synchronize(theEntity, retVal, theParams.myQuantityParams, existingParams.myQuantityParams);
|
||||
synchronize(theEntity, retVal, theParams.myQuantityNormalizedParams, existingParams.myQuantityNormalizedParams);
|
||||
synchronize(theEntity, retVal, theParams.myDateParams, existingParams.myDateParams);
|
||||
synchronize(theEntity, retVal, theParams.myUriParams, existingParams.myUriParams);
|
||||
synchronize(theEntity, retVal, theParams.myCoordsParams, existingParams.myCoordsParams);
|
||||
@ -87,6 +88,7 @@ public class DaoSearchParamSynchronizer {
|
||||
for (T next : paramsToRemove) {
|
||||
myEntityManager.remove(next);
|
||||
theEntity.getParamsQuantity().remove(next);
|
||||
theEntity.getParamsQuantityNormalized().remove(next);
|
||||
}
|
||||
for (T next : paramsToAdd) {
|
||||
myEntityManager.merge(next);
|
||||
|
@ -1,6 +1,6 @@
|
||||
package ca.uhn.fhir.jpa.search.builder;
|
||||
|
||||
/*-
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
@ -38,7 +38,7 @@ import ca.uhn.fhir.jpa.search.builder.predicate.CoordsPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.DatePredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.ForcedIdPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.NumberPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.QuantityPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.QuantityBasePredicateBuilder;
|
||||
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;
|
||||
@ -185,7 +185,14 @@ public class QueryStack {
|
||||
|
||||
public void addSortOnQuantity(String theResourceName, String theParamName, boolean theAscending) {
|
||||
BaseJoiningPredicateBuilder firstPredicateBuilder = mySqlBuilder.getOrCreateFirstPredicateBuilder();
|
||||
QuantityPredicateBuilder sortPredicateBuilder = mySqlBuilder.addQuantityPredicateBuilder(firstPredicateBuilder.getResourceIdColumn());
|
||||
|
||||
QuantityBasePredicateBuilder sortPredicateBuilder = null;
|
||||
if (myModelConfig.isNormalizedQuantitySearchSupported()) {
|
||||
sortPredicateBuilder = mySqlBuilder.addQuantityNormalizedPredicateBuilder(firstPredicateBuilder.getResourceIdColumn());
|
||||
} else {
|
||||
sortPredicateBuilder = mySqlBuilder.addQuantityPredicateBuilder(firstPredicateBuilder.getResourceIdColumn());
|
||||
|
||||
}
|
||||
|
||||
Condition hashIdentityPredicate = sortPredicateBuilder.createHashIdentityPredicate(theResourceName, theParamName);
|
||||
mySqlBuilder.addPredicate(hashIdentityPredicate);
|
||||
@ -635,9 +642,14 @@ public class QueryStack {
|
||||
List<? extends IQueryParameterType> theList,
|
||||
SearchFilterParser.CompareOperation theOperation,
|
||||
RequestPartitionId theRequestPartitionId) {
|
||||
|
||||
QuantityPredicateBuilder join = createOrReusePredicateBuilder(PredicateBuilderTypeEnum.QUANTITY, theSourceJoinColumn, theSearchParam.getName(), () -> mySqlBuilder.addQuantityPredicateBuilder(theSourceJoinColumn)).getResult();
|
||||
|
||||
|
||||
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) {
|
||||
return join.createPredicateParamMissingForNonReference(theResourceName, theSearchParam.getName(), theList.get(0).getMissing(), theRequestPartitionId);
|
||||
}
|
||||
@ -911,7 +923,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;
|
||||
}
|
||||
@ -1042,6 +1054,7 @@ public class QueryStack {
|
||||
return toAndPredicate(andPredicates);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void addPredicateCompositeUnique(String theIndexString, RequestPartitionId theRequestPartitionId) {
|
||||
|
@ -0,0 +1,131 @@
|
||||
package ca.uhn.fhir.jpa.search.builder.predicate;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* 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 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;
|
||||
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;
|
||||
|
||||
|
||||
public abstract class QuantityBasePredicateBuilder extends BaseSearchParamPredicateBuilder {
|
||||
|
||||
protected DbColumn myColumnHashIdentitySystemUnits;
|
||||
protected DbColumn myColumnHashIdentityUnits;
|
||||
protected DbColumn myColumnValue;
|
||||
|
||||
@Autowired
|
||||
private FhirContext myFhirContext;
|
||||
|
||||
@Autowired
|
||||
private ModelConfig myModelConfig;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public QuantityBasePredicateBuilder(SearchQueryBuilder theSearchSqlBuilder, DbTable theTable) {
|
||||
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;
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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);
|
||||
hashPredicate = BinaryCondition.equalTo(myColumnHashIdentitySystemUnits, generatePlaceholder(hash));
|
||||
} else if (!isBlank(unitsValue)) {
|
||||
long hash = ResourceIndexedSearchParamBaseQuantity.calculateHashUnits(getPartitionSettings(), theRequestPartitionId, theResourceName, theParamName, unitsValue);
|
||||
hashPredicate = BinaryCondition.equalTo(myColumnHashIdentityUnits, generatePlaceholder(hash));
|
||||
} else {
|
||||
long hash = BaseResourceIndexedSearchParam.calculateHashIdentity(getPartitionSettings(), theRequestPartitionId, theResourceName, theParamName);
|
||||
hashPredicate = BinaryCondition.equalTo(getColumnHashIdentity(), generatePlaceholder(hash));
|
||||
}
|
||||
|
||||
SearchFilterParser.CompareOperation operation = theOperation;
|
||||
if (operation == null && cmpValue != null) {
|
||||
operation = QueryStack.toOperation(cmpValue);
|
||||
}
|
||||
operation = defaultIfNull(operation, SearchFilterParser.CompareOperation.eq);
|
||||
Condition numericPredicate = NumberPredicateBuilder.createPredicateNumeric(this, operation, valueValue, myColumnValue, "invalidQuantityPrefix", myFhirContext, theParam);
|
||||
|
||||
return ComboCondition.and(hashPredicate, numericPredicate);
|
||||
}
|
||||
|
||||
public DbColumn getColumnValue() {
|
||||
return myColumnValue;
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package ca.uhn.fhir.jpa.search.builder.predicate;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* 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.jpa.search.builder.sql.SearchQueryBuilder;
|
||||
|
||||
public class QuantityNormalizedPredicateBuilder extends QuantityBasePredicateBuilder {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public QuantityNormalizedPredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) {
|
||||
super(theSearchSqlBuilder, theSearchSqlBuilder.addTable("HFJ_SPIDX_QUANTITY_NRML"));
|
||||
|
||||
myColumnHashIdentitySystemUnits = getTable().addColumn("HASH_IDENTITY_SYS_UNITS");
|
||||
myColumnHashIdentityUnits = getTable().addColumn("HASH_IDENTITY_AND_UNITS");
|
||||
myColumnValue = getTable().addColumn("SP_VALUE");
|
||||
}
|
||||
|
||||
}
|
@ -20,96 +20,20 @@ package ca.uhn.fhir.jpa.search.builder.predicate;
|
||||
* #L%
|
||||
*/
|
||||
|
||||
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.search.builder.QueryStack;
|
||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
|
||||
import ca.uhn.fhir.jpa.search.builder.sql.SearchQueryBuilder;
|
||||
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 com.healthmarketscience.sqlbuilder.BinaryCondition;
|
||||
import com.healthmarketscience.sqlbuilder.ComboCondition;
|
||||
import com.healthmarketscience.sqlbuilder.Condition;
|
||||
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import java.math.BigDecimal;
|
||||
public class QuantityPredicateBuilder extends QuantityBasePredicateBuilder {
|
||||
|
||||
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
public class QuantityPredicateBuilder extends BaseSearchParamPredicateBuilder {
|
||||
|
||||
private final DbColumn myColumnHashIdentitySystemUnits;
|
||||
private final DbColumn myColumnHashIdentityUnits;
|
||||
private final DbColumn myColumnValue;
|
||||
@Autowired
|
||||
private FhirContext myFhirContext;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public QuantityPredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) {
|
||||
super(theSearchSqlBuilder, theSearchSqlBuilder.addTable("HFJ_SPIDX_QUANTITY"));
|
||||
|
||||
|
||||
myColumnHashIdentitySystemUnits = getTable().addColumn("HASH_IDENTITY_SYS_UNITS");
|
||||
myColumnHashIdentityUnits = getTable().addColumn("HASH_IDENTITY_AND_UNITS");
|
||||
myColumnValue = getTable().addColumn("SP_VALUE");
|
||||
}
|
||||
|
||||
|
||||
public Condition createPredicateQuantity(IQueryParameterType theParam, String theResourceName, String theParamName, CriteriaBuilder theBuilder, QuantityPredicateBuilder theFrom, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) {
|
||||
|
||||
String systemValue;
|
||||
String unitsValue;
|
||||
ParamPrefixEnum cmpValue;
|
||||
BigDecimal valueValue;
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
Condition hashPredicate;
|
||||
if (!isBlank(systemValue) && !isBlank(unitsValue)) {
|
||||
long hash = ResourceIndexedSearchParamQuantity.calculateHashSystemAndUnits(getPartitionSettings(), theRequestPartitionId, theResourceName, theParamName, systemValue, unitsValue);
|
||||
hashPredicate = BinaryCondition.equalTo(myColumnHashIdentitySystemUnits, generatePlaceholder(hash));
|
||||
} else if (!isBlank(unitsValue)) {
|
||||
long hash = ResourceIndexedSearchParamQuantity.calculateHashUnits(getPartitionSettings(), theRequestPartitionId, theResourceName, theParamName, unitsValue);
|
||||
hashPredicate = BinaryCondition.equalTo(myColumnHashIdentityUnits, generatePlaceholder(hash));
|
||||
} else {
|
||||
long hash = BaseResourceIndexedSearchParam.calculateHashIdentity(getPartitionSettings(), theRequestPartitionId, theResourceName, theParamName);
|
||||
hashPredicate = BinaryCondition.equalTo(getColumnHashIdentity(), generatePlaceholder(hash));
|
||||
}
|
||||
|
||||
SearchFilterParser.CompareOperation operation = theOperation;
|
||||
if (operation == null && cmpValue != null) {
|
||||
operation = QueryStack.toOperation(cmpValue);
|
||||
}
|
||||
operation = defaultIfNull(operation, SearchFilterParser.CompareOperation.eq);
|
||||
Condition numericPredicate = NumberPredicateBuilder.createPredicateNumeric(this, operation, valueValue, myColumnValue, "invalidQuantityPrefix", myFhirContext, theParam);
|
||||
|
||||
return ComboCondition.and(hashPredicate, numericPredicate);
|
||||
}
|
||||
|
||||
|
||||
public DbColumn getColumnValue() {
|
||||
return myColumnValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ import ca.uhn.fhir.jpa.search.builder.predicate.DatePredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.ForcedIdPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.NumberPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.QuantityPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.QuantityNormalizedPredicateBuilder;
|
||||
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;
|
||||
@ -201,11 +202,21 @@ public class SearchQueryBuilder {
|
||||
* Add and return a predicate builder (or a root query if no root query exists yet) for selecting on a QUANTITY search parameter
|
||||
*/
|
||||
public QuantityPredicateBuilder addQuantityPredicateBuilder(@Nullable DbColumn theSourceJoinColumn) {
|
||||
|
||||
QuantityPredicateBuilder retVal = mySqlBuilderFactory.quantityIndexTable(this);
|
||||
addTable(retVal, theSourceJoinColumn);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public QuantityNormalizedPredicateBuilder addQuantityNormalizedPredicateBuilder(@Nullable DbColumn theSourceJoinColumn) {
|
||||
|
||||
QuantityNormalizedPredicateBuilder retVal = mySqlBuilderFactory.quantityNormalizedIndexTable(this);
|
||||
addTable(retVal, theSourceJoinColumn);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add and return a predicate builder (or a root query if no root query exists yet) for selecting on a <code>_source</code> search parameter
|
||||
*/
|
||||
|
@ -27,6 +27,7 @@ import ca.uhn.fhir.jpa.search.builder.predicate.DatePredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.ForcedIdPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.NumberPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.QuantityPredicateBuilder;
|
||||
import ca.uhn.fhir.jpa.search.builder.predicate.QuantityNormalizedPredicateBuilder;
|
||||
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;
|
||||
@ -68,6 +69,10 @@ public class SqlObjectFactory {
|
||||
return myApplicationContext.getBean(QuantityPredicateBuilder.class, theSearchSqlBuilder);
|
||||
}
|
||||
|
||||
public QuantityNormalizedPredicateBuilder quantityNormalizedIndexTable(SearchQueryBuilder theSearchSqlBuilder) {
|
||||
return myApplicationContext.getBean(QuantityNormalizedPredicateBuilder.class, theSearchSqlBuilder);
|
||||
}
|
||||
|
||||
public ResourceLinkPredicateBuilder referenceIndexTable(QueryStack theQueryStack, SearchQueryBuilder theSearchSqlBuilder, boolean theReversed) {
|
||||
return myApplicationContext.getBean(ResourceLinkPredicateBuilder.class, theQueryStack, theSearchSqlBuilder, theReversed);
|
||||
}
|
||||
|
@ -488,6 +488,10 @@ public class ResourceReindexingSvcImpl implements IResourceReindexingSvc {
|
||||
q.setParameter("id", theId);
|
||||
q.executeUpdate();
|
||||
|
||||
q = myEntityManager.createQuery("DELETE FROM ResourceIndexedSearchParamQuantityNormalized t WHERE t.myResourcePid = :id");
|
||||
q.setParameter("id", theId);
|
||||
q.executeUpdate();
|
||||
|
||||
q = myEntityManager.createQuery("DELETE FROM ResourceIndexedSearchParamString t WHERE t.myResourcePid = :id");
|
||||
q.setParameter("id", theId);
|
||||
q.executeUpdate();
|
||||
|
@ -4,7 +4,7 @@ package ca.uhn.fhir.jpa.dao.dstu3;
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* 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.
|
||||
|
@ -29,6 +29,7 @@ import ca.uhn.fhir.jpa.dao.data.IResourceIndexedCompositeStringUniqueDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamCoordsDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamDateDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamQuantityDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamQuantityNormalizedDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamStringDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamTokenDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceLinkDao;
|
||||
@ -222,6 +223,8 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil
|
||||
@Autowired
|
||||
protected IResourceIndexedSearchParamQuantityDao myResourceIndexedSearchParamQuantityDao;
|
||||
@Autowired
|
||||
protected IResourceIndexedSearchParamQuantityNormalizedDao myResourceIndexedSearchParamQuantityNormalizedDao;
|
||||
@Autowired
|
||||
protected IResourceIndexedSearchParamDateDao myResourceIndexedSearchParamDateDao;
|
||||
@Autowired
|
||||
protected IResourceIndexedCompositeStringUniqueDao myResourceIndexedCompositeStringUniqueDao;
|
||||
|
@ -4,7 +4,7 @@ package ca.uhn.fhir.jpa.dao.r4;
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* 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.
|
||||
|
@ -1,33 +1,5 @@
|
||||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
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.util.TestUtil;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.DateType;
|
||||
import org.hl7.fhir.r4.model.Enumerations;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
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.SampledData;
|
||||
import org.hl7.fhir.r4.model.SearchParameter;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
@ -36,6 +8,41 @@ 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 org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.DateType;
|
||||
import org.hl7.fhir.r4.model.DecimalType;
|
||||
import org.hl7.fhir.r4.model.Enumerations;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
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.SampledData;
|
||||
import org.hl7.fhir.r4.model.SearchParameter;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
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;
|
||||
|
||||
public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoR4CreateTest.class);
|
||||
|
||||
@ -44,6 +51,7 @@ public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
||||
myDaoConfig.setResourceServerIdStrategy(new DaoConfig().getResourceServerIdStrategy());
|
||||
myDaoConfig.setResourceClientIdStrategy(new DaoConfig().getResourceClientIdStrategy());
|
||||
myDaoConfig.setDefaultSearchParamsCanBeOverridden(new DaoConfig().isDefaultSearchParamsCanBeOverridden());
|
||||
myModelConfig.setNormalizedQuantitySearchNotSupported();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -71,7 +79,6 @@ public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
||||
map.setLoadSynchronous(true);
|
||||
map.add(Patient.SP_GIVEN, new StringParam("수")); // rightmost character only
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), empty());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -329,6 +336,150 @@ public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
Observation obs = new Observation();
|
||||
obs.setStatus(Observation.ObservationStatus.FINAL);
|
||||
Quantity q = new Quantity();
|
||||
q.setValueElement(new DecimalType(1.2));
|
||||
q.setUnit("CM");
|
||||
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)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithNormalizedQuantitySearchSupportedWithVerySmallNumber() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
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));
|
||||
|
||||
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());
|
||||
|
||||
assertEquals(1, ids.size());
|
||||
|
||||
ourLog.info("Observation2: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(resources.get(0)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithNormalizedQuantitySearchSupportedWithVerySmallNumber2() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
Observation obs = new Observation();
|
||||
obs.setStatus(Observation.ObservationStatus.FINAL);
|
||||
Quantity q = new Quantity();
|
||||
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());
|
||||
|
||||
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());
|
||||
|
||||
assertEquals(1, ids.size());
|
||||
|
||||
ourLog.info("Observation2: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(resources.get(0)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithNormalizedQuantitySearchSupportedWithLargeNumber() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
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());
|
||||
|
||||
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());
|
||||
|
||||
assertEquals(1, ids.size());
|
||||
|
||||
ourLog.info("Observation2: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(resources.get(0)));
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -86,6 +86,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
||||
@AfterEach
|
||||
public void after() {
|
||||
myDaoConfig.setValidateSearchParameterExpressionsOnSave(new DaoConfig().isValidateSearchParameterExpressionsOnSave());
|
||||
myModelConfig.setNormalizedQuantitySearchNotSupported();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
@ -97,6 +98,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
||||
|
||||
@Test
|
||||
public void testStoreSearchParamWithBracketsInExpression() {
|
||||
|
||||
myDaoConfig.setMarkResourcesForReindexingUponSearchParameterChange(true);
|
||||
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
@ -113,6 +115,47 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoreSearchParamWithBracketsInExpressionNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
myDaoConfig.setMarkResourcesForReindexingUponSearchParameterChange(true);
|
||||
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.setCode("foo");
|
||||
fooSp.addBase("ActivityDefinition");
|
||||
fooSp.setType(Enumerations.SearchParamType.REFERENCE);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setExpression("(ActivityDefinition.useContext.value as Quantity) | (ActivityDefinition.useContext.value as Range)");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
|
||||
// Ensure that no exceptions are thrown
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoreSearchParamWithBracketsInExpressionNormalizedQuantityStorageSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantityStorageSupported();
|
||||
myDaoConfig.setMarkResourcesForReindexingUponSearchParameterChange(true);
|
||||
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.setCode("foo");
|
||||
fooSp.addBase("ActivityDefinition");
|
||||
fooSp.setType(Enumerations.SearchParamType.REFERENCE);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setExpression("(ActivityDefinition.useContext.value as Quantity) | (ActivityDefinition.useContext.value as Range)");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
|
||||
// Ensure that no exceptions are thrown
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* See #2023
|
||||
*/
|
||||
|
@ -11,6 +11,7 @@ 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.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
@ -30,6 +31,11 @@ public class FhirResourceDaoR4SearchMissingTest extends BaseJpaR4Test {
|
||||
public void beforeResetMissing() {
|
||||
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void afterResetSearch() {
|
||||
myModelConfig.setNormalizedQuantitySearchNotSupported();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexMissingFieldsDisabledDontAllowInSearch_NonReference() {
|
||||
@ -72,6 +78,40 @@ public class FhirResourceDaoR4SearchMissingTest extends BaseJpaR4Test {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexMissingFieldsDisabledDontCreateIndexesWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.DISABLED);
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
Organization org = new Organization();
|
||||
org.setActive(true);
|
||||
myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
assertThat(mySearchParamPresentDao.findAll(), empty());
|
||||
assertThat(myResourceIndexedSearchParamStringDao.findAll(), empty());
|
||||
assertThat(myResourceIndexedSearchParamDateDao.findAll(), empty());
|
||||
assertThat(myResourceIndexedSearchParamTokenDao.findAll(), hasSize(1));
|
||||
assertThat(myResourceIndexedSearchParamQuantityDao.findAll(), empty());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexMissingFieldsDisabledDontCreateIndexesWithNormalizedQuantityStorageSupported() {
|
||||
|
||||
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.DISABLED);
|
||||
myModelConfig.setNormalizedQuantityStorageSupported();
|
||||
Organization org = new Organization();
|
||||
org.setActive(true);
|
||||
myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
assertThat(mySearchParamPresentDao.findAll(), empty());
|
||||
assertThat(myResourceIndexedSearchParamStringDao.findAll(), empty());
|
||||
assertThat(myResourceIndexedSearchParamDateDao.findAll(), empty());
|
||||
assertThat(myResourceIndexedSearchParamTokenDao.findAll(), hasSize(1));
|
||||
assertThat(myResourceIndexedSearchParamQuantityDao.findAll(), empty());
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void testSearchResourceReferenceMissingChain() {
|
||||
@ -267,6 +307,89 @@ public class FhirResourceDaoR4SearchMissingTest extends BaseJpaR4Test {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithMissingQuantityWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
IIdType notMissing;
|
||||
IIdType missing;
|
||||
{
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("001");
|
||||
missing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
{
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("002");
|
||||
obs.setValue(new Quantity(123));
|
||||
notMissing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
// Quantity Param
|
||||
{
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronous(true);
|
||||
QuantityParam param = new QuantityParam();
|
||||
param.setMissing(false);
|
||||
params.add(Observation.SP_VALUE_QUANTITY, param);
|
||||
List<IIdType> patients = toUnqualifiedVersionlessIds(myObservationDao.search(params));
|
||||
assertThat(patients, not(containsInRelativeOrder(missing)));
|
||||
assertThat(patients, containsInRelativeOrder(notMissing));
|
||||
}
|
||||
{
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronous(true);
|
||||
QuantityParam param = new QuantityParam();
|
||||
param.setMissing(true);
|
||||
params.add(Observation.SP_VALUE_QUANTITY, param);
|
||||
List<IIdType> patients = toUnqualifiedVersionlessIds(myObservationDao.search(params));
|
||||
assertThat(patients, containsInRelativeOrder(missing));
|
||||
assertThat(patients, not(containsInRelativeOrder(notMissing)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithMissingQuantityWithNormalizedQuantityStorageSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantityStorageSupported();
|
||||
IIdType notMissing;
|
||||
IIdType missing;
|
||||
{
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("001");
|
||||
missing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
{
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("002");
|
||||
obs.setValue(new Quantity(123));
|
||||
notMissing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
// Quantity Param
|
||||
{
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronous(true);
|
||||
QuantityParam param = new QuantityParam();
|
||||
param.setMissing(false);
|
||||
params.add(Observation.SP_VALUE_QUANTITY, param);
|
||||
List<IIdType> patients = toUnqualifiedVersionlessIds(myObservationDao.search(params));
|
||||
assertThat(patients, not(containsInRelativeOrder(missing)));
|
||||
assertThat(patients, containsInRelativeOrder(notMissing));
|
||||
}
|
||||
{
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronous(true);
|
||||
QuantityParam param = new QuantityParam();
|
||||
param.setMissing(true);
|
||||
params.add(Observation.SP_VALUE_QUANTITY, param);
|
||||
List<IIdType> patients = toUnqualifiedVersionlessIds(myObservationDao.search(params));
|
||||
assertThat(patients, containsInRelativeOrder(missing));
|
||||
assertThat(patients, not(containsInRelativeOrder(notMissing)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchWithMissingReference() {
|
||||
IIdType orgId = myOrganizationDao.create(new Organization(), mySrd).getId().toUnqualifiedVersionless();
|
||||
|
@ -1,58 +1,39 @@
|
||||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
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.entity.Search;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap.EverythingModeEnum;
|
||||
import ca.uhn.fhir.jpa.util.SqlQuery;
|
||||
import ca.uhn.fhir.jpa.util.TestUtil;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.CompositeParam;
|
||||
import ca.uhn.fhir.rest.param.DateParam;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import ca.uhn.fhir.rest.param.HasAndListParam;
|
||||
import ca.uhn.fhir.rest.param.HasOrListParam;
|
||||
import ca.uhn.fhir.rest.param.HasParam;
|
||||
import ca.uhn.fhir.rest.param.NumberParam;
|
||||
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
|
||||
import ca.uhn.fhir.rest.param.QuantityParam;
|
||||
import ca.uhn.fhir.rest.param.ReferenceAndListParam;
|
||||
import ca.uhn.fhir.rest.param.ReferenceOrListParam;
|
||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||
import ca.uhn.fhir.rest.param.StringAndListParam;
|
||||
import ca.uhn.fhir.rest.param.StringOrListParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
||||
import ca.uhn.fhir.rest.param.TokenOrListParam;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.param.TokenParamModifier;
|
||||
import ca.uhn.fhir.rest.param.UriParam;
|
||||
import ca.uhn.fhir.rest.param.UriParamQualifierEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
||||
import ca.uhn.fhir.util.HapiExtensions;
|
||||
import com.google.common.collect.Lists;
|
||||
import static ca.uhn.fhir.rest.api.Constants.PARAM_TYPE;
|
||||
import static org.apache.commons.lang3.StringUtils.countMatches;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.endsWith;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.hasItems;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
@ -134,38 +115,61 @@ import org.springframework.transaction.support.TransactionCallback;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import static ca.uhn.fhir.rest.api.Constants.PARAM_TYPE;
|
||||
import static org.apache.commons.lang3.StringUtils.countMatches;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.endsWith;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.hasItems;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
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.entity.Search;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
||||
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.entity.ResourceIndexedSearchParamUri;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap.EverythingModeEnum;
|
||||
import ca.uhn.fhir.jpa.util.SqlQuery;
|
||||
import ca.uhn.fhir.jpa.util.TestUtil;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.CompositeParam;
|
||||
import ca.uhn.fhir.rest.param.DateParam;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import ca.uhn.fhir.rest.param.HasAndListParam;
|
||||
import ca.uhn.fhir.rest.param.HasOrListParam;
|
||||
import ca.uhn.fhir.rest.param.HasParam;
|
||||
import ca.uhn.fhir.rest.param.NumberParam;
|
||||
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
|
||||
import ca.uhn.fhir.rest.param.QuantityParam;
|
||||
import ca.uhn.fhir.rest.param.ReferenceAndListParam;
|
||||
import ca.uhn.fhir.rest.param.ReferenceOrListParam;
|
||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||
import ca.uhn.fhir.rest.param.StringAndListParam;
|
||||
import ca.uhn.fhir.rest.param.StringOrListParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
||||
import ca.uhn.fhir.rest.param.TokenOrListParam;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.param.TokenParamModifier;
|
||||
import ca.uhn.fhir.rest.param.UriParam;
|
||||
import ca.uhn.fhir.rest.param.UriParamQualifierEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
||||
import ca.uhn.fhir.util.HapiExtensions;
|
||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||
|
||||
@SuppressWarnings({"unchecked", "Duplicates"})
|
||||
public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||
@ -181,6 +185,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||
myDaoConfig.setAllowContainsSearches(new DaoConfig().isAllowContainsSearches());
|
||||
myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds());
|
||||
myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields());
|
||||
myModelConfig.setNormalizedQuantitySearchNotSupported();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
@ -1217,11 +1222,139 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||
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(0, results.size());
|
||||
});
|
||||
|
||||
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
||||
mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 123, "http://foo", "UNIT"))));
|
||||
assertThat(actual, contains(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexNoDuplicatesQuantityWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
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);
|
||||
res.addInstance().getQuantity().setSystem("http://foo2").setCode("UNIT2").setValue(1232);
|
||||
res.addInstance().getQuantity().setSystem("http://foo2").setCode("UNIT2").setValue(1232);
|
||||
|
||||
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));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuantityWithNormalizedQuantitySearchSupported_InvalidUCUMCode() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
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"))));
|
||||
assertThat(actual, contains(id));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuantityWithNormalizedQuantitySearchSupported_NotUCUM() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
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));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexNoDuplicatesQuantityWithNormalizedQuantityStorageSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantityStorageSupported();
|
||||
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);
|
||||
res.addInstance().getQuantity().setSystem("http://foo2").setCode("UNIT2").setValue(1232);
|
||||
res.addInstance().getQuantity().setSystem("http://foo2").setCode("UNIT2").setValue(1232);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexNoDuplicatesReference() {
|
||||
ServiceRequest pr = new ServiceRequest();
|
||||
@ -2618,7 +2751,32 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchByMoneyParamWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
ChargeItem ci = new ChargeItem();
|
||||
ci.getPriceOverride().setValue(123).setCurrency("$");
|
||||
|
||||
myChargeItemDao.create(ci);
|
||||
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.setLoadSynchronous(true);
|
||||
map.add(ChargeItem.SP_PRICE_OVERRIDE, new QuantityParam().setValue(123));
|
||||
assertEquals(1, myChargeItemDao.search(map).size().intValue());
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.setLoadSynchronous(true);
|
||||
map.add(ChargeItem.SP_PRICE_OVERRIDE, new QuantityParam().setValue(123).setUnits("$"));
|
||||
assertEquals(1, myChargeItemDao.search(map).size().intValue());
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.setLoadSynchronous(true);
|
||||
map.add(ChargeItem.SP_PRICE_OVERRIDE, new QuantityParam().setValue(123).setUnits("$").setSystem("urn:iso:std:iso:4217"));
|
||||
assertEquals(1, myChargeItemDao.search(map).size().intValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchNameParam() {
|
||||
IIdType id1;
|
||||
@ -2959,6 +3117,30 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchQuantityWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
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();
|
||||
|
||||
Condition c2 = new Condition();
|
||||
c2.setOnset(new Range().setLow(new SimpleQuantity().setValue(1L)).setHigh(new SimpleQuantity().setValue(1L)));
|
||||
String id2 = myConditionDao.create(c2).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
{
|
||||
IBundleProvider found = myConditionDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Condition.SP_ABATEMENT_AGE, new QuantityParam("1")));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(found), containsInAnyOrder(id1));
|
||||
assertEquals(1, found.size().intValue());
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myConditionDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Condition.SP_ONSET_AGE, new QuantityParam("1")));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(found), containsInAnyOrder(id2));
|
||||
assertEquals(1, found.size().intValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchResourceLinkOnCanonical() {
|
||||
|
||||
|
@ -42,6 +42,8 @@ import ca.uhn.fhir.rest.param.UriParam;
|
||||
import ca.uhn.fhir.rest.param.UriParamQualifierEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
@ -141,6 +143,7 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
||||
myDaoConfig.setFetchSizeDefaultMaximum(new DaoConfig().getFetchSizeDefaultMaximum());
|
||||
myDaoConfig.setAllowContainsSearches(new DaoConfig().isAllowContainsSearches());
|
||||
myDaoConfig.setDisableHashBasedSearches(false);
|
||||
myModelConfig.setNormalizedQuantitySearchNotSupported();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
@ -1188,6 +1191,52 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComponentQuantityWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
Observation o1 = new Observation();
|
||||
o1.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm")))
|
||||
.setValue(new Quantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm").setValue(1.2));
|
||||
o1.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("m")))
|
||||
.setValue(new Quantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("mm").setValue(2));
|
||||
IIdType id1 = myObservationDao.create(o1, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
String param = Observation.SP_COMPONENT_VALUE_QUANTITY;
|
||||
|
||||
{
|
||||
QuantityParam v1 = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, 0.012, UcumServiceUtil.UCUM_CODESYSTEM_URL, "m");
|
||||
SearchParameterMap map = new SearchParameterMap().setLoadSynchronous(true).add(param, v1);
|
||||
IBundleProvider result = myObservationDao.search(map);
|
||||
assertThat("Got: " + toUnqualifiedVersionlessIdValues(result), toUnqualifiedVersionlessIdValues(result), containsInAnyOrder(id1.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComponentQuantityWithNormalizedQuantityStorageSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantityStorageSupported();
|
||||
Observation o1 = new Observation();
|
||||
o1.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm")))
|
||||
.setValue(new Quantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm").setValue(1.2));
|
||||
o1.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("m")))
|
||||
.setValue(new Quantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("mm").setValue(2));
|
||||
IIdType id1 = myObservationDao.create(o1, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
String param = Observation.SP_COMPONENT_VALUE_QUANTITY;
|
||||
|
||||
{
|
||||
QuantityParam v1 = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, 1.2, UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm");
|
||||
SearchParameterMap map = new SearchParameterMap().setLoadSynchronous(true).add(param, v1);
|
||||
IBundleProvider result = myObservationDao.search(map);
|
||||
assertThat("Got: " + toUnqualifiedVersionlessIdValues(result), toUnqualifiedVersionlessIdValues(result), containsInAnyOrder(id1.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchCompositeParamQuantity() {
|
||||
Observation o1 = new Observation();
|
||||
@ -1241,6 +1290,62 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchCompositeParamQuantityWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
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("dm").setValue(10)); // 0.1m
|
||||
o1.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("code2")))
|
||||
.setValue(new Quantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm").setValue(12));// 0.012m
|
||||
IIdType id1 = myObservationDao.create(o1, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation o2 = new Observation();
|
||||
o2.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("code1")))
|
||||
.setValue(new Quantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("dm").setValue(20)); //0.2m
|
||||
o2.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("code3")))
|
||||
.setValue(new Quantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("dm").setValue(22)); //0.022m
|
||||
IIdType id2 = myObservationDao.create(o2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
String param = Observation.SP_COMPONENT_CODE_VALUE_QUANTITY;
|
||||
|
||||
{
|
||||
TokenParam v0 = new TokenParam("http://foo", "code1");
|
||||
QuantityParam v1 = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, 15, UcumServiceUtil.UCUM_CODESYSTEM_URL, "dm"); // 0.15m
|
||||
CompositeParam<TokenParam, QuantityParam> val = new CompositeParam<>(v0, v1);
|
||||
SearchParameterMap map = new SearchParameterMap().setLoadSynchronous(true).add(param, val);
|
||||
IBundleProvider result = myObservationDao.search(map);
|
||||
assertThat("Got: " + toUnqualifiedVersionlessIdValues(result), toUnqualifiedVersionlessIdValues(result), containsInAnyOrder(id2.getValue()));
|
||||
}
|
||||
{
|
||||
TokenParam v0 = new TokenParam("http://foo", "code1");
|
||||
QuantityParam v1 = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, 5, UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm"); //0.05m
|
||||
CompositeParam<TokenParam, QuantityParam> val = new CompositeParam<>(v0, v1);
|
||||
IBundleProvider result = myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(param, val));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(result), containsInAnyOrder(id1.getValue(), id2.getValue()));
|
||||
}
|
||||
{
|
||||
TokenParam v0 = new TokenParam("http://foo", "code4");
|
||||
QuantityParam v1 = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, 5, UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm"); //0.05m
|
||||
CompositeParam<TokenParam, QuantityParam> val = new CompositeParam<>(v0, v1);
|
||||
IBundleProvider result = myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(param, val));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(result), empty());
|
||||
}
|
||||
{
|
||||
TokenParam v0 = new TokenParam("http://foo", "code1");
|
||||
QuantityParam v1 = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, 5, UcumServiceUtil.UCUM_CODESYSTEM_URL, "m"); //5m
|
||||
CompositeParam<TokenParam, QuantityParam> val = new CompositeParam<>(v0, v1);
|
||||
IBundleProvider result = myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(param, val));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(result), empty());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchDateWrongParam() {
|
||||
Patient p1 = new Patient();
|
||||
|
@ -42,6 +42,8 @@ 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.jpa.model.util.UcumServiceUtil;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
@ -159,6 +161,7 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
||||
myDaoConfig.setEnforceReferentialIntegrityOnDelete(new DaoConfig().isEnforceReferentialIntegrityOnDelete());
|
||||
myDaoConfig.setEnforceReferenceTargetTypes(new DaoConfig().isEnforceReferenceTargetTypes());
|
||||
myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields());
|
||||
myModelConfig.setNormalizedQuantitySearchNotSupported();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
@ -576,45 +579,149 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChoiceParamQuantityWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
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
|
||||
IIdType id3 = myObservationDao.create(o3, mySrd).getId();
|
||||
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam(">100", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
assertEquals(1, found.size().intValue());
|
||||
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("gt100", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
assertEquals(1, found.size().intValue());
|
||||
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("<100", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
assertEquals(0, found.size().intValue());
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("lt100", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
assertEquals(0, found.size().intValue());
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.0001", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
assertEquals(0, found.size().intValue());
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("~120", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
assertEquals(1, found.size().intValue());
|
||||
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("ap120", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
assertEquals(1, found.size().intValue());
|
||||
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("eq123", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
assertEquals(1, found.size().intValue());
|
||||
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("eq120", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
assertEquals(0, found.size().intValue());
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("ne120", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
assertEquals(1, found.size().intValue());
|
||||
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("ne123", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
assertEquals(0, found.size().intValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChoiceParamQuantityPrecision() {
|
||||
Observation o3 = new Observation();
|
||||
o3.getCode().addCoding().setSystem("foo").setCode("testChoiceParam03");
|
||||
o3.setValue(new Quantity(null, 123.01, "foo", "bar", "bar"));
|
||||
o3.setValue(new Quantity(null, 123.01, UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm", "cm")); // 0.012301 m
|
||||
IIdType id3 = myObservationDao.create(o3, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("123", "foo", "bar")).setLoadSynchronous(true));
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("123", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
List<IIdType> list = toUnqualifiedVersionlessIds(found);
|
||||
assertThat(list, Matchers.empty());
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.0", "foo", "bar")).setLoadSynchronous(true));
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.0", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
List<IIdType> list = toUnqualifiedVersionlessIds(found);
|
||||
assertThat(list, Matchers.empty());
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.01", "foo", "bar")).setLoadSynchronous(true));
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.01", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
List<IIdType> list = toUnqualifiedVersionlessIds(found);
|
||||
assertThat(list, containsInAnyOrder(id3));
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.010", "foo", "bar")).setLoadSynchronous(true));
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.010", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
List<IIdType> list = toUnqualifiedVersionlessIds(found);
|
||||
assertThat(list, containsInAnyOrder(id3));
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.02", "foo", "bar")).setLoadSynchronous(true));
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.02", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
List<IIdType> list = toUnqualifiedVersionlessIds(found);
|
||||
assertThat(list, Matchers.empty());
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.001", "foo", "bar")).setLoadSynchronous(true));
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.001", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
List<IIdType> list = toUnqualifiedVersionlessIds(found);
|
||||
assertThat(list, Matchers.empty());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChoiceParamQuantityPrecisionWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
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
|
||||
IIdType id3 = myObservationDao.create(o3, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("123", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
List<IIdType> list = toUnqualifiedVersionlessIds(found);
|
||||
assertThat(list, Matchers.empty());
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.0", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
List<IIdType> list = toUnqualifiedVersionlessIds(found);
|
||||
assertThat(list, Matchers.empty());
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.01", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
List<IIdType> list = toUnqualifiedVersionlessIds(found);
|
||||
assertThat(list, containsInAnyOrder(id3));
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.010", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
List<IIdType> list = toUnqualifiedVersionlessIds(found);
|
||||
assertThat(list, containsInAnyOrder(id3));
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.02", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
List<IIdType> list = toUnqualifiedVersionlessIds(found);
|
||||
assertThat(list, Matchers.empty());
|
||||
}
|
||||
{
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.001", UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm")).setLoadSynchronous(true));
|
||||
List<IIdType> list = toUnqualifiedVersionlessIds(found);
|
||||
assertThat(list, Matchers.empty());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChoiceParamString() {
|
||||
|
||||
@ -1417,7 +1524,7 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
||||
myObservationDao.read(obs1id);
|
||||
myObservationDao.read(obs2id);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDeleteWithMatchUrl() {
|
||||
String methodName = "testDeleteWithMatchUrl";
|
||||
@ -3391,6 +3498,47 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
||||
assertThat(actual, contains(id4, id3, id2, id1));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSortByQuantityWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
Observation res;
|
||||
|
||||
res = new Observation();
|
||||
res.setValue(new Quantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm").setValue(2)); // 0.02m
|
||||
IIdType id2 = myObservationDao.create(res, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
res = new Observation();
|
||||
res.setValue(new Quantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("dm").setValue(0.1)); // 0.01m
|
||||
IIdType id1 = myObservationDao.create(res, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
res = new Observation();
|
||||
res.setValue(new Quantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("m").setValue(0.03)); // 0.03m
|
||||
IIdType id3 = myObservationDao.create(res, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
res = new Observation();
|
||||
res.setValue(new Quantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm").setValue(4)); // 0.04m
|
||||
IIdType id4 = myObservationDao.create(res, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap pm = new SearchParameterMap();
|
||||
pm.setSort(new SortSpec(Observation.SP_VALUE_QUANTITY));
|
||||
List<IIdType> actual = toUnqualifiedVersionlessIds(myObservationDao.search(pm));
|
||||
assertEquals(4, actual.size());
|
||||
assertThat(actual, contains(id1, id2, id3, id4));
|
||||
|
||||
pm = new SearchParameterMap();
|
||||
pm.setSort(new SortSpec(Observation.SP_VALUE_QUANTITY, SortOrderEnum.ASC));
|
||||
actual = toUnqualifiedVersionlessIds(myObservationDao.search(pm));
|
||||
assertEquals(4, actual.size());
|
||||
assertThat(actual, contains(id1, id2, id3, id4));
|
||||
|
||||
pm = new SearchParameterMap();
|
||||
pm.setSort(new SortSpec(Observation.SP_VALUE_QUANTITY, SortOrderEnum.DESC));
|
||||
actual = toUnqualifiedVersionlessIds(myObservationDao.search(pm));
|
||||
assertEquals(4, actual.size());
|
||||
assertThat(actual, contains(id4, id3, id2, id1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSortByReference() {
|
||||
|
@ -110,6 +110,7 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest {
|
||||
public void after() {
|
||||
myDaoConfig.setAllowInlineMatchUrlReferences(false);
|
||||
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
|
||||
myModelConfig.setNormalizedQuantitySearchNotSupported();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
@ -3127,6 +3128,80 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest {
|
||||
assertEquals(id.getValue(), id2.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionWithConditionalUpdateDoesntUpdateIfNoChangeWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier()
|
||||
.setSystem("http://acme.org")
|
||||
.setValue("ID1");
|
||||
obs
|
||||
.getCode()
|
||||
.addCoding()
|
||||
.setSystem("http://loinc.org")
|
||||
.setCode("29463-7");
|
||||
obs.setEffective(new DateTimeType("2011-09-03T11:13:00-04:00"));
|
||||
obs.setValue(new Quantity()
|
||||
.setValue(new BigDecimal("123.4"))
|
||||
.setCode("kg")
|
||||
.setSystem("http://unitsofmeasure.org")
|
||||
.setUnit("kg"));
|
||||
Bundle input = new Bundle();
|
||||
input.setType(BundleType.TRANSACTION);
|
||||
input
|
||||
.addEntry()
|
||||
.setFullUrl("urn:uuid:0001")
|
||||
.setResource(obs)
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.PUT)
|
||||
.setUrl("Observation?identifier=http%3A%2F%2Facme.org|ID1");
|
||||
|
||||
Bundle output = mySystemDao.transaction(mySrd, input);
|
||||
assertEquals(1, output.getEntry().size());
|
||||
IdType id = new IdType(output.getEntry().get(0).getResponse().getLocation());
|
||||
assertEquals("Observation", id.getResourceType());
|
||||
assertEquals("1", id.getVersionIdPart());
|
||||
|
||||
/*
|
||||
* Try again with same contents
|
||||
*/
|
||||
|
||||
Observation obs2 = new Observation();
|
||||
obs2.addIdentifier()
|
||||
.setSystem("http://acme.org")
|
||||
.setValue("ID1");
|
||||
obs2
|
||||
.getCode()
|
||||
.addCoding()
|
||||
.setSystem("http://loinc.org")
|
||||
.setCode("29463-7");
|
||||
obs2.setEffective(new DateTimeType("2011-09-03T11:13:00-04:00"));
|
||||
obs2.setValue(new Quantity()
|
||||
.setValue(new BigDecimal("123.4"))
|
||||
.setCode("kg")
|
||||
.setSystem("http://unitsofmeasure.org")
|
||||
.setUnit("kg"));
|
||||
Bundle input2 = new Bundle();
|
||||
input2.setType(BundleType.TRANSACTION);
|
||||
input2
|
||||
.addEntry()
|
||||
.setFullUrl("urn:uuid:0001")
|
||||
.setResource(obs2)
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.PUT)
|
||||
.setUrl("Observation?identifier=http%3A%2F%2Facme.org|ID1");
|
||||
|
||||
Bundle output2 = mySystemDao.transaction(mySrd, input2);
|
||||
assertEquals(1, output2.getEntry().size());
|
||||
IdType id2 = new IdType(output2.getEntry().get(0).getResponse().getLocation());
|
||||
assertEquals("Observation", id2.getResourceType());
|
||||
assertEquals("1", id2.getVersionIdPart());
|
||||
|
||||
assertEquals(id.getValue(), id2.getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionWithIfMatch() {
|
||||
Patient p = new Patient();
|
||||
|
@ -1,5 +1,40 @@
|
||||
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 org.hl7.fhir.r4.model.BooleanType;
|
||||
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||
import org.hl7.fhir.r4.model.Coding;
|
||||
import org.hl7.fhir.r4.model.Consent;
|
||||
import org.hl7.fhir.r4.model.Encounter;
|
||||
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 ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
@ -12,6 +47,7 @@ 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;
|
||||
@ -22,36 +58,7 @@ 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;
|
||||
import org.hl7.fhir.r4.model.Consent;
|
||||
import org.hl7.fhir.r4.model.Encounter;
|
||||
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.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 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 static java.util.Comparator.comparing;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||
|
||||
public class SearchParamExtractorR4Test {
|
||||
|
||||
@ -334,6 +341,46 @@ public class SearchParamExtractorR4Test {
|
||||
assertEquals(4, links.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractComponentQuantityWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
ModelConfig modelConfig = new ModelConfig();
|
||||
|
||||
modelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
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);
|
||||
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();
|
||||
|
||||
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);
|
||||
List<String> list = extractor.extractParamValuesAsStrings(existingCodeSp, o1);
|
||||
|
||||
assertEquals(1, list.size());
|
||||
}
|
||||
|
||||
private static class MySearchParamRegistry implements ISearchParamRegistry {
|
||||
|
||||
|
||||
|
@ -14,14 +14,19 @@ import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.util.HapiExtensions;
|
||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.BooleanType;
|
||||
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||
import org.hl7.fhir.r4.model.DateType;
|
||||
import org.hl7.fhir.r4.model.DecimalType;
|
||||
import org.hl7.fhir.r4.model.Enumerations;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
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.SearchParameter;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@ -57,6 +62,7 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
|
||||
@AfterEach
|
||||
public void afterDisableExpunge() {
|
||||
myDaoConfig.setExpungeEnabled(new DaoConfig().isExpungeEnabled());
|
||||
myModelConfig.setNormalizedQuantitySearchNotSupported();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
@ -150,11 +156,18 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
|
||||
myTwoVersionObservationId = myObservationDao.create(o).getId();
|
||||
o.setStatus(Observation.ObservationStatus.AMENDED);
|
||||
myTwoVersionObservationId = myObservationDao.update(o).getId();
|
||||
CodeableConcept cc = o.getCode();
|
||||
cc.addCoding().setCode("2345-7").setSystem("http://loinc.org");
|
||||
o.setValue(new Quantity().setValueElement(new DecimalType(125.12)).setUnit("CM").setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm"));
|
||||
|
||||
o = new Observation();
|
||||
o.setStatus(Observation.ObservationStatus.FINAL);
|
||||
myDeletedObservationId = myObservationDao.create(o).getId();
|
||||
myDeletedObservationId = myObservationDao.delete(myDeletedObservationId).getId();
|
||||
cc = o.getCode();
|
||||
cc.addCoding().setCode("2345-7").setSystem("http://loinc.org");
|
||||
o.setValue(new Quantity().setValueElement(new DecimalType(13.45)).setUnit("DM").setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("dm"));
|
||||
|
||||
}
|
||||
|
||||
private IFhirResourceDao<?> getDao(IIdType theId) {
|
||||
@ -387,6 +400,50 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
|
||||
assertExpunged(myDeletedObservationId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpungeSystemEverythingWithNormalizedQuantitySearchSupported() {
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
createStandardPatients();
|
||||
|
||||
mySystemDao.expunge(new ExpungeOptions()
|
||||
.setExpungeEverything(true), null);
|
||||
|
||||
// Everything deleted
|
||||
assertExpunged(myOneVersionPatientId);
|
||||
assertExpunged(myTwoVersionPatientId.withVersion("1"));
|
||||
assertExpunged(myTwoVersionPatientId.withVersion("2"));
|
||||
assertExpunged(myDeletedPatientId.withVersion("1"));
|
||||
assertExpunged(myDeletedPatientId);
|
||||
|
||||
// Everything deleted
|
||||
assertExpunged(myOneVersionObservationId);
|
||||
assertExpunged(myTwoVersionObservationId.withVersion("1"));
|
||||
assertExpunged(myTwoVersionObservationId.withVersion("2"));
|
||||
assertExpunged(myDeletedObservationId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpungeSystemEverythingWithNormalizedQuantityStorageSupported() {
|
||||
myModelConfig.setNormalizedQuantityStorageSupported();
|
||||
createStandardPatients();
|
||||
|
||||
mySystemDao.expunge(new ExpungeOptions()
|
||||
.setExpungeEverything(true), null);
|
||||
|
||||
// Everything deleted
|
||||
assertExpunged(myOneVersionPatientId);
|
||||
assertExpunged(myTwoVersionPatientId.withVersion("1"));
|
||||
assertExpunged(myTwoVersionPatientId.withVersion("2"));
|
||||
assertExpunged(myDeletedPatientId.withVersion("1"));
|
||||
assertExpunged(myDeletedPatientId);
|
||||
|
||||
// Everything deleted
|
||||
assertExpunged(myOneVersionObservationId);
|
||||
assertExpunged(myTwoVersionObservationId.withVersion("1"));
|
||||
assertExpunged(myTwoVersionObservationId.withVersion("2"));
|
||||
assertExpunged(myDeletedObservationId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpungeTypeOldVersionsAndDeleted() {
|
||||
createStandardPatients();
|
||||
|
@ -163,7 +163,6 @@ public class ResourceProviderHasParamR4Test extends BaseResourceProviderR4Test {
|
||||
ourLog.info("uri = " + uri);
|
||||
|
||||
List<String> ids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
|
||||
System.out.println("ids.size() = " + ids.size());
|
||||
assertThat(ids, contains(pid0.getValue()));
|
||||
}
|
||||
|
||||
|
@ -1,45 +1,52 @@
|
||||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.config.TestR4Config;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.entity.Search;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl;
|
||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.model.primitive.UriDt;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.PreferReturnEnum;
|
||||
import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
|
||||
import ca.uhn.fhir.rest.api.SummaryEnum;
|
||||
import ca.uhn.fhir.rest.client.apache.ResourceEntity;
|
||||
import ca.uhn.fhir.rest.client.api.IClientInterceptor;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
||||
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
|
||||
import ca.uhn.fhir.rest.gclient.StringClientParam;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import ca.uhn.fhir.rest.param.NumberParam;
|
||||
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
|
||||
import ca.uhn.fhir.rest.param.StringAndListParam;
|
||||
import ca.uhn.fhir.rest.param.StringOrListParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.Lists;
|
||||
import static ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast;
|
||||
import static ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.containsInRelativeOrder;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.emptyString;
|
||||
import static org.hamcrest.Matchers.endsWith;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.hasItems;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.lessThan;
|
||||
import static org.hamcrest.Matchers.lessThanOrEqualTo;
|
||||
import static org.hamcrest.Matchers.matchesPattern;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
@ -80,6 +87,7 @@ import org.hl7.fhir.r4.model.Coding;
|
||||
import org.hl7.fhir.r4.model.Condition;
|
||||
import org.hl7.fhir.r4.model.DateTimeType;
|
||||
import org.hl7.fhir.r4.model.DateType;
|
||||
import org.hl7.fhir.r4.model.DecimalType;
|
||||
import org.hl7.fhir.r4.model.Device;
|
||||
import org.hl7.fhir.r4.model.DiagnosticReport;
|
||||
import org.hl7.fhir.r4.model.DocumentManifest;
|
||||
@ -129,36 +137,58 @@ import org.hl7.fhir.r4.model.Subscription.SubscriptionStatus;
|
||||
import org.hl7.fhir.r4.model.UnsignedIntType;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||
import org.junit.jupiter.api.*; import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.util.AopTestUtils;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import static ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast;
|
||||
import static ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.config.TestR4Config;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.entity.Search;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl;
|
||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.model.primitive.UriDt;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.PreferReturnEnum;
|
||||
import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
|
||||
import ca.uhn.fhir.rest.api.SummaryEnum;
|
||||
import ca.uhn.fhir.rest.client.apache.ResourceEntity;
|
||||
import ca.uhn.fhir.rest.client.api.IClientInterceptor;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
||||
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
|
||||
import ca.uhn.fhir.rest.gclient.StringClientParam;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import ca.uhn.fhir.rest.param.NumberParam;
|
||||
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
|
||||
import ca.uhn.fhir.rest.param.StringAndListParam;
|
||||
import ca.uhn.fhir.rest.param.StringOrListParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||
@ -187,6 +217,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||
mySearchCoordinatorSvcRaw.setSyncSizeForUnitTests(SearchCoordinatorSvcImpl.DEFAULT_SYNC_SIZE);
|
||||
mySearchCoordinatorSvcRaw.setNeverUseLocalSearchForUnitTests(false);
|
||||
mySearchCoordinatorSvcRaw.cancelAllActiveSearches();
|
||||
myDaoConfig.getModelConfig().setNormalizedQuantitySearchNotSupported();
|
||||
|
||||
myClient.unregisterInterceptor(myCapturingInterceptor);
|
||||
}
|
||||
@ -727,7 +758,9 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||
ourLog.info(resp);
|
||||
Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, resp);
|
||||
ids = toUnqualifiedVersionlessIdValues(bundle);
|
||||
ourLog.info("Observation: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle));
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
@ -4050,6 +4083,154 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||
assertTrue(value.before(after), new InstantDt(value) + " should be before " + new InstantDt(after));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithNormalizedQuantitySearchSupported() throws Exception {
|
||||
|
||||
myDaoConfig.getModelConfig().setNormalizedQuantitySearchSupported();
|
||||
IIdType pid0;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
||||
patient.addName().setFamily("Tester").addGiven("Joe");
|
||||
pid0 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
{
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("FOO");
|
||||
obs.getSubject().setReferenceElement(pid0);
|
||||
CodeableConcept cc = obs.getCode();
|
||||
cc.addCoding().setCode("2345-7").setSystem("http://loinc.org");
|
||||
obs.setValue(new Quantity().setValueElement(new DecimalType(125.12)).setUnit("CM").setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm"));
|
||||
|
||||
myObservationDao.create(obs, mySrd);
|
||||
|
||||
ourLog.info("Observation: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
}
|
||||
|
||||
{
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("FOO");
|
||||
obs.getSubject().setReferenceElement(pid0);
|
||||
CodeableConcept cc = obs.getCode();
|
||||
cc.addCoding().setCode("2345-7").setSystem("http://loinc.org");
|
||||
obs.setValue(new Quantity().setValueElement(new DecimalType(13.45)).setUnit("DM").setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("dm"));
|
||||
|
||||
myObservationDao.create(obs, mySrd);
|
||||
|
||||
ourLog.info("Observation: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
}
|
||||
|
||||
{
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("FOO");
|
||||
obs.getSubject().setReferenceElement(pid0);
|
||||
CodeableConcept cc = obs.getCode();
|
||||
cc.addCoding().setCode("2345-7").setSystem("http://loinc.org");
|
||||
obs.setValue(new Quantity().setValueElement(new DecimalType(1.45)).setUnit("M").setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("m"));
|
||||
|
||||
myObservationDao.create(obs, mySrd);
|
||||
|
||||
ourLog.info("Observation: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
}
|
||||
|
||||
{
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("FOO");
|
||||
obs.getSubject().setReferenceElement(pid0);
|
||||
CodeableConcept cc = obs.getCode();
|
||||
cc.addCoding().setCode("2345-7").setSystem("http://loinc.org");
|
||||
obs.setValue(new Quantity().setValueElement(new DecimalType(25)).setUnit("CM").setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm"));
|
||||
|
||||
myObservationDao.create(obs, mySrd);
|
||||
|
||||
ourLog.info("Observation: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
}
|
||||
|
||||
// > 1m
|
||||
String uri = ourServerBase + "/Observation?code-value-quantity=http://" + UrlUtil.escapeUrlParam("loinc.org|2345-7$gt1|http://unitsofmeasure.org|m");
|
||||
ourLog.info("uri = " + uri);
|
||||
List<String> ids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
|
||||
assertEquals(3, ids.size());
|
||||
|
||||
//>= 100cm
|
||||
uri = ourServerBase + "/Observation?code-value-quantity=http://" + UrlUtil.escapeUrlParam("loinc.org|2345-7$gt100|http://unitsofmeasure.org|cm");
|
||||
ourLog.info("uri = " + uri);
|
||||
ids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
|
||||
assertEquals(3, ids.size());
|
||||
|
||||
//>= 10dm
|
||||
uri = ourServerBase + "/Observation?code-value-quantity=http://" + UrlUtil.escapeUrlParam("loinc.org|2345-7$gt10|http://unitsofmeasure.org|dm");
|
||||
ourLog.info("uri = " + uri);
|
||||
ids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
|
||||
assertEquals(3, ids.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithNormalizedQuantitySearchSupported_CombineUCUMOrNonUCUM() throws Exception {
|
||||
|
||||
myDaoConfig.getModelConfig().setNormalizedQuantitySearchSupported();
|
||||
IIdType pid0;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
||||
patient.addName().setFamily("Tester").addGiven("Joe");
|
||||
pid0 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
{
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("FOO");
|
||||
obs.getSubject().setReferenceElement(pid0);
|
||||
obs.setValue(new Quantity().setValueElement(new DecimalType(1)).setUnit("M").setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("m"));
|
||||
|
||||
myObservationDao.create(obs, mySrd);
|
||||
|
||||
ourLog.info("Observation: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
}
|
||||
|
||||
{
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("FOO");
|
||||
obs.getSubject().setReferenceElement(pid0);
|
||||
obs.setValue(new Quantity().setValueElement(new DecimalType(13.45)).setUnit("DM").setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("dm"));
|
||||
|
||||
myObservationDao.create(obs, mySrd);
|
||||
|
||||
ourLog.info("Observation: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
}
|
||||
|
||||
{
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("FOO");
|
||||
obs.getSubject().setReferenceElement(pid0);
|
||||
obs.setValue(new Quantity().setValueElement(new DecimalType(1.45)).setUnit("M").setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("m"));
|
||||
|
||||
myObservationDao.create(obs, mySrd);
|
||||
|
||||
ourLog.info("Observation: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
}
|
||||
|
||||
{
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("FOO");
|
||||
obs.getSubject().setReferenceElement(pid0);
|
||||
CodeableConcept cc = obs.getCode();
|
||||
obs.setValue(new Quantity().setValueElement(new DecimalType(100)).setUnit("CM").setSystem("http://foo").setCode("cm"));
|
||||
|
||||
myObservationDao.create(obs, mySrd);
|
||||
|
||||
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);
|
||||
assertEquals(2, ids.size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchReusesNoParams() {
|
||||
List<IBaseResource> resources = new ArrayList<>();
|
||||
@ -5861,6 +6042,109 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithNormalizedQuantitySearchSupported() throws Exception {
|
||||
|
||||
myDaoConfig.getModelConfig().setNormalizedQuantitySearchSupported();
|
||||
IIdType pid0;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
||||
patient.addName().setFamily("Tester").addGiven("Joe");
|
||||
pid0 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
||||
patient.addName().setFamily("Tester").addGiven("Joe");
|
||||
myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
{
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("FOO");
|
||||
obs.getSubject().setReferenceElement(pid0);
|
||||
CodeableConcept cc = obs.getCode();
|
||||
cc.addCoding().setCode("2345-7").setSystem("http://loinc.org");
|
||||
obs.setValue(new Quantity().setValueElement(new DecimalType(125.12)).setUnit("CM").setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm"));
|
||||
|
||||
ourLog.info("Observation: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
|
||||
IIdType opid1 = myObservationDao.create(obs, mySrd).getId();
|
||||
|
||||
//-- update quantity
|
||||
obs = new Observation();
|
||||
obs.setId(opid1);
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("FOO");
|
||||
obs.getSubject().setReferenceElement(pid0);
|
||||
cc = obs.getCode();
|
||||
cc.addCoding().setCode("2345-7").setSystem("http://loinc.org");
|
||||
obs.setValue(new Quantity().setValueElement(new DecimalType(24.12)).setUnit("CM").setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm"));
|
||||
|
||||
ourLog.info("Observation: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
|
||||
myObservationDao.update(obs, mySrd);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("FOO");
|
||||
obs.getSubject().setReferenceElement(pid0);
|
||||
CodeableConcept cc = obs.getCode();
|
||||
cc.addCoding().setCode("2345-7").setSystem("http://loinc.org");
|
||||
obs.setValue(new Quantity().setValueElement(new DecimalType(13.45)).setUnit("DM").setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("dm"));
|
||||
|
||||
myObservationDao.create(obs, mySrd);
|
||||
|
||||
ourLog.info("Observation: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
}
|
||||
|
||||
{
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("FOO");
|
||||
obs.getSubject().setReferenceElement(pid0);
|
||||
CodeableConcept cc = obs.getCode();
|
||||
cc.addCoding().setCode("2345-7").setSystem("http://loinc.org");
|
||||
obs.setValue(new Quantity().setValueElement(new DecimalType(1.45)).setUnit("M").setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("m"));
|
||||
|
||||
myObservationDao.create(obs, mySrd);
|
||||
|
||||
ourLog.info("Observation: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
}
|
||||
|
||||
{
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("FOO");
|
||||
obs.getSubject().setReferenceElement(pid0);
|
||||
CodeableConcept cc = obs.getCode();
|
||||
cc.addCoding().setCode("2345-7").setSystem("http://loinc.org");
|
||||
obs.setValue(new Quantity().setValueElement(new DecimalType(25)).setUnit("CM").setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm"));
|
||||
|
||||
myObservationDao.create(obs, mySrd);
|
||||
|
||||
ourLog.info("Observation: \n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
}
|
||||
|
||||
// > 1m
|
||||
String uri = ourServerBase + "/Observation?code-value-quantity=http://" + UrlUtil.escapeUrlParam("loinc.org|2345-7$gt1|http://unitsofmeasure.org|m");
|
||||
ourLog.info("uri = " + uri);
|
||||
List<String> ids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
|
||||
assertEquals(2, ids.size());
|
||||
|
||||
|
||||
//>= 100cm
|
||||
uri = ourServerBase + "/Observation?code-value-quantity=http://" + UrlUtil.escapeUrlParam("loinc.org|2345-7$gt100|http://unitsofmeasure.org|cm");
|
||||
ourLog.info("uri = " + uri);
|
||||
ids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
|
||||
assertEquals(2, ids.size());
|
||||
|
||||
//>= 10dm
|
||||
uri = ourServerBase + "/Observation?code-value-quantity=http://" + UrlUtil.escapeUrlParam("loinc.org|2345-7$gt10|http://unitsofmeasure.org|dm");
|
||||
ourLog.info("uri = " + uri);
|
||||
ids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
|
||||
assertEquals(2, ids.size());
|
||||
}
|
||||
|
||||
private String toStr(Date theDate) {
|
||||
return new InstantDt(theDate).getValueAsString();
|
||||
|
@ -1,8 +1,11 @@
|
||||
package ca.uhn.fhir.jpa.subscription.module.matcher;
|
||||
|
||||
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.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.searchparam.matcher.InMemoryMatchResult;
|
||||
@ -61,6 +64,7 @@ import org.hl7.fhir.r4.model.StringType;
|
||||
import org.hl7.fhir.r4.model.Subscription;
|
||||
import org.hl7.fhir.r4.model.Task;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -71,7 +75,6 @@ import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
@ -95,6 +98,14 @@ public class InMemorySubscriptionMatcherR4Test {
|
||||
@Autowired
|
||||
MatchUrlService myMatchUrlService;
|
||||
|
||||
@Autowired
|
||||
ModelConfig myModelConfig;
|
||||
|
||||
@AfterEach
|
||||
public void after() throws Exception {
|
||||
myModelConfig.setNormalizedQuantitySearchNotSupported();
|
||||
}
|
||||
|
||||
private void assertMatched(Resource resource, SearchParameterMap params) {
|
||||
InMemoryMatchResult result = match(resource, params);
|
||||
assertTrue(result.supported(), result.getUnsupportedReason());
|
||||
@ -235,7 +246,89 @@ public class InMemorySubscriptionMatcherR4Test {
|
||||
SearchParameterMap params = new SearchParameterMap().setLoadSynchronous(true).add(param, v1);
|
||||
assertMatched(o1, params);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithNormalizedQuantitySearchSupported() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
Observation o1 = new Observation();
|
||||
o1.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("cm")))
|
||||
.setValue(new Quantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm").setValue(150));
|
||||
|
||||
String param1 = Observation.SP_COMPONENT_VALUE_QUANTITY;
|
||||
|
||||
QuantityParam v1 = new QuantityParam(null, 1.5, UcumServiceUtil.UCUM_CODESYSTEM_URL, "m");
|
||||
SearchParameterMap params1 = new SearchParameterMap().setLoadSynchronous(true).add(param1, v1);
|
||||
assertMatched(o1, params1);
|
||||
|
||||
Observation o2 = new Observation();
|
||||
o2.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("cm")))
|
||||
.setValue(new Quantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm").setValue(150));
|
||||
|
||||
String param2 = Observation.SP_COMPONENT_VALUE_QUANTITY;
|
||||
|
||||
QuantityParam v2 = new QuantityParam(null, 15, UcumServiceUtil.UCUM_CODESYSTEM_URL, "dm");
|
||||
SearchParameterMap params2 = new SearchParameterMap().setLoadSynchronous(true).add(param2, v2);
|
||||
assertMatched(o2, params2);
|
||||
|
||||
v2 = new QuantityParam(null, 150, UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm");
|
||||
params2 = new SearchParameterMap().setLoadSynchronous(true).add(param2, v2);
|
||||
assertMatched(o2, params2);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithNormalizedQuantitySearchSupported_InvalidUCUMUnit() {
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
Observation o1 = new Observation();
|
||||
o1.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://bar").setCode("foo")))
|
||||
.setValue(new Quantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("foo").setValue(150));
|
||||
|
||||
String param1 = Observation.SP_COMPONENT_VALUE_QUANTITY;
|
||||
|
||||
QuantityParam v1 = new QuantityParam(null, 150, UcumServiceUtil.UCUM_CODESYSTEM_URL, "foo");
|
||||
SearchParameterMap params1 = new SearchParameterMap().setLoadSynchronous(true).add(param1, v1);
|
||||
assertMatched(o1, params1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithNormalizedQuantitySearchSupported_NoSystem() {
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
Observation o1 = new Observation();
|
||||
o1.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://bar").setCode("foo")))
|
||||
.setValue(new Quantity().setCode("foo").setValue(150));
|
||||
|
||||
String param1 = Observation.SP_COMPONENT_VALUE_QUANTITY;
|
||||
|
||||
QuantityParam v1 = new QuantityParam(null, 150, null, "foo");
|
||||
SearchParameterMap params1 = new SearchParameterMap().setLoadSynchronous(true).add(param1, v1);
|
||||
assertMatched(o1, params1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithNormalizedQuantitySearchSupported_NotUcumSystem() {
|
||||
|
||||
myModelConfig.setNormalizedQuantitySearchSupported();
|
||||
|
||||
Observation o1 = new Observation();
|
||||
o1.addComponent()
|
||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("cm")))
|
||||
.setValue(new Quantity().setSystem("http://bar").setCode("cm").setValue(150));
|
||||
|
||||
String param1 = Observation.SP_COMPONENT_VALUE_QUANTITY;
|
||||
|
||||
QuantityParam v1 = new QuantityParam(null, 150, "http://bar", "cm");
|
||||
SearchParameterMap params1 = new SearchParameterMap().setLoadSynchronous(true).add(param1, v1);
|
||||
assertMatched(o1, params1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIdSupported() {
|
||||
Observation o1 = new Observation();
|
||||
|
@ -76,12 +76,40 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
||||
|
||||
private void init530() {
|
||||
Builder version = forVersion(VersionEnum.V5_3_0);
|
||||
|
||||
//-- TRM
|
||||
version
|
||||
.onTable("TRM_VALUESET_CONCEPT")
|
||||
.dropIndex("20210104.1", "IDX_VS_CONCEPT_CS_CODE");
|
||||
version
|
||||
.onTable("TRM_VALUESET_CONCEPT")
|
||||
.addIndex("20210104.2", "IDX_VS_CONCEPT_CSCD").unique(true).withColumns("VALUESET_PID", "SYSTEM_URL", "CODEVAL");
|
||||
|
||||
version
|
||||
.onTable("TRM_VALUESET_CONCEPT")
|
||||
.addIndex("20210104.2", "IDX_VS_CONCEPT_CSCD").unique(true).withColumns("VALUESET_PID", "SYSTEM_URL", "CODEVAL");
|
||||
|
||||
//-- Add new Table, HFJ_SPIDX_QUANTITY_NRML
|
||||
version.addIdGenerator("20210109.1", "SEQ_SPIDX_QUANTITY_NRML");
|
||||
Builder.BuilderAddTableByColumns pkg = version.addTableByColumns("20210109.2", "HFJ_SPIDX_QUANTITY_NRML", "SP_ID");
|
||||
pkg.addColumn("RES_ID").nonNullable().type(ColumnTypeEnum.LONG);
|
||||
pkg.addColumn("RES_TYPE").nonNullable().type(ColumnTypeEnum.STRING, 100);
|
||||
pkg.addColumn("SP_UPDATED").nullable().type(ColumnTypeEnum.DATE_TIMESTAMP);
|
||||
pkg.addColumn("SP_MISSING").nonNullable().type(ColumnTypeEnum.BOOLEAN);
|
||||
pkg.addColumn("SP_NAME").nonNullable().type(ColumnTypeEnum.STRING, 100);
|
||||
pkg.addColumn("SP_ID").nonNullable().type(ColumnTypeEnum.LONG);
|
||||
pkg.addColumn("SP_SYSTEM").nullable().type(ColumnTypeEnum.STRING, 200);
|
||||
pkg.addColumn("SP_UNITS").nullable().type(ColumnTypeEnum.STRING, 200);
|
||||
pkg.addColumn("HASH_IDENTITY_AND_UNITS").nullable().type(ColumnTypeEnum.LONG);
|
||||
pkg.addColumn("HASH_IDENTITY_SYS_UNITS").nullable().type(ColumnTypeEnum.LONG);
|
||||
pkg.addColumn("HASH_IDENTITY").nullable().type(ColumnTypeEnum.LONG);
|
||||
pkg.addColumn("SP_VALUE").nullable().type(ColumnTypeEnum.FLOAT);
|
||||
pkg.addIndex("20210109.3", "IDX_SP_QNTY_NRML_HASH").unique(false).withColumns("HASH_IDENTITY","SP_VALUE");
|
||||
pkg.addIndex("20210109.4", "IDX_SP_QNTY_NRML_HASH_UN").unique(false).withColumns("HASH_IDENTITY_AND_UNITS","SP_VALUE");
|
||||
pkg.addIndex("20210109.5", "IDX_SP_QNTY_NRML_HASH_SYSUN").unique(false).withColumns("HASH_IDENTITY_SYS_UNITS","SP_VALUE");
|
||||
pkg.addIndex("20210109.6", "IDX_SP_QNTY_NRML_UPDATED").unique(false).withColumns("SP_UPDATED");
|
||||
pkg.addIndex("20210109.7", "IDX_SP_QNTY_NRML_RESID").unique(false).withColumns("RES_ID");
|
||||
//pkg.addForeignKey("20210109.9", "FK_QNTY_NRML_RESID").toColumn("RES_ID").references("HFJ_RESOURCE", "RES_ID");
|
||||
|
||||
//-- Link to the resourceTable
|
||||
version.onTable("HFJ_RESOURCE").addColumn("20210109.10", "SP_QUANTITY_NRML_PRESENT").nullable().type(ColumnTypeEnum.BOOLEAN);
|
||||
|
||||
}
|
||||
|
||||
@ -96,7 +124,7 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
||||
.toColumn("GOLDEN_RESOURCE_PID")
|
||||
.references("HFJ_RESOURCE", "RES_ID");
|
||||
}
|
||||
|
||||
|
||||
protected void init510() {
|
||||
Builder version = forVersion(VersionEnum.V5_1_0);
|
||||
|
||||
|
@ -15,6 +15,13 @@
|
||||
<name>HAPI FHIR Model</name>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- FHIR -->
|
||||
<dependency>
|
||||
<groupId>org.fhir</groupId>
|
||||
<artifactId>ucum</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-base</artifactId>
|
||||
|
@ -89,12 +89,15 @@ public class ModelConfig {
|
||||
private IPrimitiveType<Date> myPeriodIndexStartOfTime;
|
||||
private IPrimitiveType<Date> myPeriodIndexEndOfTime;
|
||||
|
||||
private NormalizedQuantitySearchLevel myNormalizedQuantitySearchLevel;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public ModelConfig() {
|
||||
setPeriodIndexStartOfTime(new DateTimeType(DEFAULT_PERIOD_INDEX_START_OF_TIME));
|
||||
setPeriodIndexEndOfTime(new DateTimeType(DEFAULT_PERIOD_INDEX_END_OF_TIME));
|
||||
setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -585,4 +588,44 @@ 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;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
package ca.uhn.fhir.jpa.model.entity;
|
||||
|
||||
/**
|
||||
* Support different UCUM services level for FHIR Quantity data type.
|
||||
*
|
||||
* @since 5.3.0
|
||||
*/
|
||||
|
||||
public enum NormalizedQuantitySearchLevel {
|
||||
|
||||
/**
|
||||
* default, Quantity is stored in {@link ResourceIndexedSearchParamQuantity} only and it is used by searching.
|
||||
*/
|
||||
NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED,
|
||||
|
||||
/**
|
||||
* Quantity is stored in both {@link ResourceIndexedSearchParamQuantity}
|
||||
* and {@link ResourceIndexedSearchParamQuantityNormalized},
|
||||
* but {@link ResourceIndexedSearchParamQuantity} is used by searching.
|
||||
*/
|
||||
NORMALIZED_QUANTITY_STORAGE_SUPPORTED,
|
||||
|
||||
/**
|
||||
* Quantity is stored in both {@link ResourceIndexedSearchParamQuantity}
|
||||
* and {@link ResourceIndexedSearchParamQuantityNormalized},
|
||||
* {@link ResourceIndexedSearchParamQuantityNormalized} is used by searching.
|
||||
*/
|
||||
NORMALIZED_QUANTITY_SEARCH_SUPPORTED,
|
||||
|
||||
/**
|
||||
* Quantity is stored in only in {@link ResourceIndexedSearchParamQuantityNormalized},
|
||||
* {@link ResourceIndexedSearchParamQuantityNormalized} is used by searching.
|
||||
* The existing non normalized quantity will be not supported
|
||||
* NOTE: this option is not supported in this release
|
||||
*/
|
||||
//NORMALIZED_QUANTITY_SEARCH_FULL_SUPPORTED,
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
package ca.uhn.fhir.jpa.model.entity;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR Model
|
||||
* %%
|
||||
* 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 javax.persistence.Column;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField;
|
||||
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
|
||||
@MappedSuperclass
|
||||
public abstract class ResourceIndexedSearchParamBaseQuantity extends BaseResourceIndexedSearchParam {
|
||||
|
||||
private static final int MAX_LENGTH = 200;
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Column(name = "SP_SYSTEM", nullable = true, length = MAX_LENGTH)
|
||||
@FullTextField
|
||||
public String mySystem;
|
||||
|
||||
@Column(name = "SP_UNITS", nullable = true, length = MAX_LENGTH)
|
||||
@FullTextField
|
||||
public String myUnits;
|
||||
|
||||
/**
|
||||
* @since 3.5.0 - At some point this should be made not-null
|
||||
*/
|
||||
@Column(name = "HASH_IDENTITY_AND_UNITS", nullable = true)
|
||||
private Long myHashIdentityAndUnits;
|
||||
/**
|
||||
* @since 3.5.0 - At some point this should be made not-null
|
||||
*/
|
||||
@Column(name = "HASH_IDENTITY_SYS_UNITS", nullable = true)
|
||||
private Long myHashIdentitySystemAndUnits;
|
||||
/**
|
||||
* @since 3.5.0 - At some point this should be made not-null
|
||||
*/
|
||||
@Column(name = "HASH_IDENTITY", nullable = true)
|
||||
private Long myHashIdentity;
|
||||
|
||||
public ResourceIndexedSearchParamBaseQuantity() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateHashes() {
|
||||
String resourceType = getResourceType();
|
||||
String paramName = getParamName();
|
||||
String units = getUnits();
|
||||
String system = getSystem();
|
||||
setHashIdentity(calculateHashIdentity(getPartitionSettings(), getPartitionId(), resourceType, paramName));
|
||||
setHashIdentityAndUnits(calculateHashUnits(getPartitionSettings(), getPartitionId(), resourceType, paramName, units));
|
||||
setHashIdentitySystemAndUnits(calculateHashSystemAndUnits(getPartitionSettings(), getPartitionId(), resourceType, paramName, system, units));
|
||||
}
|
||||
|
||||
public Long getHashIdentity() {
|
||||
return myHashIdentity;
|
||||
}
|
||||
|
||||
public void setHashIdentity(Long theHashIdentity) {
|
||||
myHashIdentity = theHashIdentity;
|
||||
}
|
||||
|
||||
public Long getHashIdentityAndUnits() {
|
||||
return myHashIdentityAndUnits;
|
||||
}
|
||||
|
||||
public void setHashIdentityAndUnits(Long theHashIdentityAndUnits) {
|
||||
myHashIdentityAndUnits = theHashIdentityAndUnits;
|
||||
}
|
||||
|
||||
public Long getHashIdentitySystemAndUnits() {
|
||||
return myHashIdentitySystemAndUnits;
|
||||
}
|
||||
|
||||
public void setHashIdentitySystemAndUnits(Long theHashIdentitySystemAndUnits) {
|
||||
myHashIdentitySystemAndUnits = theHashIdentitySystemAndUnits;
|
||||
}
|
||||
|
||||
public String getSystem() {
|
||||
return mySystem;
|
||||
}
|
||||
|
||||
public void setSystem(String theSystem) {
|
||||
mySystem = theSystem;
|
||||
}
|
||||
|
||||
public String getUnits() {
|
||||
return myUnits;
|
||||
}
|
||||
|
||||
public void setUnits(String theUnits) {
|
||||
myUnits = theUnits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
HashCodeBuilder b = new HashCodeBuilder();
|
||||
b.append(getResourceType());
|
||||
b.append(getParamName());
|
||||
b.append(getHashIdentity());
|
||||
b.append(getHashIdentityAndUnits());
|
||||
b.append(getHashIdentitySystemAndUnits());
|
||||
return b.toHashCode();
|
||||
}
|
||||
|
||||
|
||||
public static long calculateHashSystemAndUnits(PartitionSettings thePartitionSettings, PartitionablePartitionId theRequestPartitionId, String theResourceType, String theParamName, String theSystem, String theUnits) {
|
||||
RequestPartitionId requestPartitionId = PartitionablePartitionId.toRequestPartitionId(theRequestPartitionId);
|
||||
return calculateHashSystemAndUnits(thePartitionSettings, requestPartitionId, theResourceType, theParamName, theSystem, theUnits);
|
||||
}
|
||||
|
||||
public static long calculateHashSystemAndUnits(PartitionSettings thePartitionSettings, RequestPartitionId theRequestPartitionId, String theResourceType, String theParamName, String theSystem, String theUnits) {
|
||||
return hash(thePartitionSettings, theRequestPartitionId, theResourceType, theParamName, theSystem, theUnits);
|
||||
}
|
||||
|
||||
public static long calculateHashUnits(PartitionSettings thePartitionSettings, PartitionablePartitionId theRequestPartitionId, String theResourceType, String theParamName, String theUnits) {
|
||||
RequestPartitionId requestPartitionId = PartitionablePartitionId.toRequestPartitionId(theRequestPartitionId);
|
||||
return calculateHashUnits(thePartitionSettings, requestPartitionId, theResourceType, theParamName, theUnits);
|
||||
}
|
||||
|
||||
public static long calculateHashUnits(PartitionSettings thePartitionSettings, RequestPartitionId theRequestPartitionId, String theResourceType, String theParamName, String theUnits) {
|
||||
return hash(thePartitionSettings, theRequestPartitionId, theResourceType, theParamName, theUnits);
|
||||
}
|
||||
}
|
@ -20,16 +20,11 @@ package ca.uhn.fhir.jpa.model.entity;
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
import ca.uhn.fhir.rest.param.QuantityParam;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField;
|
||||
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.ScaledNumberField;
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
@ -40,11 +35,16 @@ import javax.persistence.Id;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.SequenceGenerator;
|
||||
import javax.persistence.Table;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField;
|
||||
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.ScaledNumberField;
|
||||
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
import ca.uhn.fhir.rest.param.QuantityParam;
|
||||
|
||||
//@formatter:off
|
||||
@Embeddable
|
||||
@ -57,49 +57,24 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
@Index(name = "IDX_SP_QUANTITY_UPDATED", columnList = "SP_UPDATED"),
|
||||
@Index(name = "IDX_SP_QUANTITY_RESID", columnList = "RES_ID")
|
||||
})
|
||||
public class ResourceIndexedSearchParamQuantity extends BaseResourceIndexedSearchParam {
|
||||
|
||||
private static final int MAX_LENGTH = 200;
|
||||
public class ResourceIndexedSearchParamQuantity extends ResourceIndexedSearchParamBaseQuantity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Column(name = "SP_SYSTEM", nullable = true, length = MAX_LENGTH)
|
||||
@FullTextField
|
||||
public String mySystem;
|
||||
|
||||
@Column(name = "SP_UNITS", nullable = true, length = MAX_LENGTH)
|
||||
@FullTextField
|
||||
public String myUnits;
|
||||
@Column(name = "SP_VALUE", nullable = true)
|
||||
|
||||
@ScaledNumberField
|
||||
public BigDecimal myValue;
|
||||
|
||||
|
||||
@Id
|
||||
@SequenceGenerator(name = "SEQ_SPIDX_QUANTITY", sequenceName = "SEQ_SPIDX_QUANTITY")
|
||||
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_QUANTITY")
|
||||
@Column(name = "SP_ID")
|
||||
private Long myId;
|
||||
/**
|
||||
* @since 3.5.0 - At some point this should be made not-null
|
||||
*/
|
||||
@Column(name = "HASH_IDENTITY_AND_UNITS", nullable = true)
|
||||
private Long myHashIdentityAndUnits;
|
||||
/**
|
||||
* @since 3.5.0 - At some point this should be made not-null
|
||||
*/
|
||||
@Column(name = "HASH_IDENTITY_SYS_UNITS", nullable = true)
|
||||
private Long myHashIdentitySystemAndUnits;
|
||||
/**
|
||||
* @since 3.5.0 - At some point this should be made not-null
|
||||
*/
|
||||
@Column(name = "HASH_IDENTITY", nullable = true)
|
||||
private Long myHashIdentity;
|
||||
|
||||
@Column(name = "SP_VALUE", nullable = true)
|
||||
@ScaledNumberField
|
||||
public BigDecimal myValue;
|
||||
|
||||
public ResourceIndexedSearchParamQuantity() {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
public ResourceIndexedSearchParamQuantity(PartitionSettings thePartitionSettings, String theResourceType, String theParamName, BigDecimal theValue, String theSystem, String theUnits) {
|
||||
this();
|
||||
setPartitionSettings(thePartitionSettings);
|
||||
@ -118,21 +93,46 @@ public class ResourceIndexedSearchParamQuantity extends BaseResourceIndexedSearc
|
||||
mySystem = source.mySystem;
|
||||
myUnits = source.myUnits;
|
||||
myValue = source.myValue;
|
||||
myHashIdentity = source.myHashIdentity;
|
||||
myHashIdentityAndUnits = source.myHashIdentitySystemAndUnits;
|
||||
myHashIdentitySystemAndUnits = source.myHashIdentitySystemAndUnits;
|
||||
setHashIdentity(source.getHashIdentity());
|
||||
setHashIdentityAndUnits(source.getHashIdentityAndUnits());
|
||||
setHashIdentitySystemAndUnits(source.getHashIdentitySystemAndUnits());
|
||||
}
|
||||
|
||||
public BigDecimal getValue() {
|
||||
return myValue;
|
||||
}
|
||||
|
||||
public ResourceIndexedSearchParamQuantity setValue(BigDecimal theValue) {
|
||||
myValue = theValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getId() {
|
||||
return myId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateHashes() {
|
||||
String resourceType = getResourceType();
|
||||
String paramName = getParamName();
|
||||
String units = getUnits();
|
||||
String system = getSystem();
|
||||
setHashIdentity(calculateHashIdentity(getPartitionSettings(), getPartitionId(), resourceType, paramName));
|
||||
setHashIdentityAndUnits(calculateHashUnits(getPartitionSettings(), getPartitionId(), resourceType, paramName, units));
|
||||
setHashIdentitySystemAndUnits(calculateHashSystemAndUnits(getPartitionSettings(), getPartitionId(), resourceType, paramName, system, units));
|
||||
public void setId(Long theId) {
|
||||
myId = theId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IQueryParameterType toQueryParameterType() {
|
||||
return new QuantityParam(null, getValue(), getSystem(), getUnits());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
|
||||
b.append("paramName", getParamName());
|
||||
b.append("resourceId", getResourcePid());
|
||||
b.append("system", getSystem());
|
||||
b.append("units", getUnits());
|
||||
b.append("value", getValue());
|
||||
b.append("missing", isMissing());
|
||||
b.append("hashIdentitySystemAndUnits", getHashIdentitySystemAndUnits());
|
||||
return b.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -154,99 +154,13 @@ public class ResourceIndexedSearchParamQuantity extends BaseResourceIndexedSearc
|
||||
b.append(getHashIdentityAndUnits(), obj.getHashIdentityAndUnits());
|
||||
b.append(getHashIdentitySystemAndUnits(), obj.getHashIdentitySystemAndUnits());
|
||||
b.append(isMissing(), obj.isMissing());
|
||||
b.append(getValue(), obj.getValue());
|
||||
return b.isEquals();
|
||||
}
|
||||
|
||||
public Long getHashIdentity() {
|
||||
return myHashIdentity;
|
||||
}
|
||||
|
||||
public void setHashIdentity(Long theHashIdentity) {
|
||||
myHashIdentity = theHashIdentity;
|
||||
}
|
||||
|
||||
public Long getHashIdentityAndUnits() {
|
||||
return myHashIdentityAndUnits;
|
||||
}
|
||||
|
||||
public void setHashIdentityAndUnits(Long theHashIdentityAndUnits) {
|
||||
myHashIdentityAndUnits = theHashIdentityAndUnits;
|
||||
}
|
||||
|
||||
private Long getHashIdentitySystemAndUnits() {
|
||||
return myHashIdentitySystemAndUnits;
|
||||
}
|
||||
|
||||
public void setHashIdentitySystemAndUnits(Long theHashIdentitySystemAndUnits) {
|
||||
myHashIdentitySystemAndUnits = theHashIdentitySystemAndUnits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getId() {
|
||||
return myId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(Long theId) {
|
||||
myId = theId;
|
||||
}
|
||||
|
||||
public String getSystem() {
|
||||
return mySystem;
|
||||
}
|
||||
|
||||
public void setSystem(String theSystem) {
|
||||
mySystem = theSystem;
|
||||
}
|
||||
|
||||
public String getUnits() {
|
||||
return myUnits;
|
||||
}
|
||||
|
||||
public void setUnits(String theUnits) {
|
||||
myUnits = theUnits;
|
||||
}
|
||||
|
||||
public BigDecimal getValue() {
|
||||
return myValue;
|
||||
}
|
||||
|
||||
public ResourceIndexedSearchParamQuantity setValue(BigDecimal theValue) {
|
||||
myValue = theValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
HashCodeBuilder b = new HashCodeBuilder();
|
||||
b.append(getResourceType());
|
||||
b.append(getParamName());
|
||||
b.append(getHashIdentity());
|
||||
b.append(getHashIdentityAndUnits());
|
||||
b.append(getHashIdentitySystemAndUnits());
|
||||
return b.toHashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IQueryParameterType toQueryParameterType() {
|
||||
return new QuantityParam(null, getValue(), getSystem(), getUnits());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
|
||||
b.append("paramName", getParamName());
|
||||
b.append("resourceId", getResourcePid());
|
||||
b.append("system", getSystem());
|
||||
b.append("units", getUnits());
|
||||
b.append("value", getValue());
|
||||
b.append("missing", isMissing());
|
||||
b.append("hashIdentitySystemAndUnits", myHashIdentitySystemAndUnits);
|
||||
return b.build();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean matches(IQueryParameterType theParam) {
|
||||
|
||||
if (!(theParam instanceof QuantityParam)) {
|
||||
return false;
|
||||
}
|
||||
@ -279,26 +193,8 @@ public class ResourceIndexedSearchParamQuantity extends BaseResourceIndexedSearc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
public static long calculateHashSystemAndUnits(PartitionSettings thePartitionSettings, PartitionablePartitionId theRequestPartitionId, String theResourceType, String theParamName, String theSystem, String theUnits) {
|
||||
RequestPartitionId requestPartitionId = PartitionablePartitionId.toRequestPartitionId(theRequestPartitionId);
|
||||
return calculateHashSystemAndUnits(thePartitionSettings, requestPartitionId, theResourceType, theParamName, theSystem, theUnits);
|
||||
}
|
||||
|
||||
public static long calculateHashSystemAndUnits(PartitionSettings thePartitionSettings, RequestPartitionId theRequestPartitionId, String theResourceType, String theParamName, String theSystem, String theUnits) {
|
||||
return hash(thePartitionSettings, theRequestPartitionId, theResourceType, theParamName, theSystem, theUnits);
|
||||
}
|
||||
|
||||
public static long calculateHashUnits(PartitionSettings thePartitionSettings, PartitionablePartitionId theRequestPartitionId, String theResourceType, String theParamName, String theUnits) {
|
||||
RequestPartitionId requestPartitionId = PartitionablePartitionId.toRequestPartitionId(theRequestPartitionId);
|
||||
return calculateHashUnits(thePartitionSettings, requestPartitionId, theResourceType, theParamName, theUnits);
|
||||
}
|
||||
|
||||
public static long calculateHashUnits(PartitionSettings thePartitionSettings, RequestPartitionId theRequestPartitionId, String theResourceType, String theParamName, String theUnits) {
|
||||
return hash(thePartitionSettings, theRequestPartitionId, theResourceType, theParamName, theUnits);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,239 @@
|
||||
package ca.uhn.fhir.jpa.model.entity;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR Model
|
||||
* %%
|
||||
* 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 static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.SequenceGenerator;
|
||||
import javax.persistence.Table;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
import ca.uhn.fhir.rest.param.QuantityParam;
|
||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||
|
||||
//@formatter:off
|
||||
@Embeddable
|
||||
@Entity
|
||||
@Table(name = "HFJ_SPIDX_QUANTITY_NRML", indexes = {
|
||||
@Index(name = "IDX_SP_QNTY_NRML_HASH", columnList = "HASH_IDENTITY,SP_VALUE"),
|
||||
@Index(name = "IDX_SP_QNTY_NRML_HASH_UN", columnList = "HASH_IDENTITY_AND_UNITS,SP_VALUE"),
|
||||
@Index(name = "IDX_SP_QNTY_NRML_HASH_SYSUN", columnList = "HASH_IDENTITY_SYS_UNITS,SP_VALUE"),
|
||||
@Index(name = "IDX_SP_QNTY_NRML_UPDATED", columnList = "SP_UPDATED"),
|
||||
@Index(name = "IDX_SP_QNTY_NRML_RESID", columnList = "RES_ID")
|
||||
})
|
||||
/**
|
||||
* Support UCUM service
|
||||
* @since 5.3.0
|
||||
*
|
||||
*/
|
||||
public class ResourceIndexedSearchParamQuantityNormalized extends ResourceIndexedSearchParamBaseQuantity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@SequenceGenerator(name = "SEQ_SPIDX_QUANTITY_NRML", sequenceName = "SEQ_SPIDX_QUANTITY_NRML")
|
||||
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_QUANTITY_NRML")
|
||||
@Column(name = "SP_ID")
|
||||
private Long myId;
|
||||
|
||||
// Changed to double here for storing the value after converted to the CanonicalForm due to BigDecimal maps NUMBER(19,2)
|
||||
// The precision may lost even to store 1.2cm which is 0.012m in the CanonicalForm
|
||||
@Column(name = "SP_VALUE", nullable = true)
|
||||
@ScaledNumberField
|
||||
public Double myValue;
|
||||
|
||||
public ResourceIndexedSearchParamQuantityNormalized() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ResourceIndexedSearchParamQuantityNormalized(PartitionSettings thePartitionSettings, String theResourceType, String theParamName, BigDecimal 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);
|
||||
}
|
||||
|
||||
calculateHashes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends BaseResourceIndex> void copyMutableValuesFrom(T theSource) {
|
||||
super.copyMutableValuesFrom(theSource);
|
||||
ResourceIndexedSearchParamQuantityNormalized source = (ResourceIndexedSearchParamQuantityNormalized) theSource;
|
||||
mySystem = source.mySystem;
|
||||
myUnits = source.myUnits;
|
||||
myValue = source.myValue;
|
||||
setHashIdentity(source.getHashIdentity());
|
||||
setHashIdentityAndUnits(source.getHashIdentityAndUnits());
|
||||
setHashIdentitySystemAndUnits(source.getHashIdentitySystemAndUnits());
|
||||
}
|
||||
|
||||
//- myValue
|
||||
public Double getValue() {
|
||||
return myValue;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
//-- myId
|
||||
@Override
|
||||
public Long getId() {
|
||||
return myId;
|
||||
}
|
||||
@Override
|
||||
public void setId(Long theId) {
|
||||
myId = theId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IQueryParameterType toQueryParameterType() {
|
||||
return new QuantityParam(null, getValue(), getSystem(), getUnits());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
|
||||
b.append("paramName", getParamName());
|
||||
b.append("resourceId", getResourcePid());
|
||||
b.append("system", getSystem());
|
||||
b.append("units", getUnits());
|
||||
b.append("value", getValue());
|
||||
b.append("missing", isMissing());
|
||||
b.append("hashIdentitySystemAndUnits", getHashIdentitySystemAndUnits());
|
||||
return b.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object theObj) {
|
||||
if (this == theObj) {
|
||||
return true;
|
||||
}
|
||||
if (theObj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(theObj instanceof ResourceIndexedSearchParamQuantityNormalized)) {
|
||||
return false;
|
||||
}
|
||||
ResourceIndexedSearchParamQuantityNormalized obj = (ResourceIndexedSearchParamQuantityNormalized) theObj;
|
||||
EqualsBuilder b = new EqualsBuilder();
|
||||
b.append(getResourceType(), obj.getResourceType());
|
||||
b.append(getParamName(), obj.getParamName());
|
||||
b.append(getHashIdentity(), obj.getHashIdentity());
|
||||
b.append(getHashIdentityAndUnits(), obj.getHashIdentityAndUnits());
|
||||
b.append(getHashIdentitySystemAndUnits(), obj.getHashIdentitySystemAndUnits());
|
||||
b.append(isMissing(), obj.isMissing());
|
||||
b.append(getValue(), obj.getValue());
|
||||
return b.isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(IQueryParameterType theParam) {
|
||||
|
||||
if (!(theParam instanceof QuantityParam)) {
|
||||
return false;
|
||||
}
|
||||
QuantityParam quantity = (QuantityParam) theParam;
|
||||
boolean retval = false;
|
||||
|
||||
String quantitySystem = quantity.getSystem();
|
||||
BigDecimal quantityValue = quantity.getValue();
|
||||
Double quantityDoubleValue = null;
|
||||
if (quantityValue != null)
|
||||
quantityDoubleValue = quantityValue.doubleValue();
|
||||
String quantityUnits = defaultString(quantity.getUnits());
|
||||
|
||||
//-- convert the value/unit to the canonical form if any, otherwise store the original value/units pair
|
||||
Pair canonicalForm = UcumServiceUtil.getCanonicalForm(quantitySystem, quantityValue, quantityUnits);
|
||||
if (canonicalForm != null) {
|
||||
quantityDoubleValue = Double.parseDouble(canonicalForm.getValue().asDecimal());
|
||||
quantityUnits = canonicalForm.getCode();
|
||||
}
|
||||
|
||||
// Only match on system if it wasn't specified
|
||||
if (quantitySystem == null && isBlank(quantityUnits)) {
|
||||
if (Objects.equals(getValue(), quantityDoubleValue)) {
|
||||
retval = true;
|
||||
}
|
||||
} else {
|
||||
String unitsString = defaultString(getUnits());
|
||||
if (quantitySystem == null) {
|
||||
if (unitsString.equalsIgnoreCase(quantityUnits) &&
|
||||
Objects.equals(getValue(), quantityDoubleValue)) {
|
||||
retval = true;
|
||||
}
|
||||
} else if (isBlank(quantityUnits)) {
|
||||
if (getSystem().equalsIgnoreCase(quantitySystem) &&
|
||||
Objects.equals(getValue(), quantityDoubleValue)) {
|
||||
retval = true;
|
||||
}
|
||||
} else {
|
||||
if (getSystem().equalsIgnoreCase(quantitySystem) &&
|
||||
unitsString.equalsIgnoreCase(quantityUnits) &&
|
||||
Objects.equals(getValue(), quantityDoubleValue)) {
|
||||
retval = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
}
|
@ -32,13 +32,10 @@ import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import org.hibernate.annotations.OptimisticLock;
|
||||
import org.hibernate.search.engine.backend.types.Projectable;
|
||||
import org.hibernate.search.engine.backend.types.Searchable;
|
||||
import org.hibernate.search.mapper.pojo.automaticindexing.ReindexOnUpdate;
|
||||
import org.hibernate.search.mapper.pojo.bridge.mapping.annotation.RoutingBinderRef;
|
||||
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.DocumentId;
|
||||
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField;
|
||||
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.GenericField;
|
||||
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed;
|
||||
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.IndexedEmbedded;
|
||||
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.IndexingDependency;
|
||||
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.ObjectPath;
|
||||
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.PropertyValue;
|
||||
@ -149,6 +146,23 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||
@Column(name = "SP_QUANTITY_PRESENT")
|
||||
@OptimisticLock(excluded = true)
|
||||
private boolean myParamsQuantityPopulated;
|
||||
|
||||
/**
|
||||
* Added to support UCUM conversion
|
||||
* since 5.3.0
|
||||
*/
|
||||
@OneToMany(mappedBy = "myResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
|
||||
@OptimisticLock(excluded = true)
|
||||
private Collection<ResourceIndexedSearchParamQuantityNormalized> myParamsQuantityNormalized;
|
||||
|
||||
/**
|
||||
* Added to support UCUM conversion,
|
||||
* NOTE : use Boolean class instead of boolean primitive, in order to set the existing rows to null
|
||||
* since 5.3.0
|
||||
*/
|
||||
@Column(name = "SP_QUANTITY_NRML_PRESENT")
|
||||
@OptimisticLock(excluded = true)
|
||||
private Boolean myParamsQuantityNormalizedPopulated = Boolean.FALSE;
|
||||
|
||||
@OneToMany(mappedBy = "myResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
|
||||
@OptimisticLock(excluded = true)
|
||||
@ -361,6 +375,21 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||
getParamsQuantity().addAll(theQuantityParams);
|
||||
}
|
||||
|
||||
public Collection<ResourceIndexedSearchParamQuantityNormalized> getParamsQuantityNormalized() {
|
||||
if (myParamsQuantityNormalized == null) {
|
||||
myParamsQuantityNormalized = new ArrayList<>();
|
||||
}
|
||||
return myParamsQuantityNormalized;
|
||||
}
|
||||
|
||||
public void setParamsQuantityNormalized(Collection<ResourceIndexedSearchParamQuantityNormalized> theQuantityNormalizedParams) {
|
||||
if (!isParamsQuantityNormalizedPopulated() && theQuantityNormalizedParams.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
getParamsQuantityNormalized().clear();
|
||||
getParamsQuantityNormalized().addAll(theQuantityNormalizedParams);
|
||||
}
|
||||
|
||||
public Collection<ResourceIndexedSearchParamString> getParamsString() {
|
||||
if (myParamsString == null) {
|
||||
myParamsString = new ArrayList<>();
|
||||
@ -503,6 +532,20 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||
public void setParamsQuantityPopulated(boolean theParamsQuantityPopulated) {
|
||||
myParamsQuantityPopulated = theParamsQuantityPopulated;
|
||||
}
|
||||
|
||||
public Boolean isParamsQuantityNormalizedPopulated() {
|
||||
if (myParamsQuantityNormalizedPopulated == null)
|
||||
return Boolean.FALSE;
|
||||
else
|
||||
return myParamsQuantityNormalizedPopulated;
|
||||
}
|
||||
|
||||
public void setParamsQuantityNormalizedPopulated(Boolean theParamsQuantityNormalizedPopulated) {
|
||||
if (theParamsQuantityNormalizedPopulated == null)
|
||||
myParamsQuantityNormalizedPopulated = Boolean.FALSE;
|
||||
else
|
||||
myParamsQuantityNormalizedPopulated = theParamsQuantityNormalizedPopulated;
|
||||
}
|
||||
|
||||
public boolean isParamsStringPopulated() {
|
||||
return myParamsStringPopulated;
|
||||
|
@ -0,0 +1,100 @@
|
||||
package ca.uhn.fhir.jpa.model.util;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR Model
|
||||
* %%
|
||||
* 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 java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.fhir.ucum.Decimal;
|
||||
import org.fhir.ucum.Pair;
|
||||
import org.fhir.ucum.UcumEssenceService;
|
||||
import org.fhir.ucum.UcumException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ca.uhn.fhir.util.ClasspathUtil;
|
||||
|
||||
/**
|
||||
* It's a wrapper of UcumEssenceService
|
||||
*
|
||||
*/
|
||||
public class UcumServiceUtil {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(UcumServiceUtil.class);
|
||||
|
||||
public static final String UCUM_CODESYSTEM_URL = "http://unitsofmeasure.org";
|
||||
private static final String UCUM_SOURCE = "/ucum-essence.xml";
|
||||
|
||||
private static UcumEssenceService myUcumEssenceService = null;
|
||||
|
||||
private UcumServiceUtil() {
|
||||
}
|
||||
|
||||
// lazy load UCUM_SOURCE only once
|
||||
private static void init() {
|
||||
|
||||
if (myUcumEssenceService != null)
|
||||
return;
|
||||
|
||||
synchronized (UcumServiceUtil.class) {
|
||||
InputStream input = ClasspathUtil.loadResourceAsStream(UCUM_SOURCE);
|
||||
try {
|
||||
myUcumEssenceService = new UcumEssenceService(input);
|
||||
|
||||
} catch (UcumException e) {
|
||||
ourLog.warn("Failed to load ucum code from ", UCUM_SOURCE, e);
|
||||
} finally {
|
||||
ClasspathUtil.close(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the canonical form of a code, it's define at
|
||||
* <link>http://unitsofmeasure.org</link>
|
||||
*
|
||||
* e.g. 12cm -> 0.12m where m is the canonical form of the length.
|
||||
*
|
||||
* @param theSystem must be http://unitsofmeasure.org
|
||||
* @param theValue the value in the original form e.g. 0.12
|
||||
* @param theCode the code in the original form e.g. 'cm'
|
||||
* @return the CanonicalForm if no error, otherwise return null
|
||||
*/
|
||||
public static Pair getCanonicalForm(String theSystem, BigDecimal theValue, String theCode) {
|
||||
|
||||
// -- only for http://unitsofmeasure.org
|
||||
if (!UCUM_CODESYSTEM_URL.equals(theSystem) || theValue == null || theCode == null)
|
||||
return null;
|
||||
|
||||
init();
|
||||
Pair theCanonicalPair = null;
|
||||
|
||||
try {
|
||||
Decimal theDecimal = new Decimal(theValue.toPlainString(), theValue.precision());
|
||||
theCanonicalPair = myUcumEssenceService.getCanonicalForm(new Pair(theDecimal, theCode));
|
||||
} catch (UcumException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return theCanonicalPair;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
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() {
|
||||
ResourceIndexedSearchParamBaseQuantity val1 = new ResourceIndexedSearchParamQuantityNormalized()
|
||||
.setValue(Double.parseDouble("123"));
|
||||
val1.setPartitionSettings(new PartitionSettings());
|
||||
val1.calculateHashes();
|
||||
ResourceIndexedSearchParamBaseQuantity val2 = new ResourceIndexedSearchParamQuantityNormalized()
|
||||
.setValue(Double.parseDouble("123"));
|
||||
val2.setPartitionSettings(new PartitionSettings());
|
||||
val2.calculateHashes();
|
||||
assertEquals(val1, val1);
|
||||
assertEquals(val1, val2);
|
||||
assertNotEquals(val1, null);
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package ca.uhn.fhir.jpa.model.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class UcumServiceUtilTest {
|
||||
|
||||
@Test
|
||||
public void testCanonicalForm() {
|
||||
|
||||
assertEquals(Double.parseDouble("0.000012"),
|
||||
Double.parseDouble(UcumServiceUtil.getCanonicalForm(UcumServiceUtil.UCUM_CODESYSTEM_URL, new BigDecimal(0.012), "mm").getValue().asDecimal()));
|
||||
|
||||
|
||||
assertEquals(Double.parseDouble("149.597870691"),
|
||||
Double.parseDouble(UcumServiceUtil.getCanonicalForm(UcumServiceUtil.UCUM_CODESYSTEM_URL, new BigDecimal(149597.870691), "mm").getValue().asDecimal()));
|
||||
|
||||
assertEquals("0.0025 m", UcumServiceUtil.getCanonicalForm(UcumServiceUtil.UCUM_CODESYSTEM_URL, new BigDecimal(2.5), "mm").toString());
|
||||
assertEquals("0.025 m", UcumServiceUtil.getCanonicalForm(UcumServiceUtil.UCUM_CODESYSTEM_URL, new BigDecimal(2.5), "cm").toString());
|
||||
assertEquals("0.25 m", UcumServiceUtil.getCanonicalForm(UcumServiceUtil.UCUM_CODESYSTEM_URL, new BigDecimal(2.5), "dm").toString());
|
||||
assertEquals("2.5 m", UcumServiceUtil.getCanonicalForm(UcumServiceUtil.UCUM_CODESYSTEM_URL, new BigDecimal(2.5), "m").toString());
|
||||
assertEquals("2500 m", UcumServiceUtil.getCanonicalForm(UcumServiceUtil.UCUM_CODESYSTEM_URL, new BigDecimal(2.5), "km").toString());
|
||||
|
||||
assertEquals(Double.parseDouble("957.4"),
|
||||
Double.parseDouble(UcumServiceUtil.getCanonicalForm(UcumServiceUtil.UCUM_CODESYSTEM_URL, new BigDecimal(95.74), "mg/dL").getValue().asDecimal()));
|
||||
|
||||
assertEquals(Double.parseDouble("957400.0"),
|
||||
Double.parseDouble(UcumServiceUtil.getCanonicalForm(UcumServiceUtil.UCUM_CODESYSTEM_URL, new BigDecimal(95.74), "g/dL").getValue().asDecimal()));
|
||||
|
||||
//-- code g.m-3
|
||||
assertEquals(Double.parseDouble("957400000"),
|
||||
Double.parseDouble(UcumServiceUtil.getCanonicalForm(UcumServiceUtil.UCUM_CODESYSTEM_URL, new BigDecimal(95.74), "kg/dL").getValue().asDecimal()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidCanonicalForm() {
|
||||
|
||||
//-- invalid url
|
||||
assertEquals(null, UcumServiceUtil.getCanonicalForm("url", new BigDecimal(2.5), "cm"));
|
||||
|
||||
//-- missing value
|
||||
assertEquals(null, UcumServiceUtil.getCanonicalForm(UcumServiceUtil.UCUM_CODESYSTEM_URL, null, "dm"));
|
||||
|
||||
//-- missing code
|
||||
assertEquals(null, UcumServiceUtil.getCanonicalForm(UcumServiceUtil.UCUM_CODESYSTEM_URL, new BigDecimal(2.5), null));
|
||||
|
||||
//-- invalid codes
|
||||
assertEquals(null, UcumServiceUtil.getCanonicalForm(UcumServiceUtil.UCUM_CODESYSTEM_URL, new BigDecimal(2.5), "xyz"));
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -34,6 +34,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
||||
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.entity.ResourceIndexedSearchParamUri;
|
||||
@ -200,7 +201,10 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
||||
extractor = createReferenceExtractor();
|
||||
return extractReferenceParamsAsQueryTokens(theSearchParam, theResource, extractor);
|
||||
case QUANTITY:
|
||||
extractor = createQuantityExtractor(theResource);
|
||||
if (myModelConfig.isNormalizedQuantitySearchSupported())
|
||||
extractor = createQuantityNormalizedExtractor(theResource);
|
||||
else
|
||||
extractor = createQuantityExtractor(theResource);
|
||||
break;
|
||||
case URI:
|
||||
extractor = createUriExtractor(theResource);
|
||||
@ -373,7 +377,14 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
||||
return extractSearchParams(theResource, extractor, RestSearchParameterTypeEnum.QUANTITY);
|
||||
}
|
||||
|
||||
private IExtractor<ResourceIndexedSearchParamQuantity> createQuantityExtractor(IBaseResource theResource) {
|
||||
|
||||
@Override
|
||||
public SearchParamSet<ResourceIndexedSearchParamQuantityNormalized> extractSearchParamQuantityNormalized(IBaseResource theResource) {
|
||||
IExtractor<ResourceIndexedSearchParamQuantityNormalized> extractor = createQuantityNormalizedExtractor(theResource);
|
||||
return extractSearchParams(theResource, extractor, RestSearchParameterTypeEnum.QUANTITY);
|
||||
}
|
||||
|
||||
private IExtractor<ResourceIndexedSearchParamQuantity> createQuantityExtractor(IBaseResource theResource) {
|
||||
return (params, searchParam, value, path) -> {
|
||||
if (value.getClass().equals(myLocationPositionDefinition.getImplementingClass())) {
|
||||
return;
|
||||
@ -383,7 +394,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);
|
||||
@ -395,9 +406,35 @@ 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;
|
||||
}
|
||||
|
||||
String nextType = toRootTypeName(value);
|
||||
String resourceType = toRootTypeName(theResource);
|
||||
switch (nextType) {
|
||||
case "Quantity":
|
||||
addQuantity_QuantityNormalized(resourceType, params, searchParam, value);
|
||||
break;
|
||||
case "Money":
|
||||
addQuantity_MoneyNormalized(resourceType, params, searchParam, value);
|
||||
break;
|
||||
case "Range":
|
||||
addQuantity_RangeNormalized(resourceType, params, searchParam, value);
|
||||
break;
|
||||
default:
|
||||
addUnexpectedDatatypeWarning(params, searchParam, value);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SearchParamSet<ResourceIndexedSearchParamString> extractSearchParamStrings(IBaseResource theResource) {
|
||||
IExtractor<ResourceIndexedSearchParamString> extractor = createStringExtractor(theResource);
|
||||
@ -502,7 +539,6 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
||||
}
|
||||
|
||||
private void addQuantity_Quantity(String theResourceType, Set<ResourceIndexedSearchParamQuantity> 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();
|
||||
@ -510,13 +546,25 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
BigDecimal nextValueValue = valueField.get().getValue();
|
||||
@ -524,21 +572,45 @@ 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_Range(String theResourceType, Set<ResourceIndexedSearchParamQuantity> 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();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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));
|
||||
|
||||
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);
|
||||
@ -553,7 +625,6 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
||||
createStringIndexIfNotBlank(theResourceType, theParams, theSearchParam, text);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected boolean shouldIndexTextComponentOfToken(RuntimeSearchParam theSearchParam) {
|
||||
|
@ -1,21 +1,5 @@
|
||||
package ca.uhn.fhir.jpa.searchparam.extractor;
|
||||
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.*;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
@ -37,6 +21,24 @@ import java.util.List;
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.*;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
||||
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.ResourceIndexedSearchParamUri;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
public interface ISearchParamExtractor {
|
||||
|
||||
// SearchParamSet<ResourceIndexedSearchParamCoords> extractSearchParamCoords(IBaseResource theResource);
|
||||
@ -47,6 +49,8 @@ public interface ISearchParamExtractor {
|
||||
|
||||
SearchParamSet<ResourceIndexedSearchParamQuantity> extractSearchParamQuantity(IBaseResource theResource);
|
||||
|
||||
SearchParamSet<ResourceIndexedSearchParamQuantityNormalized> extractSearchParamQuantityNormalized(IBaseResource theResource);
|
||||
|
||||
SearchParamSet<ResourceIndexedSearchParamString> extractSearchParamStrings(IBaseResource theResource);
|
||||
|
||||
SearchParamSet<BaseResourceIndexedSearchParam> extractSearchParamTokens(IBaseResource theResource);
|
||||
|
@ -1,5 +1,6 @@
|
||||
package ca.uhn.fhir.jpa.searchparam.extractor;
|
||||
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Search Parameters
|
||||
@ -29,6 +30,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
||||
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.entity.ResourceIndexedSearchParamUri;
|
||||
@ -58,6 +60,7 @@ public final class ResourceIndexedSearchParams {
|
||||
final public Collection<ResourceIndexedSearchParamToken> myTokenParams = new HashSet<>();
|
||||
final public Collection<ResourceIndexedSearchParamNumber> myNumberParams = new ArrayList<>();
|
||||
final public Collection<ResourceIndexedSearchParamQuantity> myQuantityParams = new ArrayList<>();
|
||||
final public Collection<ResourceIndexedSearchParamQuantityNormalized> myQuantityNormalizedParams = new ArrayList<>();
|
||||
final public Collection<ResourceIndexedSearchParamDate> myDateParams = new ArrayList<>();
|
||||
final public Collection<ResourceIndexedSearchParamUri> myUriParams = new ArrayList<>();
|
||||
final public Collection<ResourceIndexedSearchParamCoords> myCoordsParams = new ArrayList<>();
|
||||
@ -82,6 +85,9 @@ public final class ResourceIndexedSearchParams {
|
||||
if (theEntity.isParamsQuantityPopulated()) {
|
||||
myQuantityParams.addAll(theEntity.getParamsQuantity());
|
||||
}
|
||||
if (theEntity.isParamsQuantityNormalizedPopulated()) {
|
||||
myQuantityNormalizedParams.addAll(theEntity.getParamsQuantityNormalized());
|
||||
}
|
||||
if (theEntity.isParamsDatePopulated()) {
|
||||
myDateParams.addAll(theEntity.getParamsDate());
|
||||
}
|
||||
@ -110,6 +116,7 @@ public final class ResourceIndexedSearchParams {
|
||||
theEntity.setParamsTokenPopulated(myTokenParams.isEmpty() == false);
|
||||
theEntity.setParamsNumberPopulated(myNumberParams.isEmpty() == false);
|
||||
theEntity.setParamsQuantityPopulated(myQuantityParams.isEmpty() == false);
|
||||
theEntity.setParamsQuantityNormalizedPopulated(myQuantityNormalizedParams.isEmpty() == false);
|
||||
theEntity.setParamsDatePopulated(myDateParams.isEmpty() == false);
|
||||
theEntity.setParamsUriPopulated(myUriParams.isEmpty() == false);
|
||||
theEntity.setParamsCoordsPopulated(myCoordsParams.isEmpty() == false);
|
||||
@ -123,6 +130,7 @@ public final class ResourceIndexedSearchParams {
|
||||
theEntity.setParamsToken(myTokenParams);
|
||||
theEntity.setParamsNumber(myNumberParams);
|
||||
theEntity.setParamsQuantity(myQuantityParams);
|
||||
theEntity.setParamsQuantityNormalized(myQuantityNormalizedParams);
|
||||
theEntity.setParamsDate(myDateParams);
|
||||
theEntity.setParamsUri(myUriParams);
|
||||
theEntity.setParamsCoords(myCoordsParams);
|
||||
@ -133,6 +141,7 @@ public final class ResourceIndexedSearchParams {
|
||||
setUpdatedTime(myStringParams, theUpdateTime);
|
||||
setUpdatedTime(myNumberParams, theUpdateTime);
|
||||
setUpdatedTime(myQuantityParams, theUpdateTime);
|
||||
setUpdatedTime(myQuantityNormalizedParams, theUpdateTime);
|
||||
setUpdatedTime(myDateParams, theUpdateTime);
|
||||
setUpdatedTime(myUriParams, theUpdateTime);
|
||||
setUpdatedTime(myCoordsParams, theUpdateTime);
|
||||
@ -150,6 +159,7 @@ public final class ResourceIndexedSearchParams {
|
||||
}
|
||||
|
||||
public boolean matchParam(ModelConfig theModelConfig, String theResourceName, String theParamName, RuntimeSearchParam theParamDef, IQueryParameterType theParam) {
|
||||
|
||||
if (theParamDef == null) {
|
||||
return false;
|
||||
}
|
||||
@ -159,7 +169,10 @@ public final class ResourceIndexedSearchParams {
|
||||
resourceParams = myTokenParams;
|
||||
break;
|
||||
case QUANTITY:
|
||||
resourceParams = myQuantityParams;
|
||||
if (theModelConfig.isNormalizedQuantitySearchSupported())
|
||||
resourceParams = myQuantityNormalizedParams;
|
||||
else
|
||||
resourceParams = myQuantityParams;
|
||||
break;
|
||||
case STRING:
|
||||
resourceParams = myStringParams;
|
||||
@ -250,6 +263,7 @@ public final class ResourceIndexedSearchParams {
|
||||
", tokenParams=" + myTokenParams +
|
||||
", numberParams=" + myNumberParams +
|
||||
", quantityParams=" + myQuantityParams +
|
||||
", quantityNormalizedParams=" + myQuantityNormalizedParams +
|
||||
", dateParams=" + myDateParams +
|
||||
", uriParams=" + myUriParams +
|
||||
", coordsParams=" + myCoordsParams +
|
||||
@ -261,7 +275,10 @@ 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);
|
||||
findMissingSearchParams(thePartitionSettings, theModelConfig, theEntity, theActiveSearchParams, RestSearchParameterTypeEnum.QUANTITY, myQuantityParams);
|
||||
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.DATE, myDateParams);
|
||||
findMissingSearchParams(thePartitionSettings, theModelConfig, theEntity, theActiveSearchParams, RestSearchParameterTypeEnum.URI, myUriParams);
|
||||
findMissingSearchParams(thePartitionSettings, theModelConfig, theEntity, theActiveSearchParams, RestSearchParameterTypeEnum.TOKEN, myTokenParams);
|
||||
@ -292,7 +309,10 @@ public final class ResourceIndexedSearchParams {
|
||||
param = new ResourceIndexedSearchParamNumber();
|
||||
break;
|
||||
case QUANTITY:
|
||||
param = new ResourceIndexedSearchParamQuantity();
|
||||
if (theModelConfig.isNormalizedQuantitySearchSupported())
|
||||
param = new ResourceIndexedSearchParamQuantityNormalized();
|
||||
else
|
||||
param = new ResourceIndexedSearchParamQuantity();
|
||||
break;
|
||||
case STRING:
|
||||
param = new ResourceIndexedSearchParamString()
|
||||
@ -382,8 +402,7 @@ public final class ResourceIndexedSearchParams {
|
||||
return queryStringsToPopulate;
|
||||
}
|
||||
|
||||
private static void extractCompositeStringUniquesValueChains(String
|
||||
theResourceType, List<List<String>> thePartsChoices, List<String> theValues, Set<String> theQueryStringsToPopulate) {
|
||||
private static void extractCompositeStringUniquesValueChains(String theResourceType, List<List<String>> thePartsChoices, List<String> theValues, Set<String> theQueryStringsToPopulate) {
|
||||
if (thePartsChoices.size() > 0) {
|
||||
List<String> nextList = thePartsChoices.get(0);
|
||||
Collections.sort(nextList);
|
||||
|
@ -35,6 +35,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
||||
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.entity.ResourceIndexedSearchParamUri;
|
||||
@ -103,7 +104,7 @@ public class SearchParamExtractorService {
|
||||
}
|
||||
|
||||
private void extractSearchIndexParameters(RequestDetails theRequestDetails, ResourceIndexedSearchParams theParams, IBaseResource theResource, ResourceTable theEntity) {
|
||||
|
||||
|
||||
// Strings
|
||||
ISearchParamExtractor.SearchParamSet<ResourceIndexedSearchParamString> strings = extractSearchParamStrings(theResource);
|
||||
handleWarnings(theRequestDetails, myInterceptorBroadcaster, strings);
|
||||
@ -118,7 +119,13 @@ public class SearchParamExtractorService {
|
||||
ISearchParamExtractor.SearchParamSet<ResourceIndexedSearchParamQuantity> quantities = extractSearchParamQuantity(theResource);
|
||||
handleWarnings(theRequestDetails, myInterceptorBroadcaster, quantities);
|
||||
theParams.myQuantityParams.addAll(quantities);
|
||||
|
||||
|
||||
if (myModelConfig.isNormalizedQuantityStorageSupported()|| myModelConfig.isNormalizedQuantitySearchSupported()) {
|
||||
ISearchParamExtractor.SearchParamSet<ResourceIndexedSearchParamQuantityNormalized> quantitiesNormalized = extractSearchParamQuantityNormalized(theResource);
|
||||
handleWarnings(theRequestDetails, myInterceptorBroadcaster, quantitiesNormalized);
|
||||
theParams.myQuantityNormalizedParams.addAll(quantitiesNormalized);
|
||||
}
|
||||
|
||||
// Dates
|
||||
ISearchParamExtractor.SearchParamSet<ResourceIndexedSearchParamDate> dates = extractSearchParamDates(theResource);
|
||||
handleWarnings(theRequestDetails, myInterceptorBroadcaster, dates);
|
||||
@ -151,6 +158,7 @@ public class SearchParamExtractorService {
|
||||
// Do this after, because we add to strings during both string and token processing
|
||||
populateResourceTable(theParams.myNumberParams, theEntity);
|
||||
populateResourceTable(theParams.myQuantityParams, theEntity);
|
||||
populateResourceTable(theParams.myQuantityNormalizedParams, theEntity);
|
||||
populateResourceTable(theParams.myDateParams, theEntity);
|
||||
populateResourceTable(theParams.myUriParams, theEntity);
|
||||
populateResourceTable(theParams.myTokenParams, theEntity);
|
||||
@ -378,6 +386,10 @@ public class SearchParamExtractorService {
|
||||
return mySearchParamExtractor.extractSearchParamQuantity(theResource);
|
||||
}
|
||||
|
||||
private ISearchParamExtractor.SearchParamSet<ResourceIndexedSearchParamQuantityNormalized> extractSearchParamQuantityNormalized(IBaseResource theResource) {
|
||||
return mySearchParamExtractor.extractSearchParamQuantityNormalized(theResource);
|
||||
}
|
||||
|
||||
private ISearchParamExtractor.SearchParamSet<ResourceIndexedSearchParamString> extractSearchParamStrings(IBaseResource theResource) {
|
||||
return mySearchParamExtractor.extractSearchParamStrings(theResource);
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ package ca.uhn.fhir.jpa.subscription.module;
|
||||
* #%L
|
||||
* HAPI FHIR Subscription Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2020 University Health Network
|
||||
* 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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user