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