+ * The default value is {@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED} which is current behavior.
+ *
+ *
+ * Here is the UCUM service support level
+ *
+ *
{@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED}, default, Quantity is stored in {@link ResourceIndexedSearchParamQuantity} only and it is used by searching.
+ *
{@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_STORAGE_SUPPORTED}, Quantity is stored in both {@link ResourceIndexedSearchParamQuantity} and {@link ResourceIndexedSearchParamQuantityNormalized}, but {@link ResourceIndexedSearchParamQuantity} is used by searching.
+ *
{@link NormalizedQuantitySearchLevel#NORMALIZED_QUANTITY_SEARCH_SUPPORTED}, Quantity is stored in both {@link ResourceIndexedSearchParamQuantity} and {@link ResourceIndexedSearchParamQuantityNormalized}, {@link ResourceIndexedSearchParamQuantityNormalized} is used by searching.
+ *
{@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.
+ *
+ *
+ *
+ * @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;
+ }
}
diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/NormalizedQuantitySearchLevel.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/NormalizedQuantitySearchLevel.java
new file mode 100644
index 00000000000..764a8c26d78
--- /dev/null
+++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/NormalizedQuantitySearchLevel.java
@@ -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,
+}
diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamBaseQuantity.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamBaseQuantity.java
new file mode 100644
index 00000000000..9e35c2c5bff
--- /dev/null
+++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamBaseQuantity.java
@@ -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);
+ }
+}
diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamQuantity.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamQuantity.java
index 5813c3b4a93..d435650cda0 100644
--- a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamQuantity.java
+++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamQuantity.java
@@ -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);
- }
-
-
-}
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamQuantityNormalized.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamQuantityNormalized.java
new file mode 100644
index 00000000000..0234d0fa4a2
--- /dev/null
+++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamQuantityNormalized.java
@@ -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 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;
+ }
+}
diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceTable.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceTable.java
index f0a9c24103d..0b6ac43c384 100644
--- a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceTable.java
+++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceTable.java
@@ -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 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 getParamsQuantityNormalized() {
+ if (myParamsQuantityNormalized == null) {
+ myParamsQuantityNormalized = new ArrayList<>();
+ }
+ return myParamsQuantityNormalized;
+ }
+
+ public void setParamsQuantityNormalized(Collection theQuantityNormalizedParams) {
+ if (!isParamsQuantityNormalizedPopulated() && theQuantityNormalizedParams.isEmpty()) {
+ return;
+ }
+ getParamsQuantityNormalized().clear();
+ getParamsQuantityNormalized().addAll(theQuantityNormalizedParams);
+ }
+
public Collection 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;
diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/util/UcumServiceUtil.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/util/UcumServiceUtil.java
new file mode 100644
index 00000000000..3224067fbc0
--- /dev/null
+++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/util/UcumServiceUtil.java
@@ -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
+ * http://unitsofmeasure.org
+ *
+ * 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;
+ }
+
+}
diff --git a/hapi-fhir-jpaserver-model/src/test/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamQuantityNormalizedTest.java b/hapi-fhir-jpaserver-model/src/test/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamQuantityNormalizedTest.java
new file mode 100644
index 00000000000..4affba1865c
--- /dev/null
+++ b/hapi-fhir-jpaserver-model/src/test/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamQuantityNormalizedTest.java
@@ -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());
+ }
+
+}
diff --git a/hapi-fhir-jpaserver-model/src/test/java/ca/uhn/fhir/jpa/model/util/UcumServiceUtilTest.java b/hapi-fhir-jpaserver-model/src/test/java/ca/uhn/fhir/jpa/model/util/UcumServiceUtilTest.java
new file mode 100644
index 00000000000..2ca1bd1e4d5
--- /dev/null
+++ b/hapi-fhir-jpaserver-model/src/test/java/ca/uhn/fhir/jpa/model/util/UcumServiceUtilTest.java
@@ -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"));
+
+ }
+
+}
diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/BaseSearchParamExtractor.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/BaseSearchParamExtractor.java
index cd0e7ef1a60..25af4ddb6c4 100644
--- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/BaseSearchParamExtractor.java
+++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/BaseSearchParamExtractor.java
@@ -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 createQuantityExtractor(IBaseResource theResource) {
+
+ @Override
+ public SearchParamSet extractSearchParamQuantityNormalized(IBaseResource theResource) {
+ IExtractor extractor = createQuantityNormalizedExtractor(theResource);
+ return extractSearchParams(theResource, extractor, RestSearchParameterTypeEnum.QUANTITY);
+ }
+
+ private IExtractor 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 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 extractSearchParamStrings(IBaseResource theResource) {
IExtractor extractor = createStringExtractor(theResource);
@@ -502,7 +539,6 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
}
private void addQuantity_Quantity(String theResourceType, Set theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
-
Optional> 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 theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
+ Optional> 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 theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
-
Optional> 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 theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
+
+ private void addQuantity_MoneyNormalized(String theResourceType, Set theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
+ Optional> 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 theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
Optional low = myRangeLowValueChild.getAccessor().getFirstValueOrNull(theValue);
low.ifPresent(theIBase -> addQuantity_Quantity(theResourceType, theParams, theSearchParam, theIBase));
Optional 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 theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
+ Optional low = myRangeLowValueChild.getAccessor().getFirstValueOrNull(theValue);
+ low.ifPresent(theIBase -> addQuantity_QuantityNormalized(theResourceType, theParams, theSearchParam, theIBase));
+
+ Optional high = myRangeHighValueChild.getAccessor().getFirstValueOrNull(theValue);
+ high.ifPresent(theIBase -> addQuantity_QuantityNormalized(theResourceType, theParams, theSearchParam, theIBase));
+ }
+
private void addToken_Identifier(String theResourceType, Set 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) {
diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ISearchParamExtractor.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ISearchParamExtractor.java
index 06e2c018555..891e2dd9202 100644
--- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ISearchParamExtractor.java
+++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ISearchParamExtractor.java
@@ -1,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 extractSearchParamCoords(IBaseResource theResource);
@@ -47,6 +49,8 @@ public interface ISearchParamExtractor {
SearchParamSet extractSearchParamQuantity(IBaseResource theResource);
+ SearchParamSet extractSearchParamQuantityNormalized(IBaseResource theResource);
+
SearchParamSet extractSearchParamStrings(IBaseResource theResource);
SearchParamSet extractSearchParamTokens(IBaseResource theResource);
diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ResourceIndexedSearchParams.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ResourceIndexedSearchParams.java
index 7b88c96a9a9..3006df3ddec 100644
--- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ResourceIndexedSearchParams.java
+++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ResourceIndexedSearchParams.java
@@ -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 myTokenParams = new HashSet<>();
final public Collection myNumberParams = new ArrayList<>();
final public Collection myQuantityParams = new ArrayList<>();
+ final public Collection myQuantityNormalizedParams = new ArrayList<>();
final public Collection myDateParams = new ArrayList<>();
final public Collection myUriParams = new ArrayList<>();
final public Collection 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> 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> thePartsChoices, List theValues, Set theQueryStringsToPopulate) {
+ private static void extractCompositeStringUniquesValueChains(String theResourceType, List> thePartsChoices, List theValues, Set theQueryStringsToPopulate) {
if (thePartsChoices.size() > 0) {
List nextList = thePartsChoices.get(0);
Collections.sort(nextList);
diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/SearchParamExtractorService.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/SearchParamExtractorService.java
index 725252c78b1..1727f6a1ba4 100644
--- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/SearchParamExtractorService.java
+++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/SearchParamExtractorService.java
@@ -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 strings = extractSearchParamStrings(theResource);
handleWarnings(theRequestDetails, myInterceptorBroadcaster, strings);
@@ -118,7 +119,13 @@ public class SearchParamExtractorService {
ISearchParamExtractor.SearchParamSet quantities = extractSearchParamQuantity(theResource);
handleWarnings(theRequestDetails, myInterceptorBroadcaster, quantities);
theParams.myQuantityParams.addAll(quantities);
-
+
+ if (myModelConfig.isNormalizedQuantityStorageSupported()|| myModelConfig.isNormalizedQuantitySearchSupported()) {
+ ISearchParamExtractor.SearchParamSet quantitiesNormalized = extractSearchParamQuantityNormalized(theResource);
+ handleWarnings(theRequestDetails, myInterceptorBroadcaster, quantitiesNormalized);
+ theParams.myQuantityNormalizedParams.addAll(quantitiesNormalized);
+ }
+
// Dates
ISearchParamExtractor.SearchParamSet 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 extractSearchParamQuantityNormalized(IBaseResource theResource) {
+ return mySearchParamExtractor.extractSearchParamQuantityNormalized(theResource);
+ }
+
private ISearchParamExtractor.SearchParamSet extractSearchParamStrings(IBaseResource theResource) {
return mySearchParamExtractor.extractSearchParamStrings(theResource);
}
diff --git a/hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/module/SubscriptionTestConfig.java b/hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/module/SubscriptionTestConfig.java
index 0ea13ede15e..e46ba54cf6f 100644
--- a/hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/module/SubscriptionTestConfig.java
+++ b/hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/module/SubscriptionTestConfig.java
@@ -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.