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}