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}