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.BasePartitionable;
023import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
024import ca.uhn.fhir.util.ValidateUtil;
025import jakarta.annotation.Nonnull;
026import jakarta.persistence.Column;
027import jakarta.persistence.Entity;
028import jakarta.persistence.FetchType;
029import jakarta.persistence.ForeignKey;
030import jakarta.persistence.GeneratedValue;
031import jakarta.persistence.GenerationType;
032import jakarta.persistence.Id;
033import jakarta.persistence.IdClass;
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.Length;
044
045import java.io.Serializable;
046import java.util.Objects;
047
048import static org.apache.commons.lang3.StringUtils.left;
049import static org.apache.commons.lang3.StringUtils.length;
050
051@Entity
052@Table(
053                name = "TRM_CONCEPT_DESIG",
054                uniqueConstraints = {},
055                indexes = {
056                        // must have same name that indexed FK or SchemaMigrationTest complains because H2 sets this index
057                        // automatically
058                        @Index(name = "FK_CONCEPTDESIG_CONCEPT", columnList = "CONCEPT_PID", unique = false),
059                        @Index(name = "FK_CONCEPTDESIG_CSV", columnList = "CS_VER_PID")
060                })
061@IdClass(IdAndPartitionId.class)
062public class TermConceptDesignation extends BasePartitionable implements Serializable {
063        private static final long serialVersionUID = 1L;
064
065        public static final int MAX_LENGTH = 500;
066        public static final int MAX_VAL_LENGTH = 2000;
067
068        @ManyToOne(fetch = FetchType.LAZY)
069        @JoinColumns(
070                        value = {
071                                @JoinColumn(
072                                                name = "CONCEPT_PID",
073                                                referencedColumnName = "PID",
074                                                insertable = false,
075                                                updatable = false,
076                                                nullable = false),
077                                @JoinColumn(
078                                                name = "PARTITION_ID",
079                                                referencedColumnName = "PARTITION_ID",
080                                                insertable = false,
081                                                updatable = false,
082                                                nullable = false)
083                        },
084                        foreignKey = @ForeignKey(name = "FK_CONCEPTDESIG_CONCEPT"))
085        private TermConcept myConcept;
086
087        @Column(name = "CONCEPT_PID", insertable = true, updatable = true, nullable = false)
088        private Long myConceptPid;
089
090        @Id()
091        @SequenceGenerator(name = "SEQ_CONCEPT_DESIG_PID", sequenceName = "SEQ_CONCEPT_DESIG_PID")
092        @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_DESIG_PID")
093        @Column(name = "PID")
094        private Long myId;
095
096        @Column(name = "LANG", nullable = true, length = MAX_LENGTH)
097        private String myLanguage;
098
099        @Column(name = "USE_SYSTEM", nullable = true, length = MAX_LENGTH)
100        private String myUseSystem;
101
102        @Column(name = "USE_CODE", nullable = true, length = MAX_LENGTH)
103        private String myUseCode;
104
105        @Column(name = "USE_DISPLAY", nullable = true, length = MAX_LENGTH)
106        private String myUseDisplay;
107
108        @Column(name = "VAL", nullable = true, length = MAX_VAL_LENGTH)
109        private String myValue;
110
111        @Column(name = "VAL_VC", nullable = true, length = Length.LONG32)
112        private String myValueVc;
113        /**
114         * TODO: Make this non-null
115         *
116         * @since 3.5.0
117         */
118        @ManyToOne(fetch = FetchType.LAZY)
119        @JoinColumns(
120                        value = {
121                                @JoinColumn(
122                                                name = "CS_VER_PID",
123                                                insertable = true,
124                                                updatable = false,
125                                                nullable = false,
126                                                referencedColumnName = "PID"),
127                                @JoinColumn(
128                                                name = "PARTITION_ID",
129                                                referencedColumnName = "PARTITION_ID",
130                                                insertable = true,
131                                                updatable = false,
132                                                nullable = false)
133                        },
134                        foreignKey = @ForeignKey(name = "FK_CONCEPTDESIG_CSV"))
135        private TermCodeSystemVersion myCodeSystemVersion;
136
137        public String getLanguage() {
138                return myLanguage;
139        }
140
141        public TermConceptDesignation setLanguage(String theLanguage) {
142                ValidateUtil.isNotTooLongOrThrowIllegalArgument(
143                                theLanguage,
144                                MAX_LENGTH,
145                                "Language exceeds maximum length (" + MAX_LENGTH + "): " + length(theLanguage));
146                myLanguage = theLanguage;
147                return this;
148        }
149
150        public String getUseCode() {
151                return myUseCode;
152        }
153
154        public TermConceptDesignation setUseCode(String theUseCode) {
155                ValidateUtil.isNotTooLongOrThrowIllegalArgument(
156                                theUseCode, MAX_LENGTH, "Use code exceeds maximum length (" + MAX_LENGTH + "): " + length(theUseCode));
157                myUseCode = theUseCode;
158                return this;
159        }
160
161        public String getUseDisplay() {
162                return myUseDisplay;
163        }
164
165        public TermConceptDesignation setUseDisplay(String theUseDisplay) {
166                myUseDisplay = left(theUseDisplay, MAX_LENGTH);
167                return this;
168        }
169
170        public String getUseSystem() {
171                return myUseSystem;
172        }
173
174        public TermConceptDesignation setUseSystem(String theUseSystem) {
175                ValidateUtil.isNotTooLongOrThrowIllegalArgument(
176                                theUseSystem,
177                                MAX_LENGTH,
178                                "Use system exceeds maximum length (" + MAX_LENGTH + "): " + length(theUseSystem));
179                myUseSystem = theUseSystem;
180                return this;
181        }
182
183        public String getValue() {
184                return Objects.nonNull(myValueVc) ? myValueVc : myValue;
185        }
186
187        public TermConceptDesignation setValue(@Nonnull String theValueVc) {
188                myValueVc = theValueVc;
189                return this;
190        }
191
192        public TermConceptDesignation setCodeSystemVersion(TermCodeSystemVersion theCodeSystemVersion) {
193                myCodeSystemVersion = theCodeSystemVersion;
194                return this;
195        }
196
197        public TermConceptDesignation setConcept(TermConcept theConcept) {
198                myConcept = theConcept;
199                myConceptPid = theConcept.getId();
200                setPartitionId(theConcept.getPartitionId());
201                return this;
202        }
203
204        @PrePersist
205        public void prePersist() {
206                if (myConceptPid == null) {
207                        myConceptPid = myConcept.getId();
208                        assert myConceptPid != null;
209                }
210        }
211
212        public Long getPid() {
213                return myId;
214        }
215
216        public IdAndPartitionId getPartitionedId() {
217                return IdAndPartitionId.forId(myId, this);
218        }
219
220        @Override
221        public String toString() {
222                return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
223                                .append("conceptPid", myConcept.getId())
224                                .append("pid", myId)
225                                .append("language", myLanguage)
226                                .append("useSystem", myUseSystem)
227                                .append("useCode", myUseCode)
228                                .append("useDisplay", myUseDisplay)
229                                .append("value", myValue)
230                                .toString();
231        }
232
233        public Long getId() {
234                return myId;
235        }
236}