001/*-
002 * #%L
003 * HAPI FHIR JPA Server
004 * %%
005 * Copyright (C) 2014 - 2023 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.entity;
021
022import ca.uhn.fhir.jpa.model.dao.JpaPid;
023import ca.uhn.fhir.jpa.model.entity.AuditableBasePartitionable;
024import ca.uhn.fhir.jpa.model.entity.ResourceTable;
025import ca.uhn.fhir.mdm.api.IMdmLink;
026import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
027import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
028import org.apache.commons.lang3.builder.ToStringBuilder;
029import org.hibernate.envers.AuditTable;
030import org.hibernate.envers.Audited;
031import org.hibernate.envers.NotAudited;
032
033import java.util.Date;
034import javax.persistence.Column;
035import javax.persistence.Entity;
036import javax.persistence.EnumType;
037import javax.persistence.Enumerated;
038import javax.persistence.FetchType;
039import javax.persistence.ForeignKey;
040import javax.persistence.GeneratedValue;
041import javax.persistence.GenerationType;
042import javax.persistence.Id;
043import javax.persistence.Index;
044import javax.persistence.JoinColumn;
045import javax.persistence.ManyToOne;
046import javax.persistence.SequenceGenerator;
047import javax.persistence.Table;
048import javax.persistence.Temporal;
049import javax.persistence.TemporalType;
050import javax.persistence.UniqueConstraint;
051
052@Entity
053@Table(
054                name = "MPI_LINK",
055                uniqueConstraints = {
056                        // TODO GGG DROP this index, and instead use the below one
057                        @UniqueConstraint(
058                                        name = "IDX_EMPI_PERSON_TGT",
059                                        columnNames = {"PERSON_PID", "TARGET_PID"}),
060                        // TODO GGG Should i make individual indices for PERSON/TARGET?
061                },
062                indexes = {
063                        @Index(name = "IDX_EMPI_MATCH_TGT_VER", columnList = "MATCH_RESULT, TARGET_PID, VERSION"),
064                        // v---- this one
065                        @Index(name = "IDX_EMPI_GR_TGT", columnList = "GOLDEN_RESOURCE_PID, TARGET_PID"),
066                        @Index(name = "FK_EMPI_LINK_TARGET", columnList = "TARGET_PID")
067                })
068@Audited
069// This is the table name generated by default by envers, but we set it explicitly for clarity
070@AuditTable("MPI_LINK_AUD")
071public class MdmLink extends AuditableBasePartitionable implements IMdmLink<JpaPid> {
072        public static final int VERSION_LENGTH = 16;
073        private static final int MATCH_RESULT_LENGTH = 16;
074        private static final int LINK_SOURCE_LENGTH = 16;
075        public static final int SOURCE_TYPE_LENGTH = 40;
076
077        @SequenceGenerator(name = "SEQ_EMPI_LINK_ID", sequenceName = "SEQ_EMPI_LINK_ID")
078        @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_EMPI_LINK_ID")
079        @Id
080        @Column(name = "PID")
081        private Long myId;
082
083        @ManyToOne(
084                        optional = false,
085                        fetch = FetchType.LAZY,
086                        cascade = {})
087        @JoinColumn(
088                        name = "GOLDEN_RESOURCE_PID",
089                        referencedColumnName = "RES_ID",
090                        foreignKey = @ForeignKey(name = "FK_EMPI_LINK_GOLDEN_RESOURCE"),
091                        insertable = false,
092                        updatable = false,
093                        nullable = false)
094        @NotAudited
095        private ResourceTable myGoldenResource;
096
097        @Column(name = "GOLDEN_RESOURCE_PID", nullable = false)
098        private Long myGoldenResourcePid;
099
100        @Deprecated
101        @ManyToOne(
102                        optional = false,
103                        fetch = FetchType.LAZY,
104                        cascade = {})
105        @JoinColumn(
106                        name = "PERSON_PID",
107                        referencedColumnName = "RES_ID",
108                        foreignKey = @ForeignKey(name = "FK_EMPI_LINK_PERSON"),
109                        insertable = false,
110                        updatable = false,
111                        nullable = false)
112        @NotAudited
113        private ResourceTable myPerson;
114
115        @Deprecated
116        @Column(name = "PERSON_PID", nullable = false)
117        private Long myPersonPid;
118
119        @ManyToOne(
120                        optional = false,
121                        fetch = FetchType.LAZY,
122                        cascade = {})
123        @JoinColumn(
124                        name = "TARGET_PID",
125                        referencedColumnName = "RES_ID",
126                        foreignKey = @ForeignKey(name = "FK_EMPI_LINK_TARGET"),
127                        insertable = false,
128                        updatable = false,
129                        nullable = false)
130        @NotAudited
131        private ResourceTable mySource;
132
133        @Column(name = "TARGET_PID", updatable = false, nullable = false)
134        private Long mySourcePid;
135
136        @Column(name = "MATCH_RESULT", nullable = false)
137        @Enumerated(EnumType.ORDINAL)
138        private MdmMatchResultEnum myMatchResult;
139
140        @Column(name = "LINK_SOURCE", nullable = false)
141        @Enumerated(EnumType.ORDINAL)
142        private MdmLinkSourceEnum myLinkSource;
143
144        @Temporal(TemporalType.TIMESTAMP)
145        @Column(name = "CREATED", nullable = false)
146        private Date myCreated;
147
148        @Temporal(TemporalType.TIMESTAMP)
149        @Column(name = "UPDATED", nullable = false)
150        private Date myUpdated;
151
152        @Column(name = "VERSION", nullable = false, length = VERSION_LENGTH)
153        private String myVersion;
154
155        /** This link was created as a result of an eid match **/
156        @Column(name = "EID_MATCH")
157        private Boolean myEidMatch;
158
159        /** This link created a new person **/
160        @Column(name = "NEW_PERSON")
161        private Boolean myHadToCreateNewGoldenResource;
162
163        @Column(name = "VECTOR")
164        private Long myVector;
165
166        @Column(name = "SCORE")
167        private Double myScore;
168
169        // TODO GGG GL-1340
170        @Column(name = "RULE_COUNT")
171        private Long myRuleCount;
172
173        public MdmLink() {}
174
175        public MdmLink(String theVersion) {
176                myVersion = theVersion;
177        }
178
179        @Column(name = "TARGET_TYPE", nullable = true, length = SOURCE_TYPE_LENGTH)
180        private String myMdmSourceType;
181
182        @Override
183        public JpaPid getId() {
184                return JpaPid.fromId(myId);
185        }
186
187        @Override
188        public MdmLink setId(JpaPid theId) {
189                myId = theId.getId();
190                return this;
191        }
192
193        @Override
194        public JpaPid getGoldenResourcePersistenceId() {
195                return JpaPid.fromId(myGoldenResourcePid);
196        }
197
198        @Override
199        public IMdmLink setGoldenResourcePersistenceId(JpaPid theGoldenResourcePid) {
200                Long longPid = theGoldenResourcePid.getId();
201                setPersonPid(longPid);
202
203                myGoldenResourcePid = longPid;
204                return this;
205        }
206
207        @Override
208        public JpaPid getSourcePersistenceId() {
209                return JpaPid.fromId(mySourcePid);
210        }
211
212        @Override
213        public IMdmLink setSourcePersistenceId(JpaPid theSourcePid) {
214                mySourcePid = theSourcePid.getId();
215                return this;
216        }
217
218        public ResourceTable getGoldenResource() {
219                return myGoldenResource;
220        }
221
222        public MdmLink setGoldenResource(ResourceTable theGoldenResource) {
223                myGoldenResource = theGoldenResource;
224                myGoldenResourcePid = theGoldenResource.getId();
225
226                myPerson = theGoldenResource;
227                myPersonPid = theGoldenResource.getId();
228
229                return this;
230        }
231
232        @Deprecated
233        public Long getGoldenResourcePid() {
234                return myGoldenResourcePid;
235        }
236
237        /**
238         * @deprecated  Use {@link #setGoldenResourcePid(Long)} instead
239         */
240        @Deprecated
241        public MdmLink setPersonPid(Long thePersonPid) {
242                myPersonPid = thePersonPid;
243                return this;
244        }
245
246        /**
247         * @deprecated  Use {@link #setGoldenResourcePersistenceId(JpaPid)} instead
248         */
249        @Deprecated
250        public MdmLink setGoldenResourcePid(Long theGoldenResourcePid) {
251                setPersonPid(theGoldenResourcePid);
252
253                myGoldenResourcePid = theGoldenResourcePid;
254                return this;
255        }
256
257        public ResourceTable getSource() {
258                return mySource;
259        }
260
261        public MdmLink setSource(ResourceTable theSource) {
262                mySource = theSource;
263                mySourcePid = theSource.getId();
264                return this;
265        }
266
267        @Deprecated
268        public Long getSourcePid() {
269                return mySourcePid;
270        }
271
272        /**
273         * @deprecated  Use {@link #setSourcePersistenceId(JpaPid)} instead
274         */
275        @Deprecated
276        public MdmLink setSourcePid(Long theSourcePid) {
277                mySourcePid = theSourcePid;
278                return this;
279        }
280
281        @Override
282        public MdmMatchResultEnum getMatchResult() {
283                return myMatchResult;
284        }
285
286        @Override
287        public MdmLink setMatchResult(MdmMatchResultEnum theMatchResult) {
288                myMatchResult = theMatchResult;
289                return this;
290        }
291
292        @Override
293        public MdmLinkSourceEnum getLinkSource() {
294                return myLinkSource;
295        }
296
297        @Override
298        public MdmLink setLinkSource(MdmLinkSourceEnum theLinkSource) {
299                myLinkSource = theLinkSource;
300                return this;
301        }
302
303        @Override
304        public Date getCreated() {
305                return myCreated;
306        }
307
308        @Override
309        public MdmLink setCreated(Date theCreated) {
310                myCreated = theCreated;
311                return this;
312        }
313
314        @Override
315        public Date getUpdated() {
316                return myUpdated;
317        }
318
319        @Override
320        public MdmLink setUpdated(Date theUpdated) {
321                myUpdated = theUpdated;
322                return this;
323        }
324
325        @Override
326        public String getVersion() {
327                return myVersion;
328        }
329
330        @Override
331        public MdmLink setVersion(String theVersion) {
332                myVersion = theVersion;
333                return this;
334        }
335
336        @Override
337        public Long getVector() {
338                return myVector;
339        }
340
341        @Override
342        public MdmLink setVector(Long theVector) {
343                myVector = theVector;
344                return this;
345        }
346
347        @Override
348        public Double getScore() {
349                return myScore;
350        }
351
352        @Override
353        public MdmLink setScore(Double theScore) {
354                myScore = theScore;
355                return this;
356        }
357
358        public Boolean getEidMatch() {
359                return myEidMatch;
360        }
361
362        /**
363         * Note that this method can not be called <code>getEidMatch</code> or
364         * <code>isEidMatch</code> because Hibernate Search complains about having
365         * 2 accessors for this property
366         */
367        @Override
368        public Boolean isEidMatchPresent() {
369                return myEidMatch != null && myEidMatch;
370        }
371
372        @Override
373        public MdmLink setEidMatch(Boolean theEidMatch) {
374                myEidMatch = theEidMatch;
375                return this;
376        }
377
378        @Override
379        public Boolean getHadToCreateNewGoldenResource() {
380                return myHadToCreateNewGoldenResource != null && myHadToCreateNewGoldenResource;
381        }
382
383        @Override
384        public MdmLink setHadToCreateNewGoldenResource(Boolean theHadToCreateNewResource) {
385                myHadToCreateNewGoldenResource = theHadToCreateNewResource;
386                return this;
387        }
388
389        public MdmLink setMdmSourceType(String mdmSourceType) {
390                myMdmSourceType = mdmSourceType;
391                return this;
392        }
393
394        @Override
395        public String toString() {
396                return new ToStringBuilder(this)
397                                .append("myId", myId)
398                                .append("myGoldenResource", myGoldenResourcePid)
399                                .append("mySourcePid", mySourcePid)
400                                .append("myMdmSourceType", myMdmSourceType)
401                                .append("myMatchResult", myMatchResult)
402                                .append("myLinkSource", myLinkSource)
403                                .append("myEidMatch", myEidMatch)
404                                .append("myHadToCreateNewResource", myHadToCreateNewGoldenResource)
405                                .append("myScore", myScore)
406                                .append("myRuleCount", myRuleCount)
407                                .append("myPartitionId", getPartitionId())
408                                .toString();
409        }
410
411        public String getMdmSourceType() {
412                return myMdmSourceType;
413        }
414
415        public Long getRuleCount() {
416                return myRuleCount;
417        }
418
419        public MdmLink setRuleCount(Long theRuleCount) {
420                myRuleCount = theRuleCount;
421                return this;
422        }
423}