001/*
002 * #%L
003 * HAPI FHIR JPA Server
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.entity;
021
022import ca.uhn.fhir.util.ValidateUtil;
023import jakarta.annotation.Nonnull;
024import jakarta.persistence.Column;
025import jakarta.persistence.Entity;
026import jakarta.persistence.FetchType;
027import jakarta.persistence.ForeignKey;
028import jakarta.persistence.GeneratedValue;
029import jakarta.persistence.GenerationType;
030import jakarta.persistence.Id;
031import jakarta.persistence.JoinColumn;
032import jakarta.persistence.Lob;
033import jakarta.persistence.ManyToOne;
034import jakarta.persistence.OneToMany;
035import jakarta.persistence.SequenceGenerator;
036import jakarta.persistence.Table;
037import jakarta.persistence.Transient;
038import jakarta.persistence.UniqueConstraint;
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.Length;
044
045import java.io.Serializable;
046import java.util.ArrayList;
047import java.util.List;
048
049import static org.apache.commons.lang3.StringUtils.isNotEmpty;
050import static org.apache.commons.lang3.StringUtils.left;
051import static org.apache.commons.lang3.StringUtils.length;
052
053/*
054 * DM 2019-08-01 - Do not use IDX_VALUESET_CONCEPT_CS_CD or IDX_VALUESET_CONCEPT_CS_CODE; this was previously used as an index so reusing the name will
055 * bork up migration tasks.
056 */
057@Table(
058                name = "TRM_VALUESET_CONCEPT",
059                uniqueConstraints = {
060                        @UniqueConstraint(
061                                        name = "IDX_VS_CONCEPT_CSCD",
062                                        columnNames = {"VALUESET_PID", "SYSTEM_URL", "CODEVAL"}),
063                        @UniqueConstraint(
064                                        name = "IDX_VS_CONCEPT_ORDER",
065                                        columnNames = {"VALUESET_PID", "VALUESET_ORDER"})
066                })
067@Entity()
068public class TermValueSetConcept implements Serializable {
069        private static final long serialVersionUID = 1L;
070
071        @Id()
072        @SequenceGenerator(name = "SEQ_VALUESET_CONCEPT_PID", sequenceName = "SEQ_VALUESET_CONCEPT_PID")
073        @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_VALUESET_CONCEPT_PID")
074        @Column(name = "PID")
075        private Long myId;
076
077        @ManyToOne(fetch = FetchType.LAZY)
078        @JoinColumn(
079                        name = "VALUESET_PID",
080                        referencedColumnName = "PID",
081                        nullable = false,
082                        foreignKey = @ForeignKey(name = "FK_TRM_VALUESET_PID"))
083        private TermValueSet myValueSet;
084
085        @Column(name = "VALUESET_PID", insertable = false, updatable = false, nullable = false)
086        private Long myValueSetPid;
087
088        @Column(name = "INDEX_STATUS", nullable = true)
089        private Long myIndexStatus;
090
091        @Column(name = "VALUESET_ORDER", nullable = false)
092        private int myOrder;
093
094        @Transient
095        private String myValueSetUrl;
096
097        @Transient
098        private String myValueSetName;
099
100        @Column(name = "SOURCE_PID", nullable = true)
101        private Long mySourceConceptPid;
102
103        @Deprecated(since = "7.2.0")
104        @Lob
105        @Column(name = "SOURCE_DIRECT_PARENT_PIDS", nullable = true)
106        private String mySourceConceptDirectParentPids;
107
108        @Column(name = "SOURCE_DIRECT_PARENT_PIDS_VC", nullable = true, length = Length.LONG32)
109        private String mySourceConceptDirectParentPidsVc;
110
111        @Column(name = "SYSTEM_URL", nullable = false, length = TermCodeSystem.MAX_URL_LENGTH)
112        private String mySystem;
113
114        @Column(name = "SYSTEM_VER", nullable = true, length = TermCodeSystemVersion.MAX_VERSION_LENGTH)
115        private String mySystemVer;
116
117        @Column(name = "CODEVAL", nullable = false, length = TermConcept.MAX_CODE_LENGTH)
118        private String myCode;
119
120        @Column(name = "DISPLAY", nullable = true, length = TermConcept.MAX_DESC_LENGTH)
121        private String myDisplay;
122
123        @OneToMany(mappedBy = "myConcept", fetch = FetchType.LAZY)
124        private List<TermValueSetConceptDesignation> myDesignations;
125
126        @Transient
127        private transient Integer myHashCode;
128
129        /**
130         * Constructor
131         */
132        public TermValueSetConcept() {
133                super();
134        }
135
136        public Long getId() {
137                return myId;
138        }
139
140        public TermValueSet getValueSet() {
141                return myValueSet;
142        }
143
144        public TermValueSetConcept setValueSet(TermValueSet theValueSet) {
145                myValueSet = theValueSet;
146                return this;
147        }
148
149        public int getOrder() {
150                return myOrder;
151        }
152
153        public TermValueSetConcept setOrder(int theOrder) {
154                myOrder = theOrder;
155                return this;
156        }
157
158        public String getValueSetUrl() {
159                if (myValueSetUrl == null) {
160                        myValueSetUrl = getValueSet().getUrl();
161                }
162
163                return myValueSetUrl;
164        }
165
166        public String getValueSetName() {
167                if (myValueSetName == null) {
168                        myValueSetName = getValueSet().getName();
169                }
170
171                return myValueSetName;
172        }
173
174        public String getSystem() {
175                return mySystem;
176        }
177
178        public TermValueSetConcept setSystem(@Nonnull String theSystem) {
179                ValidateUtil.isNotBlankOrThrowIllegalArgument(theSystem, "theSystem must not be null or empty");
180                ValidateUtil.isNotTooLongOrThrowIllegalArgument(
181                                theSystem,
182                                TermCodeSystem.MAX_URL_LENGTH,
183                                "System exceeds maximum length (" + TermCodeSystem.MAX_URL_LENGTH + "): " + length(theSystem));
184                mySystem = theSystem;
185                return this;
186        }
187
188        public String getSystemVersion() {
189                return mySystemVer;
190        }
191
192        public TermValueSetConcept setSystemVersion(String theSystemVersion) {
193                ValidateUtil.isNotTooLongOrThrowIllegalArgument(
194                                theSystemVersion,
195                                TermCodeSystemVersion.MAX_VERSION_LENGTH,
196                                "System version exceeds maximum length (" + TermCodeSystemVersion.MAX_VERSION_LENGTH + "): "
197                                                + length(theSystemVersion));
198                mySystemVer = theSystemVersion;
199                return this;
200        }
201
202        public String getCode() {
203                return myCode;
204        }
205
206        public TermValueSetConcept setCode(@Nonnull String theCode) {
207                ValidateUtil.isNotBlankOrThrowIllegalArgument(theCode, "theCode must not be null or empty");
208                ValidateUtil.isNotTooLongOrThrowIllegalArgument(
209                                theCode,
210                                TermConcept.MAX_CODE_LENGTH,
211                                "Code exceeds maximum length (" + TermConcept.MAX_CODE_LENGTH + "): " + length(theCode));
212                myCode = theCode;
213                return this;
214        }
215
216        public String getDisplay() {
217                return myDisplay;
218        }
219
220        public TermValueSetConcept setDisplay(String theDisplay) {
221                myDisplay = left(theDisplay, TermConcept.MAX_DESC_LENGTH);
222                return this;
223        }
224
225        public List<TermValueSetConceptDesignation> getDesignations() {
226                if (myDesignations == null) {
227                        myDesignations = new ArrayList<>();
228                }
229
230                return myDesignations;
231        }
232
233        @Override
234        public boolean equals(Object theO) {
235                if (this == theO) return true;
236
237                if (!(theO instanceof TermValueSetConcept)) return false;
238
239                TermValueSetConcept that = (TermValueSetConcept) theO;
240
241                return new EqualsBuilder()
242                                .append(myValueSetPid, that.myValueSetPid)
243                                .append(getSystem(), that.getSystem())
244                                .append(getCode(), that.getCode())
245                                .isEquals();
246        }
247
248        @Override
249        public int hashCode() {
250                if (myHashCode == null) {
251                        myHashCode = new HashCodeBuilder(17, 37)
252                                        .append(myValueSetPid)
253                                        .append(getSystem())
254                                        .append(getCode())
255                                        .toHashCode();
256                }
257                return myHashCode;
258        }
259
260        @Override
261        public String toString() {
262                return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
263                                .append("id", myId)
264                                .append("order", myOrder)
265                                .append("system", mySystem)
266                                .append("code", myCode)
267                                .append("valueSet", myValueSet != null ? myValueSet.getId() : "(null)")
268                                .append("valueSetPid", myValueSetPid)
269                                .append("valueSetUrl", this.getValueSetUrl())
270                                .append("valueSetName", this.getValueSetName())
271                                .append("display", myDisplay)
272                                .append("designationCount", myDesignations != null ? myDesignations.size() : "(null)")
273                                .append("parentPids", getSourceConceptDirectParentPids())
274                                .toString();
275        }
276
277        public Long getIndexStatus() {
278                return myIndexStatus;
279        }
280
281        public void setIndexStatus(Long theIndexStatus) {
282                myIndexStatus = theIndexStatus;
283        }
284
285        public void setSourceConceptPid(Long theSourceConceptPid) {
286                mySourceConceptPid = theSourceConceptPid;
287        }
288
289        public void setSourceConceptDirectParentPids(String theSourceConceptDirectParentPids) {
290                mySourceConceptDirectParentPids = theSourceConceptDirectParentPids;
291                mySourceConceptDirectParentPidsVc = theSourceConceptDirectParentPids;
292        }
293
294        public String getSourceConceptDirectParentPids() {
295                return isNotEmpty(mySourceConceptDirectParentPidsVc)
296                                ? mySourceConceptDirectParentPidsVc
297                                : mySourceConceptDirectParentPids;
298        }
299}