001/*- 002 * #%L 003 * HAPI FHIR JPA Model 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.model.entity; 021 022import jakarta.persistence.Column; 023import jakarta.persistence.EmbeddedId; 024import jakarta.persistence.Entity; 025import jakarta.persistence.FetchType; 026import jakarta.persistence.ForeignKey; 027import jakarta.persistence.Index; 028import jakarta.persistence.JoinColumn; 029import jakarta.persistence.ManyToOne; 030import jakarta.persistence.Table; 031import jakarta.persistence.Temporal; 032import jakarta.persistence.TemporalType; 033 034import java.time.LocalDate; 035import java.util.Date; 036import java.util.Optional; 037 038/** 039 * This entity is used to enforce uniqueness on a given search URL being 040 * used as a conditional operation URL, e.g. a conditional create or a 041 * conditional update. When we perform a conditional operation that is 042 * creating a new resource, we store an entity with the conditional URL 043 * in this table. The URL is the PK of the table, so the database 044 * ensures that two concurrent threads don't accidentally create two 045 * resources with the same conditional URL. 046 */ 047@Entity 048@Table( 049 name = "HFJ_RES_SEARCH_URL", 050 indexes = { 051 @Index(name = "IDX_RESSEARCHURL_RES", columnList = "RES_ID"), 052 @Index(name = "IDX_RESSEARCHURL_TIME", columnList = "CREATED_TIME") 053 }) 054public class ResourceSearchUrlEntity { 055 056 public static final String RES_SEARCH_URL_COLUMN_NAME = "RES_SEARCH_URL"; 057 public static final String PARTITION_ID = "PARTITION_ID"; 058 059 public static final int RES_SEARCH_URL_LENGTH = 768; 060 061 @EmbeddedId 062 private ResourceSearchUrlEntityPK myPk; 063 064 @ManyToOne(fetch = FetchType.LAZY) 065 @JoinColumn( 066 name = "RES_ID", 067 nullable = false, 068 updatable = false, 069 foreignKey = @ForeignKey(name = "FK_RES_SEARCH_URL_RESOURCE")) 070 private ResourceTable myResourceTable; 071 072 @Column(name = "RES_ID", updatable = false, nullable = false, insertable = false) 073 private Long myResourcePid; 074 075 @Column(name = "PARTITION_DATE", nullable = true, insertable = true, updatable = false) 076 private LocalDate myPartitionDate; 077 078 @Column(name = "CREATED_TIME", nullable = false) 079 @Temporal(TemporalType.TIMESTAMP) 080 private Date myCreatedTime; 081 082 public static ResourceSearchUrlEntity from( 083 String theUrl, ResourceTable theResourceTable, boolean theSearchUrlDuplicateAcrossPartitionsEnabled) { 084 085 return new ResourceSearchUrlEntity() 086 .setPk(ResourceSearchUrlEntityPK.from( 087 theUrl, theResourceTable, theSearchUrlDuplicateAcrossPartitionsEnabled)) 088 .setPartitionDate(Optional.ofNullable(theResourceTable.getPartitionId()) 089 .map(PartitionablePartitionId::getPartitionDate) 090 .orElse(null)) 091 .setResourceTable(theResourceTable) 092 .setCreatedTime(new Date()); 093 } 094 095 public ResourceSearchUrlEntityPK getPk() { 096 return myPk; 097 } 098 099 public ResourceSearchUrlEntity setPk(ResourceSearchUrlEntityPK thePk) { 100 myPk = thePk; 101 return this; 102 } 103 104 public Long getResourcePid() { 105 if (myResourcePid != null) { 106 return myResourcePid; 107 } 108 return myResourceTable.getResourceId(); 109 } 110 111 public ResourceSearchUrlEntity setResourcePid(Long theResourcePid) { 112 myResourcePid = theResourcePid; 113 return this; 114 } 115 116 public ResourceTable getResourceTable() { 117 return myResourceTable; 118 } 119 120 public ResourceSearchUrlEntity setResourceTable(ResourceTable myResourceTable) { 121 this.myResourceTable = myResourceTable; 122 return this; 123 } 124 125 public Date getCreatedTime() { 126 return myCreatedTime; 127 } 128 129 public ResourceSearchUrlEntity setCreatedTime(Date theCreatedTime) { 130 myCreatedTime = theCreatedTime; 131 return this; 132 } 133 134 public String getSearchUrl() { 135 return myPk.getSearchUrl(); 136 } 137 138 public Integer getPartitionId() { 139 return myPk.getPartitionId(); 140 } 141 142 public LocalDate getPartitionDate() { 143 return myPartitionDate; 144 } 145 146 public ResourceSearchUrlEntity setPartitionDate(LocalDate thePartitionDate) { 147 myPartitionDate = thePartitionDate; 148 return this; 149 } 150}