
001/*- 002 * #%L 003 * HAPI FHIR JPA Model 004 * %% 005 * Copyright (C) 2014 - 2025 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.interceptor.model.RequestPartitionId; 023import ca.uhn.fhir.jpa.model.config.PartitionSettings; 024import ca.uhn.fhir.jpa.model.util.SearchParamHash; 025import jakarta.persistence.Column; 026import jakarta.persistence.Entity; 027import jakarta.persistence.FetchType; 028import jakarta.persistence.ForeignKey; 029import jakarta.persistence.GeneratedValue; 030import jakarta.persistence.GenerationType; 031import jakarta.persistence.Id; 032import jakarta.persistence.IdClass; 033import jakarta.persistence.Index; 034import jakarta.persistence.JoinColumn; 035import jakarta.persistence.JoinColumns; 036import jakarta.persistence.ManyToOne; 037import jakarta.persistence.Table; 038import jakarta.persistence.Transient; 039import org.apache.commons.lang3.builder.CompareToBuilder; 040import org.apache.commons.lang3.builder.EqualsBuilder; 041import org.apache.commons.lang3.builder.HashCodeBuilder; 042import org.apache.commons.lang3.builder.ToStringBuilder; 043import org.hibernate.annotations.GenericGenerator; 044 045@Entity 046@Table( 047 name = ResourceIndexedComboTokenNonUnique.HFJ_IDX_CMB_TOK_NU, 048 indexes = { 049 // TODO: The hash index was added in 7.4.0 - In 7.6.0 we should drop the string index 050 // As of 8.6.0 the string equivalent column is nullable 051 @Index(name = "IDX_IDXCMBTOKNU_STR", columnList = "IDX_STRING", unique = false), 052 @Index(name = "IDX_IDXCMBTOKNU_HASHC", columnList = "HASH_COMPLETE,RES_ID,PARTITION_ID", unique = false), 053 @Index(name = "IDX_IDXCMBTOKNU_RES", columnList = "RES_ID", unique = false) 054 }) 055@IdClass(IdAndPartitionId.class) 056public class ResourceIndexedComboTokenNonUnique extends BaseResourceIndexedCombo 057 implements Comparable<ResourceIndexedComboTokenNonUnique>, IResourceIndexComboSearchParameter { 058 059 public static final String HFJ_IDX_CMB_TOK_NU = "HFJ_IDX_CMB_TOK_NU"; 060 061 @GenericGenerator( 062 name = "SEQ_IDXCMBTOKNU_ID", 063 type = ca.uhn.fhir.jpa.model.dialect.HapiSequenceStyleGenerator.class) 064 @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_IDXCMBTOKNU_ID") 065 @Id 066 @Column(name = "PID") 067 private Long myId; 068 069 @ManyToOne( 070 optional = false, 071 fetch = FetchType.LAZY, 072 cascade = {}) 073 @JoinColumns( 074 value = { 075 @JoinColumn( 076 name = "RES_ID", 077 referencedColumnName = "RES_ID", 078 insertable = false, 079 updatable = false, 080 nullable = true), 081 @JoinColumn( 082 name = "PARTITION_ID", 083 referencedColumnName = "PARTITION_ID", 084 insertable = false, 085 updatable = false, 086 nullable = true) 087 }, 088 foreignKey = @ForeignKey(name = "FK_IDXCMBTOKNU_RES_ID")) 089 private ResourceTable myResource; 090 091 @Column(name = "RES_ID", updatable = false, nullable = true) 092 private Long myResourceId; 093 094 @Column(name = "HASH_COMPLETE", nullable = false) 095 private Long myHashComplete; 096 097 @Column(name = "IDX_STRING", nullable = true, length = ResourceIndexedComboStringUnique.MAX_STRING_LENGTH) 098 private String myIndexString; 099 100 @Transient 101 private transient PartitionSettings myPartitionSettings; 102 103 /** 104 * Constructor 105 */ 106 public ResourceIndexedComboTokenNonUnique() { 107 super(); 108 } 109 110 public ResourceIndexedComboTokenNonUnique( 111 PartitionSettings thePartitionSettings, ResourceTable theEntity, String theQueryString) { 112 myPartitionSettings = thePartitionSettings; 113 myResource = theEntity; 114 myIndexString = theQueryString; 115 calculateHashes(); 116 } 117 118 @Override 119 public String getIndexString() { 120 return myIndexString; 121 } 122 123 public void setIndexString(String theIndexString) { 124 myIndexString = theIndexString; 125 } 126 127 @Override 128 public boolean equals(Object theO) { 129 calculateHashes(); 130 131 if (this == theO) { 132 return true; 133 } 134 135 if (theO == null || getClass() != theO.getClass()) { 136 return false; 137 } 138 139 ResourceIndexedComboTokenNonUnique that = (ResourceIndexedComboTokenNonUnique) theO; 140 141 EqualsBuilder b = new EqualsBuilder(); 142 b.append(getHashComplete(), that.getHashComplete()); 143 return b.isEquals(); 144 } 145 146 @Override 147 public <T extends BaseResourceIndex> void copyMutableValuesFrom(T theSource) { 148 ResourceIndexedComboTokenNonUnique source = (ResourceIndexedComboTokenNonUnique) theSource; 149 myPartitionSettings = source.myPartitionSettings; 150 myHashComplete = source.myHashComplete; 151 myIndexString = source.myIndexString; 152 } 153 154 @Override 155 public void setResourceId(Long theResourceId) { 156 myResourceId = theResourceId; 157 } 158 159 @Override 160 public Long getId() { 161 return myId; 162 } 163 164 @Override 165 public void setId(Long theId) { 166 myId = theId; 167 } 168 169 @Override 170 public void clearHashes() { 171 myHashComplete = null; 172 } 173 174 @Override 175 public void calculateHashes() { 176 if (myHashComplete != null) { 177 return; 178 } 179 180 PartitionSettings partitionSettings = getPartitionSettings(); 181 PartitionablePartitionId partitionId = getPartitionId(); 182 String queryString = myIndexString; 183 setHashComplete(calculateHashComplete(partitionSettings, partitionId, queryString)); 184 } 185 186 @Override 187 public int hashCode() { 188 calculateHashes(); 189 190 HashCodeBuilder builder = new HashCodeBuilder(17, 37); 191 builder.append(getHashComplete()); 192 return builder.toHashCode(); 193 } 194 195 public PartitionSettings getPartitionSettings() { 196 return myPartitionSettings; 197 } 198 199 public void setPartitionSettings(PartitionSettings thePartitionSettings) { 200 myPartitionSettings = thePartitionSettings; 201 } 202 203 @Override 204 public ResourceTable getResource() { 205 return myResource; 206 } 207 208 @Override 209 public void setResource(ResourceTable theResource) { 210 myResource = theResource; 211 } 212 213 public Long getHashComplete() { 214 return myHashComplete; 215 } 216 217 public void setHashComplete(Long theHashComplete) { 218 myHashComplete = theHashComplete; 219 } 220 221 @Override 222 public int compareTo(ResourceIndexedComboTokenNonUnique theO) { 223 CompareToBuilder b = new CompareToBuilder(); 224 b.append(myHashComplete, theO.getHashComplete()); 225 return b.toComparison(); 226 } 227 228 @Override 229 public String toString() { 230 return new ToStringBuilder(this) 231 .append("id", myId) 232 .append("resourceId", myResourceId) 233 .append("hashComplete", myHashComplete) 234 .append("indexString", myIndexString) 235 .toString(); 236 } 237 238 public static long calculateHashComplete( 239 PartitionSettings partitionSettings, PartitionablePartitionId thePartitionId, String queryString) { 240 RequestPartitionId requestPartitionId = PartitionablePartitionId.toRequestPartitionId(thePartitionId); 241 return SearchParamHash.hashSearchParam(partitionSettings, requestPartitionId, queryString); 242 } 243}