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 jakarta.persistence.Column;
025import jakarta.persistence.Entity;
026import jakarta.persistence.ForeignKey;
027import jakarta.persistence.GeneratedValue;
028import jakarta.persistence.GenerationType;
029import jakarta.persistence.Id;
030import jakarta.persistence.IdClass;
031import jakarta.persistence.Index;
032import jakarta.persistence.JoinColumn;
033import jakarta.persistence.JoinColumns;
034import jakarta.persistence.ManyToOne;
035import jakarta.persistence.PrePersist;
036import jakarta.persistence.Table;
037import jakarta.persistence.Transient;
038import org.apache.commons.lang3.Validate;
039import org.apache.commons.lang3.builder.EqualsBuilder;
040import org.apache.commons.lang3.builder.HashCodeBuilder;
041import org.apache.commons.lang3.builder.ToStringBuilder;
042import org.apache.commons.lang3.builder.ToStringStyle;
043import org.hibernate.annotations.GenericGenerator;
044
045import java.io.Serializable;
046
047import static ca.uhn.fhir.jpa.model.util.SearchParamHash.hashSearchParam;
048
049@Entity
050@Table(
051                name = "HFJ_RES_PARAM_PRESENT",
052                indexes = {
053                        // We used to have a constraint named IDX_RESPARMPRESENT_SPID_RESID - Don't reuse
054                        @Index(name = "IDX_RESPARMPRESENT_RESID", columnList = "RES_ID"),
055                        @Index(name = "IDX_RESPARMPRESENT_HASHPRES", columnList = "HASH_PRESENCE")
056                })
057@IdClass(IdAndPartitionId.class)
058public class SearchParamPresentEntity extends BasePartitionable implements Serializable {
059
060        private static final long serialVersionUID = 1L;
061
062        @Id
063        @GenericGenerator(
064                        name = "SEQ_RESPARMPRESENT_ID",
065                        type = ca.uhn.fhir.jpa.model.dialect.HapiSequenceStyleGenerator.class)
066        @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_RESPARMPRESENT_ID")
067        @Column(name = "PID")
068        private Long myId;
069
070        @Column(name = "SP_PRESENT", nullable = false)
071        private boolean myPresent;
072
073        @ManyToOne()
074        @JoinColumns(
075                        value = {
076                                @JoinColumn(
077                                                name = "RES_ID",
078                                                referencedColumnName = "RES_ID",
079                                                insertable = false,
080                                                updatable = false,
081                                                nullable = false),
082                                @JoinColumn(
083                                                name = "PARTITION_ID",
084                                                referencedColumnName = "PARTITION_ID",
085                                                insertable = false,
086                                                updatable = false,
087                                                nullable = false),
088                        },
089                        foreignKey = @ForeignKey(name = "FK_RESPARMPRES_RESID"))
090        private ResourceTable myResource;
091
092        @Column(name = "RES_ID", nullable = false, updatable = false)
093        private Long myResourcePid;
094
095        @Transient
096        private transient String myParamName;
097
098        @Column(name = "HASH_PRESENCE")
099        private Long myHashPresence;
100
101        @Transient
102        private transient PartitionSettings myPartitionSettings;
103
104        /**
105         * Constructor
106         */
107        public SearchParamPresentEntity() {
108                super();
109        }
110
111        /**
112         * Constructor
113         */
114        public SearchParamPresentEntity(String theParamName, boolean thePresent) {
115                myParamName = theParamName;
116                myPresent = thePresent;
117        }
118
119        @SuppressWarnings("unused")
120        @PrePersist
121        public void calculateHashes() {
122                if (myHashPresence == null && getParamName() != null) {
123                        String resourceType = getResource().getResourceType();
124                        String paramName = getParamName();
125                        boolean present = myPresent;
126                        setHashPresence(
127                                        calculateHashPresence(getPartitionSettings(), getPartitionId(), resourceType, paramName, present));
128                }
129        }
130
131        public Long getHashPresence() {
132                Validate.notNull(myHashPresence);
133                return myHashPresence;
134        }
135
136        public void setHashPresence(Long theHashPresence) {
137                myHashPresence = theHashPresence;
138        }
139
140        public String getParamName() {
141                return myParamName;
142        }
143
144        public void setParamName(String theParamName) {
145                myParamName = theParamName;
146        }
147
148        public ResourceTable getResource() {
149                return myResource;
150        }
151
152        public void setResource(ResourceTable theResourceTable) {
153                myResource = theResourceTable;
154                myResourcePid = theResourceTable.getId().getId();
155                myPartitionIdValue = theResourceTable.getPartitionId().getPartitionId();
156        }
157
158        public boolean isPresent() {
159                return myPresent;
160        }
161
162        public void setPresent(boolean thePresent) {
163                myPresent = thePresent;
164        }
165
166        @Override
167        public boolean equals(Object theO) {
168                if (this == theO) return true;
169
170                if (theO == null || getClass() != theO.getClass()) return false;
171
172                SearchParamPresentEntity that = (SearchParamPresentEntity) theO;
173
174                EqualsBuilder b = new EqualsBuilder();
175                b.append(getHashPresence(), that.getHashPresence());
176                return b.isEquals();
177        }
178
179        @Override
180        public int hashCode() {
181                HashCodeBuilder b = new HashCodeBuilder(17, 37);
182                b.append(getHashPresence());
183                return b.toHashCode();
184        }
185
186        @Override
187        public String toString() {
188                ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
189
190                b.append("resPid", myResource.getIdDt().toUnqualifiedVersionless().getValue());
191                b.append("paramName", myParamName);
192                b.append("present", myPresent);
193                b.append("partition", getPartitionId());
194                return b.build();
195        }
196
197        public PartitionSettings getPartitionSettings() {
198                return myPartitionSettings;
199        }
200
201        public void setPartitionSettings(PartitionSettings thePartitionSettings) {
202                myPartitionSettings = thePartitionSettings;
203        }
204
205        /**
206         * Copy all mutable values from the given source
207         */
208        public void updateValues(SearchParamPresentEntity theSource) {
209                setPartitionId(theSource.getPartitionId());
210                setResource(theSource.getResource());
211                setPartitionSettings(theSource.getPartitionSettings());
212                setHashPresence(theSource.getHashPresence());
213                setParamName(theSource.getParamName());
214                setPresent(theSource.isPresent());
215        }
216
217        public static long calculateHashPresence(
218                        PartitionSettings thePartitionSettings,
219                        PartitionablePartitionId theRequestPartitionId,
220                        String theResourceType,
221                        String theParamName,
222                        Boolean thePresent) {
223                RequestPartitionId requestPartitionId = PartitionablePartitionId.toRequestPartitionId(theRequestPartitionId);
224                return calculateHashPresence(
225                                thePartitionSettings, requestPartitionId, theResourceType, theParamName, thePresent);
226        }
227
228        public static long calculateHashPresence(
229                        PartitionSettings thePartitionSettings,
230                        RequestPartitionId theRequestPartitionId,
231                        String theResourceType,
232                        String theParamName,
233                        Boolean thePresent) {
234                String string = thePresent != null ? Boolean.toString(thePresent) : Boolean.toString(false);
235                return hashSearchParam(thePartitionSettings, theRequestPartitionId, theResourceType, theParamName, string);
236        }
237}