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