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