001package ca.uhn.fhir.jpa.model.entity; 002 003/* 004 * #%L 005 * HAPI FHIR JPA Model 006 * %% 007 * Copyright (C) 2014 - 2022 Smile CDR, Inc. 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import static org.apache.commons.lang3.StringUtils.defaultString; 024import static org.apache.commons.lang3.StringUtils.isBlank; 025 026import java.math.BigDecimal; 027import java.util.Objects; 028 029import javax.persistence.Column; 030import javax.persistence.Embeddable; 031import javax.persistence.Entity; 032import javax.persistence.GeneratedValue; 033import javax.persistence.GenerationType; 034import javax.persistence.Id; 035import javax.persistence.Index; 036import javax.persistence.SequenceGenerator; 037import javax.persistence.Table; 038 039import org.apache.commons.lang3.builder.EqualsBuilder; 040import org.apache.commons.lang3.builder.ToStringBuilder; 041import org.apache.commons.lang3.builder.ToStringStyle; 042import org.fhir.ucum.Pair; 043import org.hibernate.search.mapper.pojo.mapping.definition.annotation.ScaledNumberField; 044 045 046import ca.uhn.fhir.jpa.model.config.PartitionSettings; 047import ca.uhn.fhir.model.api.IQueryParameterType; 048import ca.uhn.fhir.rest.param.QuantityParam; 049import ca.uhn.fhir.jpa.model.util.UcumServiceUtil; 050 051//@formatter:off 052@Embeddable 053@Entity 054@Table(name = "HFJ_SPIDX_QUANTITY_NRML", indexes = { 055 @Index(name = "IDX_SP_QNTY_NRML_HASH", columnList = "HASH_IDENTITY,SP_VALUE"), 056 @Index(name = "IDX_SP_QNTY_NRML_HASH_UN", columnList = "HASH_IDENTITY_AND_UNITS,SP_VALUE"), 057 @Index(name = "IDX_SP_QNTY_NRML_HASH_SYSUN", columnList = "HASH_IDENTITY_SYS_UNITS,SP_VALUE"), 058 @Index(name = "IDX_SP_QNTY_NRML_UPDATED", columnList = "SP_UPDATED"), 059 @Index(name = "IDX_SP_QNTY_NRML_RESID", columnList = "RES_ID") 060}) 061/** 062 * Support UCUM service 063 * @since 5.3.0 064 * 065 */ 066public class ResourceIndexedSearchParamQuantityNormalized extends ResourceIndexedSearchParamBaseQuantity { 067 068 private static final long serialVersionUID = 1L; 069 070 @Id 071 @SequenceGenerator(name = "SEQ_SPIDX_QUANTITY_NRML", sequenceName = "SEQ_SPIDX_QUANTITY_NRML") 072 @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_QUANTITY_NRML") 073 @Column(name = "SP_ID") 074 private Long myId; 075 076 // Changed to double here for storing the value after converted to the CanonicalForm due to BigDecimal maps NUMBER(19,2) 077 // The precision may lost even to store 1.2cm which is 0.012m in the CanonicalForm 078 @Column(name = "SP_VALUE", nullable = true) 079 @ScaledNumberField 080 public Double myValue; 081 082 public ResourceIndexedSearchParamQuantityNormalized() { 083 super(); 084 } 085 086 public ResourceIndexedSearchParamQuantityNormalized(PartitionSettings thePartitionSettings, String theResourceType, String theParamName, double theValue, String theSystem, String theUnits) { 087 this(); 088 setPartitionSettings(thePartitionSettings); 089 setResourceType(theResourceType); 090 setParamName(theParamName); 091 setSystem(theSystem); 092 setValue(theValue); 093 setUnits(theUnits); 094 calculateHashes(); 095 } 096 097 @Override 098 public <T extends BaseResourceIndex> void copyMutableValuesFrom(T theSource) { 099 super.copyMutableValuesFrom(theSource); 100 ResourceIndexedSearchParamQuantityNormalized source = (ResourceIndexedSearchParamQuantityNormalized) theSource; 101 mySystem = source.mySystem; 102 myUnits = source.myUnits; 103 myValue = source.myValue; 104 setHashIdentity(source.getHashIdentity()); 105 setHashIdentityAndUnits(source.getHashIdentityAndUnits()); 106 setHashIdentitySystemAndUnits(source.getHashIdentitySystemAndUnits()); 107 } 108 109 //- myValue 110 public Double getValue() { 111 return myValue; 112 } 113 public ResourceIndexedSearchParamQuantityNormalized setValue(Double theValue) { 114 myValue = theValue; 115 return this; 116 } 117 118 public ResourceIndexedSearchParamQuantityNormalized setValue(double theValue) { 119 myValue = theValue; 120 return this; 121 } 122 123 //-- myId 124 @Override 125 public Long getId() { 126 return myId; 127 } 128 @Override 129 public void setId(Long theId) { 130 myId = theId; 131 } 132 133 @Override 134 public IQueryParameterType toQueryParameterType() { 135 return new QuantityParam(null, getValue(), getSystem(), getUnits()); 136 } 137 138 @Override 139 public String toString() { 140 ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); 141 b.append("paramName", getParamName()); 142 b.append("resourceId", getResourcePid()); 143 b.append("system", getSystem()); 144 b.append("units", getUnits()); 145 b.append("value", getValue()); 146 b.append("missing", isMissing()); 147 b.append("hashIdentitySystemAndUnits", getHashIdentitySystemAndUnits()); 148 return b.build(); 149 } 150 151 @Override 152 public boolean equals(Object theObj) { 153 if (this == theObj) { 154 return true; 155 } 156 if (theObj == null) { 157 return false; 158 } 159 if (!(theObj instanceof ResourceIndexedSearchParamQuantityNormalized)) { 160 return false; 161 } 162 ResourceIndexedSearchParamQuantityNormalized obj = (ResourceIndexedSearchParamQuantityNormalized) theObj; 163 EqualsBuilder b = new EqualsBuilder(); 164 b.append(getResourceType(), obj.getResourceType()); 165 b.append(getParamName(), obj.getParamName()); 166 b.append(getHashIdentity(), obj.getHashIdentity()); 167 b.append(getHashIdentityAndUnits(), obj.getHashIdentityAndUnits()); 168 b.append(getHashIdentitySystemAndUnits(), obj.getHashIdentitySystemAndUnits()); 169 b.append(isMissing(), obj.isMissing()); 170 b.append(getValue(), obj.getValue()); 171 return b.isEquals(); 172 } 173 174 @Override 175 public boolean matches(IQueryParameterType theParam) { 176 177 if (!(theParam instanceof QuantityParam)) { 178 return false; 179 } 180 QuantityParam quantity = (QuantityParam) theParam; 181 boolean retval = false; 182 183 String quantitySystem = quantity.getSystem(); 184 BigDecimal quantityValue = quantity.getValue(); 185 Double quantityDoubleValue = null; 186 if (quantityValue != null) 187 quantityDoubleValue = quantityValue.doubleValue(); 188 String quantityUnits = defaultString(quantity.getUnits()); 189 190 //-- convert the value/unit to the canonical form if any, otherwise store the original value/units pair 191 Pair canonicalForm = UcumServiceUtil.getCanonicalForm(quantitySystem, quantityValue, quantityUnits); 192 if (canonicalForm != null) { 193 quantityDoubleValue = Double.parseDouble(canonicalForm.getValue().asDecimal()); 194 quantityUnits = canonicalForm.getCode(); 195 } 196 197 // Only match on system if it wasn't specified 198 if (quantitySystem == null && isBlank(quantityUnits)) { 199 if (Objects.equals(getValue(), quantityDoubleValue)) { 200 retval = true; 201 } 202 } else { 203 String unitsString = defaultString(getUnits()); 204 if (quantitySystem == null) { 205 if (unitsString.equalsIgnoreCase(quantityUnits) && 206 Objects.equals(getValue(), quantityDoubleValue)) { 207 retval = true; 208 } 209 } else if (isBlank(quantityUnits)) { 210 if (getSystem().equalsIgnoreCase(quantitySystem) && 211 Objects.equals(getValue(), quantityDoubleValue)) { 212 retval = true; 213 } 214 } else { 215 if (getSystem().equalsIgnoreCase(quantitySystem) && 216 unitsString.equalsIgnoreCase(quantityUnits) && 217 Objects.equals(getValue(), quantityDoubleValue)) { 218 retval = true; 219 } 220 } 221 } 222 223 return retval; 224 } 225}