001/* 002 * #%L 003 * HAPI FHIR JPA Server 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.entity; 021 022import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId; 023import ca.uhn.hapi.fhir.sql.hibernatesvc.PartitionedIdProperty; 024import jakarta.persistence.Column; 025import jakarta.persistence.Embeddable; 026import jakarta.persistence.EmbeddedId; 027import jakarta.persistence.Entity; 028import jakarta.persistence.EnumType; 029import jakarta.persistence.Enumerated; 030import jakarta.persistence.FetchType; 031import jakarta.persistence.ForeignKey; 032import jakarta.persistence.GeneratedValue; 033import jakarta.persistence.GenerationType; 034import jakarta.persistence.Index; 035import jakarta.persistence.JoinColumn; 036import jakarta.persistence.JoinColumns; 037import jakarta.persistence.ManyToOne; 038import jakarta.persistence.PrePersist; 039import jakarta.persistence.SequenceGenerator; 040import jakarta.persistence.Table; 041import org.apache.commons.lang3.builder.ToStringBuilder; 042import org.apache.commons.lang3.builder.ToStringStyle; 043import org.hibernate.annotations.JdbcTypeCode; 044import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField; 045import org.hibernate.type.SqlTypes; 046 047import java.io.Serializable; 048import java.util.Objects; 049 050@Entity 051@Table( 052 name = "TRM_CONCEPT_PC_LINK", 053 indexes = { 054 // must have same name that indexed FK or SchemaMigrationTest complains because H2 sets this index 055 // automatically 056 @Index(name = "FK_TERM_CONCEPTPC_CHILD", columnList = "CHILD_PID", unique = false), 057 @Index(name = "FK_TERM_CONCEPTPC_PARENT", columnList = "PARENT_PID", unique = false), 058 @Index(name = "FK_TERM_CONCEPTPC_CS", columnList = "CODESYSTEM_PID") 059 }) 060public class TermConceptParentChildLink implements Serializable { 061 private static final long serialVersionUID = 1L; 062 063 @ManyToOne(fetch = FetchType.LAZY) 064 @JoinColumns( 065 value = { 066 @JoinColumn( 067 name = "CHILD_PID", 068 insertable = false, 069 updatable = false, 070 nullable = false, 071 referencedColumnName = "PID"), 072 @JoinColumn( 073 name = "PARTITION_ID", 074 referencedColumnName = "PARTITION_ID", 075 insertable = false, 076 updatable = false, 077 nullable = false) 078 }, 079 foreignKey = @ForeignKey(name = "FK_TERM_CONCEPTPC_CHILD")) 080 private TermConcept myChild; 081 082 @Column(name = "CHILD_PID", insertable = true, updatable = true, nullable = false) 083 private Long myChildPid; 084 085 @ManyToOne(fetch = FetchType.LAZY) 086 @JoinColumns( 087 value = { 088 @JoinColumn( 089 name = "CODESYSTEM_PID", 090 referencedColumnName = "PID", 091 insertable = false, 092 updatable = false, 093 nullable = false), 094 @JoinColumn( 095 name = "PARTITION_ID", 096 referencedColumnName = "PARTITION_ID", 097 insertable = false, 098 updatable = false, 099 nullable = false) 100 }, 101 foreignKey = @ForeignKey(name = "FK_TERM_CONCEPTPC_CS")) 102 private TermCodeSystemVersion myCodeSystem; 103 104 @Column(name = "CODESYSTEM_PID", insertable = true, updatable = true, nullable = false) 105 @FullTextField(name = "myCodeSystemVersionPid") 106 private Long myCodeSystemVersionPid; 107 108 @ManyToOne( 109 fetch = FetchType.LAZY, 110 cascade = {}) 111 @JoinColumns( 112 value = { 113 @JoinColumn( 114 name = "PARENT_PID", 115 insertable = false, 116 updatable = false, 117 nullable = false, 118 referencedColumnName = "PID"), 119 @JoinColumn( 120 name = "PARTITION_ID", 121 referencedColumnName = "PARTITION_ID", 122 insertable = false, 123 updatable = false, 124 nullable = false) 125 }, 126 foreignKey = @ForeignKey(name = "FK_TERM_CONCEPTPC_PARENT")) 127 private TermConcept myParent; 128 129 @Column(name = "PARENT_PID", insertable = true, updatable = true, nullable = false) 130 private Long myParentPid; 131 132 @EmbeddedId 133 private TermConceptParentChildLinkPk myId; 134 135 @Column(name = PartitionablePartitionId.PARTITION_ID, nullable = true, insertable = false, updatable = false) 136 private Integer myPartitionIdValue; 137 138 @Enumerated(EnumType.ORDINAL) 139 @Column(name = "REL_TYPE", length = 5, nullable = true) 140 @JdbcTypeCode(SqlTypes.INTEGER) 141 private RelationshipTypeEnum myRelationshipType; 142 143 @Override 144 public boolean equals(Object obj) { 145 if (this == obj) return true; 146 if (obj == null) return false; 147 if (getClass() != obj.getClass()) return false; 148 TermConceptParentChildLink other = (TermConceptParentChildLink) obj; 149 if (myChild == null) { 150 if (other.myChild != null) return false; 151 } else if (!myChild.equals(other.myChild)) return false; 152 if (myCodeSystem == null) { 153 if (other.myCodeSystem != null) return false; 154 } else if (!myCodeSystem.equals(other.myCodeSystem)) return false; 155 if (myParent == null) { 156 if (other.myParent != null) return false; 157 } else if (!myParent.equals(other.myParent)) return false; 158 if (myRelationshipType != other.myRelationshipType) return false; 159 return true; 160 } 161 162 public TermConcept getChild() { 163 return myChild; 164 } 165 166 public Long getChildPid() { 167 return myChildPid; 168 } 169 170 public TermCodeSystemVersion getCodeSystem() { 171 return myCodeSystem; 172 } 173 174 public TermConceptParentChildLinkPk getPid() { 175 if (myId == null) { 176 myId = new TermConceptParentChildLinkPk(); 177 } 178 return myId; 179 } 180 181 public Long getId() { 182 return getPid().myId; 183 } 184 185 public TermConcept getParent() { 186 return myParent; 187 } 188 189 public Long getParentPid() { 190 return myParentPid; 191 } 192 193 public RelationshipTypeEnum getRelationshipType() { 194 return myRelationshipType; 195 } 196 197 @PrePersist 198 public void prePersist() { 199 if (myChildPid == null) { 200 myChildPid = myChild.getId(); 201 assert myChildPid != null; 202 } 203 if (myParentPid == null) { 204 myParentPid = myParent.getId(); 205 assert myParentPid != null; 206 } 207 if (myCodeSystemVersionPid == null) { 208 myCodeSystemVersionPid = myCodeSystem.getPid(); 209 assert myCodeSystemVersionPid != null; 210 } 211 } 212 213 @Override 214 public int hashCode() { 215 final int prime = 31; 216 int result = 1; 217 result = prime * result + ((myChild == null) ? 0 : myChild.hashCode()); 218 result = prime * result + ((myCodeSystem == null) ? 0 : myCodeSystem.hashCode()); 219 result = prime * result + ((myParent == null) ? 0 : myParent.hashCode()); 220 result = prime * result + ((myRelationshipType == null) ? 0 : myRelationshipType.hashCode()); 221 return result; 222 } 223 224 public TermConceptParentChildLink setChild(TermConcept theChild) { 225 myChild = theChild; 226 myChildPid = theChild.getId(); 227 return this; 228 } 229 230 public TermConceptParentChildLink setCodeSystem(TermCodeSystemVersion theCodeSystemVersion) { 231 myCodeSystem = theCodeSystemVersion; 232 myCodeSystemVersionPid = theCodeSystemVersion.getPid(); 233 return this; 234 } 235 236 public TermConceptParentChildLink setParent(TermConcept theParent) { 237 myParent = theParent; 238 myParentPid = theParent.getId(); 239 myPartitionIdValue = theParent.getPartitionId().getPartitionId(); 240 getPid().myPartitionIdValue = myPartitionIdValue; 241 return this; 242 } 243 244 public TermConceptParentChildLink setRelationshipType(RelationshipTypeEnum theRelationshipType) { 245 myRelationshipType = theRelationshipType; 246 return this; 247 } 248 249 @Override 250 public String toString() { 251 return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) 252 .append("pid", myId) 253 .append("csvPid", myCodeSystemVersionPid) 254 .append("parentPid", myParentPid) 255 .append("childPid", myChildPid) 256 .append("rel", myRelationshipType) 257 .toString(); 258 } 259 260 public enum RelationshipTypeEnum { 261 // ******************************************** 262 // IF YOU ADD HERE MAKE SURE ORDER IS PRESERVED 263 ISA 264 } 265 266 @Embeddable 267 public static class TermConceptParentChildLinkPk { 268 269 @SequenceGenerator(name = "SEQ_CONCEPT_PC_PID", sequenceName = "SEQ_CONCEPT_PC_PID") 270 @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_PC_PID") 271 @Column(name = "PID") 272 private Long myId; 273 274 @PartitionedIdProperty 275 @Column(name = PartitionablePartitionId.PARTITION_ID, nullable = false) 276 private Integer myPartitionIdValue; 277 278 @Override 279 public int hashCode() { 280 return Objects.hash(myId, myPartitionIdValue); 281 } 282 283 @Override 284 public boolean equals(Object theO) { 285 if (this == theO) { 286 return true; 287 } 288 if (!(theO instanceof TermConceptParentChildLinkPk)) { 289 return false; 290 } 291 TermConceptParentChildLinkPk that = (TermConceptParentChildLinkPk) theO; 292 return Objects.equals(myId, that.myId) && Objects.equals(myPartitionIdValue, that.myPartitionIdValue); 293 } 294 295 @Override 296 public String toString() { 297 return myPartitionIdValue + "/" + myId; 298 } 299 } 300}