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.jpa.model.config.PartitionSettings;
023import ca.uhn.fhir.jpa.model.listener.IndexStorageOptimizationListener;
024import ca.uhn.fhir.model.api.IQueryParameterType;
025import jakarta.annotation.Nullable;
026import jakarta.persistence.Column;
027import jakarta.persistence.Entity;
028import jakarta.persistence.EntityListeners;
029import jakarta.persistence.FetchType;
030import jakarta.persistence.ForeignKey;
031import jakarta.persistence.GeneratedValue;
032import jakarta.persistence.GenerationType;
033import jakarta.persistence.Id;
034import jakarta.persistence.IdClass;
035import jakarta.persistence.Index;
036import jakarta.persistence.JoinColumn;
037import jakarta.persistence.JoinColumns;
038import jakarta.persistence.ManyToOne;
039import jakarta.persistence.Table;
040import org.apache.commons.lang3.builder.EqualsBuilder;
041import org.apache.commons.lang3.builder.HashCodeBuilder;
042import org.apache.commons.lang3.builder.ToStringBuilder;
043import org.apache.commons.lang3.builder.ToStringStyle;
044import org.hibernate.annotations.GenericGenerator;
045
046@EntityListeners(IndexStorageOptimizationListener.class)
047@Entity
048@Table(
049                name = "HFJ_SPIDX_COORDS",
050                indexes = {
051                        @Index(
052                                        name = "IDX_SP_COORDS_HASH_V2",
053                                        columnList = "HASH_IDENTITY,SP_LATITUDE,SP_LONGITUDE,RES_ID,PARTITION_ID"),
054                        @Index(name = "IDX_SP_COORDS_UPDATED", columnList = "SP_UPDATED"),
055                        @Index(name = "IDX_SP_COORDS_RESID", columnList = "RES_ID")
056                })
057@IdClass(IdAndPartitionId.class)
058public class ResourceIndexedSearchParamCoords extends BaseResourceIndexedSearchParam {
059
060        public static final int MAX_LENGTH = 100;
061
062        private static final long serialVersionUID = 1L;
063
064        @Column(name = "SP_LATITUDE", nullable = true)
065        public Double myLatitude;
066
067        @Column(name = "SP_LONGITUDE", nullable = true)
068        public Double myLongitude;
069
070        @Id
071        @GenericGenerator(name = "SEQ_SPIDX_COORDS", type = ca.uhn.fhir.jpa.model.dialect.HapiSequenceStyleGenerator.class)
072        @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_COORDS")
073        @Column(name = "SP_ID")
074        private Long myId;
075
076        @ManyToOne(
077                        optional = false,
078                        fetch = FetchType.LAZY,
079                        cascade = {})
080        @JoinColumns(
081                        value = {
082                                @JoinColumn(
083                                                name = "RES_ID",
084                                                referencedColumnName = "RES_ID",
085                                                insertable = false,
086                                                updatable = false,
087                                                nullable = false),
088                                @JoinColumn(
089                                                name = "PARTITION_ID",
090                                                referencedColumnName = "PARTITION_ID",
091                                                insertable = false,
092                                                updatable = false,
093                                                nullable = false)
094                        },
095                        foreignKey = @ForeignKey(name = "FKC97MPK37OKWU8QVTCEG2NH9VN"))
096        private ResourceTable myResource;
097
098        @Column(name = "RES_ID", nullable = false)
099        private Long myResourceId;
100
101        public ResourceIndexedSearchParamCoords() {}
102
103        public ResourceIndexedSearchParamCoords(
104                        PartitionSettings thePartitionSettings,
105                        String theResourceType,
106                        String theParamName,
107                        double theLatitude,
108                        double theLongitude) {
109                setPartitionSettings(thePartitionSettings);
110                setResourceType(theResourceType);
111                setParamName(theParamName);
112                setLatitude(theLatitude);
113                setLongitude(theLongitude);
114                calculateHashes();
115        }
116
117        @Override
118        public void clearHashes() {
119                myHashIdentity = null;
120        }
121
122        @Override
123        public void calculateHashes() {
124                if (myHashIdentity != null) {
125                        return;
126                }
127
128                String resourceType = getResourceType();
129                String paramName = getParamName();
130                setHashIdentity(calculateHashIdentity(getPartitionSettings(), getPartitionId(), resourceType, paramName));
131        }
132
133        @Override
134        public boolean equals(Object theObj) {
135                if (this == theObj) {
136                        return true;
137                }
138                if (theObj == null) {
139                        return false;
140                }
141                if (!(theObj instanceof ResourceIndexedSearchParamCoords)) {
142                        return false;
143                }
144                ResourceIndexedSearchParamCoords obj = (ResourceIndexedSearchParamCoords) theObj;
145                EqualsBuilder b = new EqualsBuilder();
146                b.append(getHashIdentity(), obj.getHashIdentity());
147                b.append(getLatitude(), obj.getLatitude());
148                b.append(getLongitude(), obj.getLongitude());
149                b.append(isMissing(), obj.isMissing());
150                return b.isEquals();
151        }
152
153        @Override
154        public <T extends BaseResourceIndex> void copyMutableValuesFrom(T theSource) {
155                super.copyMutableValuesFrom(theSource);
156                ResourceIndexedSearchParamCoords source = (ResourceIndexedSearchParamCoords) theSource;
157                myLatitude = source.getLatitude();
158                myLongitude = source.getLongitude();
159                myHashIdentity = source.myHashIdentity;
160        }
161
162        @Override
163        public void setResourceId(Long theResourceId) {
164                myResourceId = theResourceId;
165        }
166
167        @Override
168        public Long getId() {
169                return myId;
170        }
171
172        @Override
173        public void setId(Long theId) {
174                myId = theId;
175        }
176
177        @Nullable
178        public Double getLatitude() {
179                return myLatitude;
180        }
181
182        public ResourceIndexedSearchParamCoords setLatitude(double theLatitude) {
183                myLatitude = theLatitude;
184                return this;
185        }
186
187        @Nullable
188        public Double getLongitude() {
189                return myLongitude;
190        }
191
192        public ResourceIndexedSearchParamCoords setLongitude(double theLongitude) {
193                myLongitude = theLongitude;
194                return this;
195        }
196
197        @Override
198        public int hashCode() {
199                HashCodeBuilder b = new HashCodeBuilder();
200                b.append(getHashIdentity());
201                b.append(getLatitude());
202                b.append(getLongitude());
203                b.append(isMissing());
204                return b.toHashCode();
205        }
206
207        @Override
208        public IQueryParameterType toQueryParameterType() {
209                return null;
210        }
211
212        @Override
213        public String toString() {
214                ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
215                b.append("paramName", getParamName());
216                b.append("resourceId", getResourcePid());
217                if (isMissing()) {
218                        b.append("missing", isMissing());
219                } else {
220                        b.append("lat", getLatitude());
221                        b.append("lon", getLongitude());
222                }
223                return b.build();
224        }
225
226        @Override
227        public ResourceTable getResource() {
228                return myResource;
229        }
230
231        @Override
232        public BaseResourceIndexedSearchParam setResource(ResourceTable theResource) {
233                myResource = theResource;
234                setResourceType(theResource.getResourceType());
235                return this;
236        }
237}