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