Database Partition Mode Merge 3 (#6535)

* Start mods for round 2

* Work on changes

* Work on build

* Work on tests

* Test fixes

* Test fixes

* Test fixes

* Add dump

* potless

* Cleanup

* Cleanup

* Work on mock validation support

* Test fixes

* Test fixes

* Test fixes

* Test fix

* Test fixes

* Test fix

* Test fixes

* Test fixes

* Test fixes

* Test fix

* Test fixes

* Remove redundant test

* Compile fixes

* Test fix

* Add javadocs

* Rename class

* Spotless

* Test fixes

* Compile fix

* Add test logging

* Add test logging

* Work on tracking down intermittent

* Intermittent test fix

* Add logging for another intermittent

* Merge master

* Cleanup

* Work on tests

* Work on tests

* Test fixes

* Test fix

* Test fixes

* Test fixes

* Cleanup

* Merge issues

* HAPI version bump

* Test fix
This commit is contained in:
James Agnew 2024-12-10 21:14:58 -05:00 committed by GitHub
parent 28d4f65d79
commit a999cb32c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
363 changed files with 5427 additions and 3292 deletions

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>7.7.13-SNAPSHOT</version>
<version>7.7.14-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.13-SNAPSHOT</version>
<version>7.7.14-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.13-SNAPSHOT</version>
<version>7.7.14-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-bom</artifactId>
<version>7.7.13-SNAPSHOT</version>
<version>7.7.14-SNAPSHOT</version>
<packaging>pom</packaging>
<name>HAPI FHIR BOM</name>
@ -12,7 +12,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.13-SNAPSHOT</version>
<version>7.7.14-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>7.7.13-SNAPSHOT</version>
<version>7.7.14-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.13-SNAPSHOT</version>
<version>7.7.14-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-cli</artifactId>
<version>7.7.13-SNAPSHOT</version>
<version>7.7.14-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>7.7.13-SNAPSHOT</version>
<version>7.7.14-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.13-SNAPSHOT</version>
<version>7.7.14-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.13-SNAPSHOT</version>
<version>7.7.14-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.13-SNAPSHOT</version>
<version>7.7.14-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.13-SNAPSHOT</version>
<version>7.7.14-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>7.7.13-SNAPSHOT</version>
<version>7.7.14-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.13-SNAPSHOT</version>
<version>7.7.14-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -11,7 +11,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.13-SNAPSHOT</version>
<version>7.7.14-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.13-SNAPSHOT</version>
<version>7.7.14-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.13-SNAPSHOT</version>
<version>7.7.14-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.7.13-SNAPSHOT</version>
<version>7.7.14-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -111,9 +111,9 @@ public class Batch2DaoSvcImpl implements IBatch2DaoSvc {
}
private static TypedResourcePid typedPidFromQueryArray(Object[] thePidTypeDateArray) {
JpaPid pid = (JpaPid) thePidTypeDateArray[0];
String resourceType = (String) thePidTypeDateArray[1];
Long pid = (Long) thePidTypeDateArray[0];
return new TypedResourcePid(resourceType, JpaPid.fromId(pid));
return new TypedResourcePid(resourceType, pid);
}
@Nonnull

View File

@ -40,7 +40,6 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import static org.slf4j.LoggerFactory.getLogger;
@ -110,10 +109,10 @@ public class ResourceVersionSvcDaoImpl implements IResourceVersionSvc {
private ResourcePersistentIdMap getIdsOfExistingResources(
RequestPartitionId thePartitionId, Collection<IIdType> theIds) {
// these are the found Ids that were in the db
ResourcePersistentIdMap retval = new ResourcePersistentIdMap();
ResourcePersistentIdMap retVal = new ResourcePersistentIdMap();
if (theIds == null || theIds.isEmpty()) {
return retval;
return retVal;
}
Map<IIdType, IResourceLookup<JpaPid>> identities = myIdHelperService.resolveResourceIdentities(
@ -121,39 +120,36 @@ public class ResourceVersionSvcDaoImpl implements IResourceVersionSvc {
new ArrayList<>(theIds),
ResolveIdentityMode.includeDeleted().cacheOk());
// we'll use this map to fetch pids that require versions
HashMap<Long, JpaPid> pidsToVersionToResourcePid = new HashMap<>();
Map<String, JpaPid> entriesWithoutVersion = new HashMap<>(identities.size());
// fill in our map
for (IResourceLookup<JpaPid> identity : identities.values()) {
JpaPid pid = identity.getPersistentId();
if (pid.getVersion() == null) {
pidsToVersionToResourcePid.put(pid.getId(), pid);
for (Map.Entry<IIdType, IResourceLookup<JpaPid>> entry : identities.entrySet()) {
IResourceLookup<JpaPid> lookup = entry.getValue();
JpaPid persistentId = lookup.getPersistentId();
retVal.put(entry.getKey(), persistentId);
if (persistentId.getVersion() == null) {
entriesWithoutVersion.put(
entry.getKey().toUnqualifiedVersionless().getValue(), persistentId);
}
Optional<IIdType> idOp = theIds.stream()
.filter(i ->
i.getIdPart().equals(pid.getAssociatedResourceId().getIdPart()))
.findFirst();
// this should always be present
// since it was passed in.
// but land of optionals...
idOp.ifPresent(id -> retval.put(id, pid));
}
// set any versions we don't already have
if (!pidsToVersionToResourcePid.isEmpty()) {
if (!entriesWithoutVersion.isEmpty()) {
Collection<Object[]> resourceEntries =
myResourceTableDao.getResourceVersionsForPid(new ArrayList<>(pidsToVersionToResourcePid.keySet()));
myResourceTableDao.getResourceVersionsForPid(entriesWithoutVersion.values());
for (Object[] nextRecord : resourceEntries) {
// order matters!
Long retPid = (Long) nextRecord[0];
JpaPid retPid = (JpaPid) nextRecord[0];
String resType = (String) nextRecord[1];
Long version = (Long) nextRecord[2];
pidsToVersionToResourcePid.get(retPid).setVersion(version);
String fhirId = (String) nextRecord[2];
Long version = (Long) nextRecord[3];
JpaPid jpaPid = entriesWithoutVersion.get(resType + "/" + fhirId);
if (jpaPid != null) {
jpaPid.setVersion(version);
}
}
}
return retval;
return retVal;
}
}

View File

@ -33,6 +33,7 @@ import ca.uhn.fhir.jpa.dao.expunge.ResourceTableFKProvider;
import ca.uhn.fhir.jpa.dao.tx.IHapiTransactionService;
import ca.uhn.fhir.jpa.delete.batch2.DeleteExpungeSqlBuilder;
import ca.uhn.fhir.jpa.delete.batch2.DeleteExpungeSvcImpl;
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
import jakarta.persistence.EntityManager;
import org.springframework.beans.factory.annotation.Autowired;
@ -64,8 +65,9 @@ public class Batch2SupportConfig {
ResourceTableFKProvider theResourceTableFKProvider,
JpaStorageSettings theStorageSettings,
IIdHelperService theIdHelper,
IResourceLinkDao theResourceLinkDao) {
IResourceLinkDao theResourceLinkDao,
PartitionSettings thePartitionSettings) {
return new DeleteExpungeSqlBuilder(
theResourceTableFKProvider, theStorageSettings, theIdHelper, theResourceLinkDao);
theResourceTableFKProvider, theStorageSettings, theIdHelper, theResourceLinkDao, thePartitionSettings);
}
}

View File

@ -57,6 +57,10 @@ public class HapiFhirHibernateJpaDialect extends HibernateJpaDialect {
if (theException.getCause() instanceof HibernateException) {
return new PersistenceException(
convertHibernateAccessException((HibernateException) theException.getCause(), theMessageToPrepend));
} else if (theException instanceof HibernateException) {
return new PersistenceException(
theException.getMessage(),
convertHibernateAccessException((HibernateException) theException, theMessageToPrepend));
}
return theException;
}

View File

@ -729,7 +729,7 @@ public class JpaConfig {
@Scope("prototype")
public HistoryBuilder newHistoryBuilder(
@Nullable String theResourceType,
@Nullable Long theResourceId,
@Nullable JpaPid theResourceId,
@Nullable Date theRangeStartInclusive,
@Nullable Date theRangeEndInclusive) {
return new HistoryBuilder(theResourceType, theResourceId, theRangeStartInclusive, theRangeEndInclusive);

View File

@ -46,7 +46,6 @@ import ca.uhn.fhir.jpa.dao.index.DaoSearchParamSynchronizer;
import ca.uhn.fhir.jpa.dao.index.SearchParamWithInlineReferencesExtractor;
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
import ca.uhn.fhir.jpa.delete.DeleteConflictService;
import ca.uhn.fhir.jpa.entity.PartitionEntity;
import ca.uhn.fhir.jpa.esr.ExternallyStoredResourceAddress;
import ca.uhn.fhir.jpa.esr.ExternallyStoredResourceAddressMetadataKey;
import ca.uhn.fhir.jpa.esr.ExternallyStoredResourceServiceRegistry;
@ -559,8 +558,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
} else {
ResourceHistoryTable currentHistoryVersion = theEntity.getCurrentVersionEntity();
if (currentHistoryVersion == null) {
currentHistoryVersion =
myResourceHistoryTableDao.findForIdAndVersion(theEntity.getId(), theEntity.getVersion());
currentHistoryVersion = myResourceHistoryTableDao.findForIdAndVersion(
theEntity.getId().toFk(), theEntity.getVersion());
}
if (currentHistoryVersion == null || !currentHistoryVersion.hasResource()) {
changed = true;
@ -914,9 +913,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
// CREATE or UPDATE
IdentityHashMap<ResourceTable, ResourceIndexedSearchParams> existingSearchParams =
theTransactionDetails.getOrCreateUserData(
HapiTransactionService.XACT_USERDATA_KEY_EXISTING_SEARCH_PARAMS,
() -> new IdentityHashMap<>());
getSearchParamsMapFromTransaction(theTransactionDetails);
existingParams = existingSearchParams.get(entity);
if (existingParams == null) {
existingParams = ResourceIndexedSearchParams.withLists(entity);
@ -926,11 +923,11 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
* old set later on
*/
if (existingParams.getResourceLinks().size() >= 10) {
List<Long> pids = existingParams.getResourceLinks().stream()
.map(t -> t.getId())
List<Long> allPids = existingParams.getResourceLinks().stream()
.map(ResourceLink::getId)
.collect(Collectors.toList());
new QueryChunker<Long>().chunk(pids, t -> {
List<ResourceLink> targets = myResourceLinkDao.findByPidAndFetchTargetDetails(t);
new QueryChunker<Long>().chunk(allPids, chunkPids -> {
List<ResourceLink> targets = myResourceLinkDao.findByPidAndFetchTargetDetails(chunkPids);
ourLog.trace("Prefetched targets: {}", targets);
});
}
@ -952,8 +949,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
requestPartitionId = RequestPartitionId.defaultPartition();
}
failIfPartitionMismatch(theRequest, entity);
// Extract search params for resource
mySearchParamWithInlineReferencesExtractor.populateFromResource(
requestPartitionId,
@ -1012,18 +1007,18 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
return entity;
}
if (entity.getId() != null && theUpdateVersion) {
if (entity.getId().getId() != null && theUpdateVersion) {
entity.markVersionUpdatedInCurrentTransaction();
}
/*
* Save the resource itself
*/
if (entity.getId() == null) {
if (entity.getId().getId() == null) {
myEntityManager.persist(entity);
if (entity.getFhirId() == null) {
entity.setFhirId(Long.toString(entity.getResourceId()));
entity.setFhirId(Long.toString(entity.getId().getId()));
}
postPersist(entity, (T) theResource, theRequest);
@ -1111,6 +1106,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
compositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_INFO, params);
}
}
// Put the final set of search params into the transaction
getSearchParamsMapFromTransaction(theTransactionDetails).put(entity, newParams);
}
}
@ -1121,6 +1119,12 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
return entity;
}
private static IdentityHashMap<ResourceTable, ResourceIndexedSearchParams> getSearchParamsMapFromTransaction(
TransactionDetails theTransactionDetails) {
return theTransactionDetails.getOrCreateUserData(
HapiTransactionService.XACT_USERDATA_KEY_EXISTING_SEARCH_PARAMS, IdentityHashMap::new);
}
/**
* This methor returns the {@link EntityIndexStatusEnum} value that should be
* used for a successfully fully indexed resource. This method will return
@ -1183,11 +1187,11 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
}
}
public IBasePersistedResource updateHistoryEntity(
public IBasePersistedResource<?> updateHistoryEntity(
RequestDetails theRequest,
T theResource,
IBasePersistedResource theEntity,
IBasePersistedResource theHistoryEntity,
IBasePersistedResource<?> theEntity,
IBasePersistedResource<?> theHistoryEntity,
IIdType theResourceId,
TransactionDetails theTransactionDetails,
boolean isUpdatingCurrent) {
@ -1291,29 +1295,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
encodedResource.setEncoding(theEncoding);
}
/**
* TODO eventually consider refactoring this to be part of an interceptor.
* <p>
* Throws an exception if the partition of the request, and the partition of the existing entity do not match.
*
* @param theRequest the request.
* @param entity the existing entity.
*/
private void failIfPartitionMismatch(RequestDetails theRequest, ResourceTable entity) {
if (myPartitionSettings.isPartitioningEnabled()
&& theRequest != null
&& theRequest.getTenantId() != null
&& entity.getPartitionId() != null) {
PartitionEntity partitionEntity = myPartitionLookupSvc.getPartitionByName(theRequest.getTenantId());
// partitionEntity should never be null
if (partitionEntity != null
&& !partitionEntity.getId().equals(entity.getPartitionId().getPartitionId())) {
throw new InvalidRequestException(Msg.code(2079) + "Resource " + entity.getResourceType() + "/"
+ entity.getId() + " is not known");
}
}
}
private void createHistoryEntry(
RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, EncodedResource theChanged) {
boolean versionedTags =
@ -1321,7 +1302,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
ResourceHistoryTable historyEntry = null;
long resourceVersion = theEntity.getVersion();
boolean reusingHistoryEntity = false;
if (!myStorageSettings.isResourceDbHistoryEnabled() && resourceVersion > 1L) {
/*
* If we're not storing history, then just pull the current history
@ -1329,10 +1309,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
* this could return null if the current resourceVersion has been expunged
* in which case we'll still create a new one
*/
historyEntry =
myResourceHistoryTableDao.findForIdAndVersion(theEntity.getResourceId(), resourceVersion - 1);
historyEntry = myResourceHistoryTableDao.findForIdAndVersion(
theEntity.getResourceId().toFk(), resourceVersion - 1);
if (historyEntry != null) {
reusingHistoryEntity = true;
theEntity.populateHistoryEntityVersionAndDates(historyEntry);
if (versionedTags && theEntity.isHasTags()) {
for (ResourceTag next : theEntity.getTags()) {
@ -1543,9 +1522,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
protected void addPidToResource(IResourceLookup<JpaPid> theEntity, IBaseResource theResource) {
if (theResource instanceof IAnyResource) {
IDao.RESOURCE_PID.put(theResource, theEntity.getPersistentId().getId());
IDao.RESOURCE_PID.put(theResource, theEntity.getPersistentId());
} else if (theResource instanceof IResource) {
IDao.RESOURCE_PID.put(theResource, theEntity.getPersistentId().getId());
IDao.RESOURCE_PID.put(theResource, theEntity.getPersistentId());
}
}

View File

@ -52,6 +52,8 @@ import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.BaseHasResource;
import ca.uhn.fhir.jpa.model.entity.BaseTag;
import ca.uhn.fhir.jpa.model.entity.EntityIndexStatusEnum;
import ca.uhn.fhir.jpa.model.entity.IBaseResourceEntity;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceEncodingEnum;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryProvenanceEntity;
@ -126,6 +128,7 @@ import jakarta.persistence.NoResultException;
import jakarta.persistence.TypedQuery;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.function.TriFunction;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseMetaType;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
@ -157,7 +160,6 @@ import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -421,6 +423,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
if (isNotBlank(theMatchUrl) && theProcessMatchUrl) {
Set<JpaPid> match = myMatchResourceUrlService.processMatchUrl(
theMatchUrl, myResourceType, theTransactionDetails, theRequest);
ourLog.trace("Resolving match URL {} found: {}", theMatchUrl, match);
if (match.size() > 1) {
String msg = getContext()
.getLocalizer()
@ -472,7 +475,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
*/
Supplier<LazyDaoMethodOutcome.EntityAndResource> entitySupplier = () -> myTxTemplate.execute(tx -> {
ResourceTable foundEntity = myEntityManager.find(ResourceTable.class, pid.getId());
ResourceTable foundEntity = myEntityManager.find(ResourceTable.class, pid);
IBaseResource resource = myJpaStorageResourceParser.toResource(foundEntity, false);
theResource.setId(resource.getIdElement().getValue());
return new LazyDaoMethodOutcome.EntityAndResource(foundEntity, resource);
@ -483,7 +486,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
Long version = myMemoryCacheService.getIfPresent(
MemoryCacheService.CacheEnum.RESOURCE_CONDITIONAL_CREATE_VERSION, pid.getId());
if (version == null) {
version = myResourceTableDao.findCurrentVersionByPid(pid.getId());
version = myResourceTableDao.findCurrentVersionByPid(pid);
if (version != null) {
myMemoryCacheService.putAfterCommit(
MemoryCacheService.CacheEnum.RESOURCE_CONDITIONAL_CREATE_VERSION,
@ -733,10 +736,10 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
final ResourceTable entity;
try {
entity = readEntityLatestVersion(theId, requestPartitionId, theTransactionDetails);
entity = readEntityLatestVersion(theRequestDetails, theId, requestPartitionId, theTransactionDetails);
} catch (ResourceNotFoundException ex) {
// we don't want to throw 404s.
// if not found, return an outcome anyways.
// if not found, return an outcome anyway.
// Because no object actually existed, we'll
// just set the id and nothing else
return createMethodOutcomeForResourceId(
@ -750,7 +753,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
Msg.code(961) + "Trying to delete " + theId + " but this is not the current version");
}
JpaPid persistentId = JpaPid.fromId(entity.getResourceId());
JpaPid persistentId = entity.getId();
theTransactionDetails.addDeletedResourceId(persistentId);
// Don't delete again if it's already deleted
@ -941,7 +944,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
JpaPid jpaPid = (JpaPid) pid;
// This shouldn't actually need to hit the DB because we pre-fetch above
ResourceTable entity = myEntityManager.find(ResourceTable.class, jpaPid.getId());
ResourceTable entity = myEntityManager.find(ResourceTable.class, jpaPid);
deletedResources.add(entity);
T resourceToDelete = myJpaStorageResourceParser.toResource(myResourceType, entity, null, false);
@ -1040,7 +1043,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
private <MT extends IBaseMetaType> void doMetaAdd(
MT theMetaAdd,
BaseHasResource theEntity,
BaseHasResource<?> theEntity,
RequestDetails theRequestDetails,
TransactionDetails theTransactionDetails) {
IBaseResource oldVersion = myJpaStorageResourceParser.toResource(theEntity, false);
@ -1049,7 +1052,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
for (TagDefinition nextDef : tags) {
boolean entityHasTag = false;
for (BaseTag next : new ArrayList<>(theEntity.getTags())) {
for (BaseTag next : theEntity.getTags()) {
if (Objects.equals(next.getTag().getTagType(), nextDef.getTagType())
&& Objects.equals(next.getTag().getSystem(), nextDef.getSystem())
&& Objects.equals(next.getTag().getCode(), nextDef.getCode())
@ -1184,11 +1187,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
IIdType theId, ExpungeOptions theExpungeOptions, RequestDetails theRequest) {
TransactionTemplate txTemplate = new TransactionTemplate(myPlatformTransactionManager);
BaseHasResource entity = txTemplate.execute(t -> readEntity(theId, theRequest));
BaseHasResource<?> entity = txTemplate.execute(t -> readEntity(theId, theRequest));
Validate.notNull(entity, "Resource with ID %s not found in database", theId);
if (theId.hasVersionIdPart()) {
BaseHasResource currentVersion;
BaseHasResource<?> currentVersion;
currentVersion = txTemplate.execute(t -> readEntity(theId.toVersionless(), theRequest));
Validate.notNull(
currentVersion,
@ -1201,15 +1204,15 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
+ theId.toUnqualified().getValue() + " as this is the current version");
}
return myExpungeService.expunge(
getResourceName(),
JpaPid.fromIdAndVersion(entity.getResourceId(), entity.getVersion()),
theExpungeOptions,
theRequest);
return myExpungeService.expunge(getResourceName(), entity.getResourceId(), theExpungeOptions, theRequest);
}
return myExpungeService.expunge(
getResourceName(), JpaPid.fromId(entity.getResourceId()), theExpungeOptions, theRequest);
// Downstream code expects the version to be null in the JpaPid if we're not
// doing a version specific expunge
JpaPid resourceId = entity.getResourceId();
resourceId = JpaPid.fromId(resourceId.getId(), resourceId.getPartitionId());
return myExpungeService.expunge(getResourceName(), resourceId, theExpungeOptions, theRequest);
}
@Override
@ -1265,7 +1268,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
return myPersistedJpaBundleProviderFactory.history(
theRequest,
myResourceName,
entity.getPersistentId(),
entity.getResourceId(),
theSince,
theUntil,
theOffset,
@ -1295,7 +1298,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
return myPersistedJpaBundleProviderFactory.history(
theRequest,
myResourceName,
JpaPid.fromId(entity.getId()),
entity.getResourceId(),
theHistorySearchDateRangeParam.getLowerBoundAsInstant(),
theHistorySearchDateRangeParam.getUpperBoundAsInstant(),
theHistorySearchDateRangeParam.getOffset(),
@ -1388,15 +1391,16 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
throw new ResourceNotFoundException(Msg.code(1993) + theResourceId);
}
ResourceTable latestVersion = readEntityLatestVersion(theResourceId, theRequestPartitionId, transactionDetails);
ResourceTable latestVersion =
readEntityLatestVersion(theRequest, theResourceId, theRequestPartitionId, transactionDetails);
if (latestVersion.getVersion() != entity.getVersion()) {
doMetaAdd(theMetaAdd, entity, theRequest, transactionDetails);
} else {
doMetaAdd(theMetaAdd, latestVersion, theRequest, transactionDetails);
// Also update history entry
ResourceHistoryTable history =
myResourceHistoryTableDao.findForIdAndVersion(entity.getId(), entity.getVersion());
ResourceHistoryTable history = myResourceHistoryTableDao.findForIdAndVersion(
entity.getResourceId().toFk(), entity.getVersion());
doMetaAdd(theMetaAdd, history, theRequest, transactionDetails);
}
@ -1434,7 +1438,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
throw new ResourceNotFoundException(Msg.code(1994) + theResourceId);
}
ResourceTable latestVersion = readEntityLatestVersion(theResourceId, theRequestPartitionId, transactionDetails);
ResourceTable latestVersion =
readEntityLatestVersion(theRequest, theResourceId, theRequestPartitionId, transactionDetails);
boolean nonVersionedTags =
myStorageSettings.getTagStorageMode() != JpaStorageSettings.TagStorageModeEnum.VERSIONED;
@ -1443,8 +1448,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
} else {
doMetaDelete(theMetaDel, latestVersion, theRequest, transactionDetails);
// Also update history entry
ResourceHistoryTable history =
myResourceHistoryTableDao.findForIdAndVersion(entity.getId(), entity.getVersion());
ResourceHistoryTable history = myResourceHistoryTableDao.findForIdAndVersion(
entity.getResourceId().toFk(), entity.getVersion());
doMetaDelete(theMetaDel, history, theRequest, transactionDetails);
}
@ -1455,7 +1460,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
public <MT extends IBaseMetaType> MT metaGetOperation(Class<MT> theType, IIdType theId, RequestDetails theRequest) {
return myTransactionService.withRequest(theRequest).execute(() -> {
Set<TagDefinition> tagDefs = new HashSet<>();
BaseHasResource entity = readEntity(theId, theRequest);
BaseHasResource<?> entity = readEntity(theId, theRequest);
for (BaseTag next : entity.getTags()) {
tagDefs.add(next.getTag());
}
@ -1522,7 +1527,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
StopWatch w = new StopWatch();
JpaPid jpaPid = (JpaPid) thePid;
Optional<ResourceTable> entity = myResourceTableDao.findById(jpaPid.getId());
Optional<ResourceTable> entity = myResourceTableDao.findById(jpaPid);
if (entity.isEmpty()) {
throw new ResourceNotFoundException(Msg.code(975) + "No resource found with PID " + jpaPid);
}
@ -1569,10 +1574,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
assert TransactionSynchronizationManager.isActualTransactionActive();
StopWatch w = new StopWatch();
BaseHasResource entity = readEntity(theId, true, theRequest, theRequestPartitionId);
BaseHasResource<?> entity = readEntity(theId, true, theRequest, theRequestPartitionId);
validateResourceType(entity);
T retVal = myJpaStorageResourceParser.toResource(myResourceType, entity, null, false);
T retVal = myJpaStorageResourceParser.toResource(
myResourceType, (IBaseResourceEntity<JpaPid>) entity, null, false);
if (!theDeletedOk) {
if (isDeleted(entity)) {
@ -1642,9 +1648,9 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
// We use the main entity as the lock object since all the index rows hang off it.
ResourceTable entity;
if (theReindexParameters.isOptimisticLock()) {
entity = myEntityManager.find(ResourceTable.class, jpaPid.getId(), LockModeType.OPTIMISTIC);
entity = myEntityManager.find(ResourceTable.class, jpaPid, LockModeType.OPTIMISTIC);
} else {
entity = myEntityManager.find(ResourceTable.class, jpaPid.getId());
entity = myEntityManager.find(ResourceTable.class, jpaPid);
}
if (entity == null) {
@ -1709,7 +1715,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
ResourceTable entity, ReindexParameters.OptimizeStorageModeEnum theOptimizeStorageMode) {
ResourceHistoryTable historyEntity = entity.getCurrentVersionEntity();
if (historyEntity != null) {
reindexOptimizeStorageHistoryEntityThenDetachIt(entity, historyEntity);
reindexOptimizeStorageHistoryEntity(entity, historyEntity);
if (theOptimizeStorageMode == ReindexParameters.OptimizeStorageModeEnum.ALL_VERSIONS) {
int pageSize = 100;
for (int page = 0; ((long) page * pageSize) < entity.getVersion(); page++) {
@ -1720,10 +1726,10 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
PageRequest pageRequest = PageRequest.of(page, pageSize, Sort.by("myId"));
Slice<ResourceHistoryTable> historyEntities =
myResourceHistoryTableDao.findAllVersionsExceptSpecificForResourcePid(
pageRequest, entity.getId(), historyEntity.getVersion());
pageRequest, entity.getId().toFk(), historyEntity.getVersion());
for (ResourceHistoryTable next : historyEntities) {
reindexOptimizeStorageHistoryEntityThenDetachIt(entity, next);
reindexOptimizeStorageHistoryEntity(entity, next);
}
}
}
@ -1734,8 +1740,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
* Note that the entity will be detached after being saved if it has changed
* in order to avoid growing the number of resources in memory to be too big
*/
private void reindexOptimizeStorageHistoryEntityThenDetachIt(
ResourceTable entity, ResourceHistoryTable historyEntity) {
private void reindexOptimizeStorageHistoryEntity(ResourceTable entity, ResourceHistoryTable historyEntity) {
if (historyEntity.getEncoding() == ResourceEncodingEnum.JSONC
|| historyEntity.getEncoding() == ResourceEncodingEnum.JSON) {
byte[] resourceBytes = historyEntity.getResource();
@ -1746,7 +1751,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
}
if (myStorageSettings.isAccessMetaSourceInformationFromProvenanceTable()) {
if (isBlank(historyEntity.getSourceUri()) && isBlank(historyEntity.getRequestId())) {
Long id = historyEntity.getId();
IdAndPartitionId id = historyEntity.getId().asIdAndPartitionId();
Optional<ResourceHistoryProvenanceEntity> provenanceEntityOpt =
myResourceHistoryProvenanceDao.findById(id);
if (provenanceEntityOpt.isPresent()) {
@ -1759,7 +1764,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
}
}
private BaseHasResource readEntity(
private BaseHasResource<?> readEntity(
IIdType theId,
boolean theCheckForForcedId,
RequestDetails theRequest,
@ -1776,7 +1781,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
.getPersistentId();
Set<Integer> readPartitions = null;
if (requestPartitionId.isAllPartitions()) {
entity = myEntityManager.find(ResourceTable.class, pid.getId());
entity = myEntityManager.find(ResourceTable.class, pid);
} else {
readPartitions = myRequestPartitionHelperService.toReadPartitions(requestPartitionId);
if (readPartitions.size() == 1) {
@ -1872,7 +1877,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
RequestDetails theRequestDetails,
TransactionDetails theTransactionDetails) {
JpaPid jpaPid = (JpaPid) thePersistentId;
return myEntityManager.find(ResourceTable.class, jpaPid.getId());
return myEntityManager.find(ResourceTable.class, jpaPid);
}
@Override
@ -1885,11 +1890,13 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
return myTransactionService
.withRequest(theRequestDetails)
.withRequestPartitionId(requestPartitionId)
.execute(() -> readEntityLatestVersion(theId, requestPartitionId, theTransactionDetails));
.execute(() ->
readEntityLatestVersion(theRequestDetails, theId, requestPartitionId, theTransactionDetails));
}
@Nonnull
private ResourceTable readEntityLatestVersion(
RequestDetails theRequestDetails,
IIdType theId,
@Nonnull RequestPartitionId theRequestPartitionId,
TransactionDetails theTransactionDetails) {
@ -1919,7 +1926,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
ResolveIdentityMode.includeDeleted().cacheOk());
}
ResourceTable entity = myEntityManager.find(ResourceTable.class, persistentId.getId());
ResourceTable entity = myEntityManager.find(ResourceTable.class, persistentId);
if (entity == null) {
throw new ResourceNotFoundException(Msg.code(1998) + id);
}
@ -1938,7 +1945,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
public void removeTag(
IIdType theId, TagTypeEnum theTagType, String theScheme, String theTerm, RequestDetails theRequest) {
StopWatch w = new StopWatch();
BaseHasResource entity = readEntity(theId, theRequest);
BaseHasResource<?> entity = readEntity(theId, theRequest);
if (entity == null) {
throw new ResourceNotFoundException(Msg.code(1999) + theId);
}
@ -2171,7 +2178,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
private <V> List<V> searchForTransformedIds(
SearchParameterMap theParams,
RequestDetails theRequest,
BiFunction<RequestDetails, Stream<JpaPid>, Stream<V>> transform) {
TriFunction<RequestDetails, Stream<JpaPid>, RequestPartitionId, Stream<V>> transform) {
RequestPartitionId requestPartitionId =
myRequestPartitionHelperService.determineReadPartitionForRequestForSearchType(
theRequest, myResourceName, theParams);
@ -2188,7 +2195,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
Stream<JpaPid> pidStream =
builder.createQueryStream(theParams, searchRuntimeDetails, theRequest, requestPartitionId);
Stream<V> transformedStream = transform.apply(theRequest, pidStream);
Stream<V> transformedStream = transform.apply(theRequest, pidStream, requestPartitionId);
return transformedStream.collect(Collectors.toList());
});
@ -2198,12 +2205,13 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
* Fetch the resources in chunks and apply PreAccess/PreShow interceptors.
*/
@Nonnull
private Stream<T> pidsToResource(RequestDetails theRequest, Stream<JpaPid> pidStream) {
private Stream<T> pidsToResource(
RequestDetails theRequest, Stream<JpaPid> thePidStream, RequestPartitionId theRequestPartitionId) {
ISearchBuilder<JpaPid> searchBuilder =
mySearchBuilderFactory.newSearchBuilder(getResourceName(), getResourceType());
@SuppressWarnings("unchecked")
Stream<T> resourceStream = (Stream<T>) new QueryChunker<>()
.chunk(pidStream, SearchBuilder.getMaximumPageSize())
.chunk(thePidStream, SearchBuilder.getMaximumPageSize())
.flatMap(pidChunk -> searchBuilder.loadResourcesByPid(pidChunk, theRequest).stream());
// apply interceptors
return resourceStream
@ -2215,11 +2223,19 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
* get the Ids from the ResourceTable entities in chunks.
*/
@Nonnull
private Stream<IIdType> pidsToIds(RequestDetails theRequestDetails, Stream<JpaPid> thePidStream) {
Stream<Long> longStream = thePidStream.map(JpaPid::getId);
private Stream<IIdType> pidsToIds(
RequestDetails theRequestDetails, Stream<JpaPid> thePidStream, RequestPartitionId theRequestPartitionId) {
Stream<JpaPid> pidStream = thePidStream;
if (!theRequestPartitionId.isAllPartitions()
&& theRequestPartitionId.getPartitionIds().size() == 1) {
pidStream = pidStream.map(t -> t.setPartitionIdIfNotAlreadySet(
theRequestPartitionId.getPartitionIds().get(0)));
}
return new QueryChunker<>()
.chunk(longStream, SearchBuilder.getMaximumPageSize())
.chunk(pidStream, SearchBuilder.getMaximumPageSize())
.flatMap(ids -> myResourceTableDao.findAllById(ids).stream())
.map(ResourceTable::getIdDt);
}
@ -2386,7 +2402,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
throw new PreconditionFailedException(Msg.code(988) + msg);
} else if (match.size() == 1) {
JpaPid pid = match.iterator().next();
entity = myEntityManager.find(ResourceTable.class, pid.getId());
entity = myEntityManager.find(ResourceTable.class, pid);
resourceId = entity.getIdDt();
if (myFhirContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.R4)
&& theResource.getIdElement().getIdPart() != null) {
@ -2450,7 +2466,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
if (!create) {
try {
entity = readEntityLatestVersion(resourceId, theRequestPartitionId, theTransactionDetails);
entity = readEntityLatestVersion(
theRequest, resourceId, theRequestPartitionId, theTransactionDetails);
} catch (ResourceNotFoundException e) {
create = true;
}
@ -2494,8 +2511,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
if (!theTransactionDetails.isFhirTransaction()) {
Set<IResourcePersistentId> resourceIds = theTransactionDetails.getUpdatedResourceIds();
if (resourceIds != null && !resourceIds.isEmpty()) {
List<Long> ids = resourceIds.stream().map(r -> (Long) r.getId()).collect(Collectors.toList());
@Nonnull
List<JpaPid> ids = resourceIds.stream().map(r -> (JpaPid) r).collect(Collectors.toList());
myResourceSearchUrlSvc.deleteByResIds(ids);
}
}
@ -2519,8 +2536,21 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
* duplicate index violations if we try to add another (after this create/update)
*/
ResourceTable entity = (ResourceTable) theEntity;
/*
* If we read back the entity from hibernate, and it's already saying
* it's been updated in this transaction, then someone is probably
* doing multiple modifications of the same resource within the same
* database transaction. The only way for this to work cleanly is for
* us to flush hibernate now. That way we can increment the version
* a second time, create multiple history entries, etc.
*/
if (entity != null && entity.isVersionUpdatedInCurrentTransaction()) {
myEntityManager.flush();
}
if (entity.isSearchUrlPresent()) {
JpaPid persistentId = JpaPid.fromId(entity.getResourceId());
JpaPid persistentId = entity.getResourceId();
theTransactionDetails.addUpdatedResourceId(persistentId);
entity.setSearchUrlPresent(false); // it will be removed at the end
@ -2578,8 +2608,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
assert resourceId.hasIdPart();
try {
currentEntity =
readEntityLatestVersion(resourceId.toVersionless(), theRequestPartitionId, theTransactionDetails);
currentEntity = readEntityLatestVersion(
theRequest, resourceId.toVersionless(), theRequestPartitionId, theTransactionDetails);
if (!resourceId.hasVersionIdPart()) {
throw new InvalidRequestException(
@ -2640,7 +2670,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
.withRequestPartitionId(requestPartitionId)
.execute(() -> {
final ResourceTable entity =
readEntityLatestVersion(theId, requestPartitionId, transactionDetails);
readEntityLatestVersion(theRequest, theId, requestPartitionId, transactionDetails);
// Validate that there are no resources pointing to the candidate that
// would prevent deletion
@ -2723,7 +2753,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
}
}
private void validateResourceType(BaseHasResource entity) {
private void validateResourceType(IBasePersistedResource<?> entity) {
validateResourceType(entity, myResourceName);
}

View File

@ -190,7 +190,7 @@ public abstract class BaseHapiFhirSystemDao<T extends IBaseBundle, MT> extends B
public <P extends IResourcePersistentId> void preFetchResources(
List<P> theResolvedIds, boolean thePreFetchIndexes) {
HapiTransactionService.requireTransaction();
List<Long> pids = theResolvedIds.stream().map(t -> ((JpaPid) t).getId()).collect(Collectors.toList());
List<JpaPid> pids = theResolvedIds.stream().map(t -> ((JpaPid) t)).collect(Collectors.toList());
QueryChunker.chunk(pids, idChunk -> {
@ -215,7 +215,13 @@ public abstract class BaseHapiFhirSystemDao<T extends IBaseBundle, MT> extends B
prefetchByField("date", "myParamsDate", ResourceTable::isParamsDatePopulated, entityChunk);
prefetchByField(
"quantity", "myParamsQuantity", ResourceTable::isParamsQuantityPopulated, entityChunk);
prefetchByField("resourceLinks", "myResourceLinks", ResourceTable::isHasLinks, entityChunk);
prefetchByJoinClause(
"resourceLinks",
// fetch the ResourceLink but also the target resource for that link
"LEFT JOIN FETCH r.myResourceLinks l LEFT JOIN FETCH l.myTargetResource",
ResourceTable::isHasLinks,
entityChunk);
prefetchByJoinClause(
"tags",
@ -244,14 +250,14 @@ public abstract class BaseHapiFhirSystemDao<T extends IBaseBundle, MT> extends B
}
@Nonnull
private List<ResourceTable> prefetchResourceTableAndHistory(List<Long> idChunk) {
private List<ResourceTable> prefetchResourceTableAndHistory(List<JpaPid> idChunk) {
assert idChunk.size() < SearchConstants.MAX_PAGE_SIZE : "assume pre-chunked";
Query query = myEntityManager.createQuery("select r, h "
+ " FROM ResourceTable r "
+ " LEFT JOIN fetch ResourceHistoryTable h "
+ " on r.myVersion = h.myResourceVersion and r.id = h.myResourceId "
+ " WHERE r.myId IN ( :IDS ) ");
+ " on r.myVersion = h.myResourceVersion and r = h.myResourceTable "
+ " WHERE r.myPid IN ( :IDS ) ");
query.setParameter("IDS", idChunk);
@SuppressWarnings("unchecked")
@ -302,7 +308,7 @@ public abstract class BaseHapiFhirSystemDao<T extends IBaseBundle, MT> extends B
List<ResourceTable> theEntities) {
// Which entities need this prefetch?
List<Long> idSubset = theEntities.stream()
List<JpaPid> idSubset = theEntities.stream()
.filter(theEntityPredicate)
.map(ResourceTable::getId)
.collect(Collectors.toList());
@ -312,7 +318,7 @@ public abstract class BaseHapiFhirSystemDao<T extends IBaseBundle, MT> extends B
return;
}
String jqlQuery = "FROM ResourceTable r " + theJoinClause + " WHERE r.myId IN ( :IDS )";
String jqlQuery = "FROM ResourceTable r " + theJoinClause + " WHERE r.myPid IN ( :IDS )";
TypedQuery<ResourceTable> query = myEntityManager.createQuery(jqlQuery, ResourceTable.class);
query.setParameter("IDS", idSubset);

View File

@ -43,32 +43,18 @@ public class FhirResourceDaoSubscriptionDstu2 extends BaseHapiFhirResourceDao<Su
@Autowired
private PlatformTransactionManager myTxManager;
private void createSubscriptionTable(ResourceTable theEntity, Subscription theSubscription) {
SubscriptionTable subscriptionEntity = new SubscriptionTable();
subscriptionEntity.setCreated(new Date());
subscriptionEntity.setSubscriptionResource(theEntity);
myEntityManager.persist(subscriptionEntity);
}
@Override
public Long getSubscriptionTablePidForSubscriptionResource(
IIdType theId, RequestDetails theRequest, TransactionDetails theTransactionDetails) {
ResourceTable entity = readEntityLatestVersion(theId, theRequest, theTransactionDetails);
SubscriptionTable table = mySubscriptionTableDao.findOneByResourcePid(entity.getId());
SubscriptionTable table =
mySubscriptionTableDao.findOneByResourcePid(entity.getId().getId());
if (table == null) {
return null;
}
return table.getId();
}
@Override
protected void postPersist(
ResourceTable theEntity, Subscription theSubscription, RequestDetails theRequestDetails) {
super.postPersist(theEntity, theSubscription, theRequestDetails);
createSubscriptionTable(theEntity, theSubscription);
}
@Override
public ResourceTable updateEntity(
RequestDetails theRequest,
@ -92,7 +78,8 @@ public class FhirResourceDaoSubscriptionDstu2 extends BaseHapiFhirResourceDao<Su
theCreateNewHistoryEntry);
if (theDeletedTimestampOrNull != null) {
mySubscriptionTableDao.deleteAllForSubscription((ResourceTable) theEntity);
mySubscriptionTableDao.deleteAllForSubscription(
((ResourceTable) theEntity).getResourceId().getId());
}
return retVal;
}

View File

@ -193,7 +193,7 @@ public class FulltextSearchSvcImpl implements IFulltextSearchSvc {
String theResourceType, SearchParameterMap theParams, RequestDetails theRequestDetails) {
validateHibernateSearchIsEnabled();
SearchQueryOptionsStep<?, Long, SearchLoadingOptionsStep, ?, ?> searchQueryOptionsStep =
SearchQueryOptionsStep<?, JpaPid, SearchLoadingOptionsStep, ?, ?> searchQueryOptionsStep =
getSearchQueryOptionsStep(theResourceType, theParams, null);
logQuery(searchQueryOptionsStep, theRequestDetails);
@ -213,14 +213,14 @@ public class FulltextSearchSvcImpl implements IFulltextSearchSvc {
int count = getMaxFetchSize(theParams, theMaxResultsToFetch);
// perform an offset search instead of a scroll one, which doesn't allow for offset
SearchQueryOptionsStep<?, Long, SearchLoadingOptionsStep, ?, ?> searchQueryOptionsStep =
SearchQueryOptionsStep<?, JpaPid, SearchLoadingOptionsStep, ?, ?> searchQueryOptionsStep =
getSearchQueryOptionsStep(theResourceType, theParams, theReferencingPid);
logQuery(searchQueryOptionsStep, theRequestDetails);
List<Long> longs = searchQueryOptionsStep.fetchHits(offset, count);
List<JpaPid> longs = searchQueryOptionsStep.fetchHits(offset, count);
// indicate param was already processed, otherwise queries DB to process it
theParams.setOffset(null);
return SearchQueryExecutors.from(JpaPid.fromLongList(longs));
return SearchQueryExecutors.from(longs);
}
private int getMaxFetchSize(SearchParameterMap theParams, Integer theMax) {
@ -237,16 +237,16 @@ public class FulltextSearchSvcImpl implements IFulltextSearchSvc {
}
@SuppressWarnings("rawtypes")
private SearchQueryOptionsStep<?, Long, SearchLoadingOptionsStep, ?, ?> getSearchQueryOptionsStep(
private SearchQueryOptionsStep<?, JpaPid, SearchLoadingOptionsStep, ?, ?> getSearchQueryOptionsStep(
String theResourceType, SearchParameterMap theParams, IResourcePersistentId theReferencingPid) {
dispatchEvent(IHSearchEventListener.HSearchEventType.SEARCH);
var query = getSearchSession()
SearchQueryOptionsStep<?, JpaPid, SearchLoadingOptionsStep, ?, ?> query = getSearchSession()
.search(ResourceTable.class)
// The document id is the PK which is pid. We use this instead of _myId to avoid fetching the doc body.
.select(
// adapt the String docRef.id() to the Long that it really is.
f -> f.composite(docRef -> Long.valueOf(docRef.id()), f.documentReference()))
f -> f.composite(docRef -> JpaPid.fromId(Long.valueOf(docRef.id())), f.documentReference()))
.where(f -> buildWhereClause(f, theResourceType, theParams, theReferencingPid));
if (theParams.getSort() != null) {
@ -456,7 +456,7 @@ public class FulltextSearchSvcImpl implements IFulltextSearchSvc {
List<ExtendedHSearchResourceProjection> rawResourceDataList = session.search(ResourceTable.class)
.select(this::buildResourceSelectClause)
.where(
f -> f.id().matchingAny(thePids) // matches '_id' from resource index
f -> f.id().matchingAny(JpaPid.fromLongList(thePids)) // matches '_id' from resource index
)
.fetchAllHits();
@ -480,14 +480,14 @@ public class FulltextSearchSvcImpl implements IFulltextSearchSvc {
SearchProjectionFactory<EntityReference, ResourceTable> f) {
return f.composite(
ExtendedHSearchResourceProjection::new,
f.field("myId", Long.class),
f.field("myId", JpaPid.class),
f.field("myForcedId", String.class),
f.field("myRawResource", String.class));
}
@Override
public long count(String theResourceName, SearchParameterMap theParams) {
SearchQueryOptionsStep<?, Long, SearchLoadingOptionsStep, ?, ?> queryOptionsStep =
SearchQueryOptionsStep<?, JpaPid, SearchLoadingOptionsStep, ?, ?> queryOptionsStep =
getSearchQueryOptionsStep(theResourceName, theParams, null);
return queryOptionsStep.fetchTotalHitCount();

View File

@ -55,7 +55,6 @@ import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static ca.uhn.fhir.jpa.util.QueryParameterUtils.toPredicateArray;
@ -66,7 +65,7 @@ public class HistoryBuilder {
private static final Logger ourLog = LoggerFactory.getLogger(HistoryBuilder.class);
private final String myResourceType;
private final Long myResourceId;
private final JpaPid myResourceId;
private final Date myRangeStartInclusive;
private final Date myRangeEndInclusive;
@ -90,7 +89,7 @@ public class HistoryBuilder {
*/
public HistoryBuilder(
@Nullable String theResourceType,
@Nullable Long theResourceId,
@Nullable JpaPid theResourceId,
@Nullable Date theRangeStartInclusive,
@Nullable Date theRangeEndInclusive) {
myResourceType = theResourceType;
@ -111,7 +110,6 @@ public class HistoryBuilder {
return query.getSingleResult();
}
@SuppressWarnings("OptionalIsPresent")
public List<ResourceHistoryTable> fetchEntities(
RequestPartitionId thePartitionId,
Integer theOffset,
@ -151,20 +149,18 @@ public class HistoryBuilder {
List<ResourceHistoryTable> tables = query.getResultList();
if (!tables.isEmpty()) {
ImmutableListMultimap<Long, ResourceHistoryTable> resourceIdToHistoryEntries =
ImmutableListMultimap<JpaPid, ResourceHistoryTable> resourceIdToHistoryEntries =
Multimaps.index(tables, ResourceHistoryTable::getResourceId);
Set<JpaPid> pids = resourceIdToHistoryEntries.keySet().stream()
.map(JpaPid::fromId)
.collect(Collectors.toSet());
Set<JpaPid> pids = resourceIdToHistoryEntries.keySet();
PersistentIdToForcedIdMap<JpaPid> pidToForcedId = myIdHelperService.translatePidsToForcedIds(pids);
ourLog.trace("Translated IDs: {}", pidToForcedId.getResourcePersistentIdOptionalMap());
for (Long nextResourceId : resourceIdToHistoryEntries.keySet()) {
for (JpaPid nextResourceId : resourceIdToHistoryEntries.keySet()) {
List<ResourceHistoryTable> historyTables = resourceIdToHistoryEntries.get(nextResourceId);
String resourceId;
Optional<String> forcedId = pidToForcedId.get(JpaPid.fromId(nextResourceId));
Optional<String> forcedId = pidToForcedId.get(nextResourceId);
if (forcedId.isPresent()) {
resourceId = forcedId.get();
// IdHelperService returns a forcedId with the '<resourceType>/' prefix
@ -177,7 +173,7 @@ public class HistoryBuilder {
resourceId = resourceId.substring(slashIdx + 1);
}
} else {
resourceId = nextResourceId.toString();
resourceId = Long.toString(nextResourceId.getId());
}
for (ResourceHistoryTable nextHistoryTable : historyTables) {
@ -197,25 +193,38 @@ public class HistoryBuilder {
HistorySearchStyleEnum theHistorySearchStyle) {
List<Predicate> predicates = new ArrayList<>();
if (!thePartitionId.isAllPartitions()) {
if (thePartitionId.isDefaultPartition()) {
predicates.add(theCriteriaBuilder.isNull(theFrom.get("myPartitionIdValue")));
} else if (thePartitionId.hasDefaultPartitionId()) {
predicates.add(theCriteriaBuilder.or(
theCriteriaBuilder.isNull(theFrom.get("myPartitionIdValue")),
theFrom.get("myPartitionIdValue").in(thePartitionId.getPartitionIdsWithoutDefault())));
} else {
predicates.add(theFrom.get("myPartitionIdValue").in(thePartitionId.getPartitionIds()));
}
}
if (myResourceId != null) {
predicates.add(theCriteriaBuilder.equal(theFrom.get("myResourceId"), myResourceId));
} else if (myResourceType != null) {
validateNotSearchingAllPartitions(thePartitionId);
predicates.add(theCriteriaBuilder.equal(theFrom.get("myResourceType"), myResourceType));
predicates.add(theCriteriaBuilder.equal(theFrom.get("myResourceId"), myResourceId.getId()));
if (myPartitionSettings.isPartitioningEnabled()) {
if (myResourceId.getPartitionId() != null) {
predicates.add(
theCriteriaBuilder.equal(theFrom.get("myPartitionIdValue"), myResourceId.getPartitionId()));
} else {
predicates.add(theCriteriaBuilder.isNull(theFrom.get("myPartitionIdValue")));
}
}
} else {
validateNotSearchingAllPartitions(thePartitionId);
if (!thePartitionId.isAllPartitions()) {
if (thePartitionId.isDefaultPartition()) {
predicates.add(theCriteriaBuilder.isNull(theFrom.get("myPartitionIdValue")));
} else if (thePartitionId.hasDefaultPartitionId()) {
predicates.add(theCriteriaBuilder.or(
theCriteriaBuilder.isNull(theFrom.get("myPartitionIdValue")),
theFrom.get("myPartitionIdValue").in(thePartitionId.getPartitionIdsWithoutDefault())));
} else {
predicates.add(theFrom.get("myPartitionIdValue").in(thePartitionId.getPartitionIds()));
}
}
if (myResourceType != null) {
validateNotSearchingAllPartitions(thePartitionId);
predicates.add(theCriteriaBuilder.equal(theFrom.get("myResourceType"), myResourceType));
} else {
validateNotSearchingAllPartitions(thePartitionId);
}
}
if (myRangeStartInclusive != null) {
@ -266,7 +275,7 @@ public class HistoryBuilder {
.where(
theCriteriaBuilder.lessThanOrEqualTo(
subQueryResourceHistory.get("myUpdated"), myRangeStartInclusive),
theCriteriaBuilder.equal(subQueryResourceHistory.get("myResourceId"), myResourceId));
theCriteriaBuilder.equal(subQueryResourceHistory.get("myResourcePid"), myResourceId.toFk()));
Predicate updatedDatePredicate =
theCriteriaBuilder.greaterThanOrEqualTo(theFrom.get("myUpdated"), pastDateSubQuery);

View File

@ -20,6 +20,7 @@
package ca.uhn.fhir.jpa.dao;
import ca.uhn.fhir.jpa.config.JpaConfig;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import jakarta.annotation.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
@ -33,7 +34,7 @@ public class HistoryBuilderFactory {
public HistoryBuilder newHistoryBuilder(
@Nullable String theResourceType,
@Nullable Long theResourceId,
@Nullable JpaPid theResourceId,
@Nullable Date theRangeStartInclusive,
@Nullable Date theRangeEndInclusive) {
return (HistoryBuilder) myApplicationContext.getBean(

View File

@ -35,7 +35,7 @@ public interface IJpaStorageResourceParser extends IStorageResourceParser<JpaPid
*/
<R extends IBaseResource> R toResource(
Class<R> theResourceType,
IBaseResourceEntity theEntity,
IBaseResourceEntity<?> theEntity,
Collection<BaseTag> theTagList,
boolean theForHistoryOperation);
@ -44,7 +44,7 @@ public interface IJpaStorageResourceParser extends IStorageResourceParser<JpaPid
* objects pulled from the database
*/
<R extends IBaseResource> R populateResourceMetadata(
IBaseResourceEntity theEntitySource,
IBaseResourceEntity<?> theEntitySource,
boolean theForHistoryOperation,
@Nullable Collection<? extends BaseTag> tagList,
long theVersion,
@ -57,5 +57,5 @@ public interface IJpaStorageResourceParser extends IStorageResourceParser<JpaPid
* @param theEntitySource The source
* @param theResourceTarget The target
*/
void updateResourceMetadata(IBaseResourceEntity theEntitySource, IBaseResource theResourceTarget);
void updateResourceMetadata(IBaseResourceEntity<?> theEntitySource, IBaseResource theResourceTarget);
}

View File

@ -232,6 +232,7 @@ public class JpaResourceDaoCodeSystem<T extends IBaseResource> extends BaseHapiF
TransactionDetails theTransactionDetails,
boolean theForceUpdate,
boolean theCreateNewHistoryEntry) {
ResourceTable retVal = super.updateEntity(
theRequest,
theResource,
@ -251,6 +252,15 @@ public class JpaResourceDaoCodeSystem<T extends IBaseResource> extends BaseHapiF
myTerminologyCodeSystemStorageSvc.storeNewCodeSystemVersionIfNeeded(
cs, (ResourceTable) theEntity, theRequest);
}
/*
* Flushing for each stored resource hurts performance, but in this case
* it's justified because we don't expect people to be submitting
* CodeSystem resources at super high rates, and we need to have the
* various writes finished in case a second entry in the same transaction
* tries to create a duplicate codesystem.
*/
myEntityManager.flush();
}
return retVal;

View File

@ -33,6 +33,7 @@ import ca.uhn.fhir.jpa.esr.ExternallyStoredResourceServiceRegistry;
import ca.uhn.fhir.jpa.esr.IExternallyStoredResourceService;
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.BaseTag;
import ca.uhn.fhir.jpa.model.entity.IBaseResourceEntity;
import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
@ -112,13 +113,13 @@ public class JpaStorageResourceParser implements IJpaStorageResourceParser {
public IBaseResource toResource(IBasePersistedResource theEntity, boolean theForHistoryOperation) {
RuntimeResourceDefinition type = myFhirContext.getResourceDefinition(theEntity.getResourceType());
Class<? extends IBaseResource> resourceType = type.getImplementingClass();
return toResource(resourceType, (IBaseResourceEntity) theEntity, null, theForHistoryOperation);
return toResource(resourceType, (IBaseResourceEntity<JpaPid>) theEntity, null, theForHistoryOperation);
}
@Override
public <R extends IBaseResource> R toResource(
Class<R> theResourceType,
IBaseResourceEntity theEntity,
IBaseResourceEntity<?> theEntity,
Collection<BaseTag> theTagList,
boolean theForHistoryOperation) {
@ -164,8 +165,8 @@ public class JpaStorageResourceParser implements IJpaStorageResourceParser {
provenanceRequestId = history.getRequestId();
if (isBlank(provenanceSourceUri) && isBlank(provenanceRequestId)) {
if (myStorageSettings.isAccessMetaSourceInformationFromProvenanceTable()) {
Optional<ResourceHistoryProvenanceEntity> provenanceOpt =
myResourceHistoryProvenanceDao.findById(history.getId());
Optional<ResourceHistoryProvenanceEntity> provenanceOpt = myResourceHistoryProvenanceDao.findById(
history.getId().asIdAndPartitionId());
if (provenanceOpt.isPresent()) {
ResourceHistoryProvenanceEntity provenance = provenanceOpt.get();
provenanceRequestId = provenance.getRequestId();
@ -180,13 +181,15 @@ public class JpaStorageResourceParser implements IJpaStorageResourceParser {
history = resource.getCurrentVersionEntity();
} else {
version = theEntity.getVersion();
history = myResourceHistoryTableDao.findForIdAndVersion(theEntity.getResourceId(), version);
history = myResourceHistoryTableDao.findForIdAndVersion(
theEntity.getResourceId().toFk(), version);
((ResourceTable) theEntity).setCurrentVersionEntity(history);
while (history == null) {
if (version > 1L) {
version--;
history = myResourceHistoryTableDao.findForIdAndVersion(theEntity.getResourceId(), version);
history = myResourceHistoryTableDao.findForIdAndVersion(
theEntity.getResourceId().toFk(), version);
} else {
return null;
}
@ -215,8 +218,8 @@ public class JpaStorageResourceParser implements IJpaStorageResourceParser {
provenanceRequestId = history.getRequestId();
if (isBlank(provenanceSourceUri) && isBlank(provenanceRequestId)) {
if (myStorageSettings.isAccessMetaSourceInformationFromProvenanceTable()) {
Optional<ResourceHistoryProvenanceEntity> provenanceOpt =
myResourceHistoryProvenanceDao.findById(history.getId());
Optional<ResourceHistoryProvenanceEntity> provenanceOpt = myResourceHistoryProvenanceDao.findById(
history.getId().asIdAndPartitionId());
if (provenanceOpt.isPresent()) {
ResourceHistoryProvenanceEntity provenance = provenanceOpt.get();
provenanceRequestId = provenance.getRequestId();
@ -269,7 +272,7 @@ public class JpaStorageResourceParser implements IJpaStorageResourceParser {
@SuppressWarnings("unchecked")
private <R extends IBaseResource> R parseResource(
IBaseResourceEntity theEntity,
IBaseResourceEntity<?> theEntity,
ResourceEncodingEnum theResourceEncoding,
String theDecodedResourceText,
Class<R> theResourceType) {
@ -346,7 +349,7 @@ public class JpaStorageResourceParser implements IJpaStorageResourceParser {
@SuppressWarnings("unchecked")
@Override
public <R extends IBaseResource> R populateResourceMetadata(
IBaseResourceEntity theEntitySource,
IBaseResourceEntity<?> theEntitySource,
boolean theForHistoryOperation,
@Nullable Collection<? extends BaseTag> tagList,
long theVersion,
@ -365,7 +368,7 @@ public class JpaStorageResourceParser implements IJpaStorageResourceParser {
@SuppressWarnings("unchecked")
private <R extends IResource> R populateResourceMetadataHapi(
IBaseResourceEntity theEntity,
IBaseResourceEntity<?> theEntity,
@Nullable Collection<? extends BaseTag> theTagList,
boolean theForHistoryOperation,
R res,
@ -519,7 +522,7 @@ public class JpaStorageResourceParser implements IJpaStorageResourceParser {
}
@Override
public void updateResourceMetadata(IBaseResourceEntity theEntitySource, IBaseResource theResourceTarget) {
public void updateResourceMetadata(IBaseResourceEntity<?> theEntitySource, IBaseResource theResourceTarget) {
IIdType id = theEntitySource.getIdDt();
if (myFhirContext.getVersion().getVersion().isRi()) {
id = myFhirContext.getVersion().newIdType().setValue(id.getValue());

View File

@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.dao;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParserErrorHandler;
import ca.uhn.fhir.parser.JsonParser;
@ -42,7 +43,7 @@ public class TolerantJsonParser extends JsonParser {
private static final Logger ourLog = LoggerFactory.getLogger(TolerantJsonParser.class);
private final FhirContext myContext;
private final Long myResourcePid;
private final JpaPid myResourcePid;
/**
* Constructor
@ -50,7 +51,8 @@ public class TolerantJsonParser extends JsonParser {
* @param theResourcePid The ID of the resource that will be parsed with this parser. It would be ok to change the
* datatype for this param if we ever need to since it's only used for logging.
*/
public TolerantJsonParser(FhirContext theContext, IParserErrorHandler theParserErrorHandler, Long theResourcePid) {
public TolerantJsonParser(
FhirContext theContext, IParserErrorHandler theParserErrorHandler, JpaPid theResourcePid) {
super(theContext, theParserErrorHandler);
myContext = theContext;
myResourcePid = theResourcePid;
@ -121,7 +123,7 @@ public class TolerantJsonParser extends JsonParser {
}
public static TolerantJsonParser createWithLenientErrorHandling(
FhirContext theContext, @Nullable Long theResourcePid) {
FhirContext theContext, @Nullable JpaPid theResourcePid) {
LenientErrorHandler errorHandler = new LenientErrorHandler(false).disableAllErrors();
return new TolerantJsonParser(theContext, errorHandler, theResourcePid);
}

View File

@ -89,8 +89,8 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class TransactionProcessor extends BaseTransactionProcessor {
public static final Pattern SINGLE_PARAMETER_MATCH_URL_PATTERN = Pattern.compile("^[^?]+[?][a-z0-9-]+=[^&,]+$");
private static final Logger ourLog = LoggerFactory.getLogger(TransactionProcessor.class);
public static final int CONDITIONAL_URL_FETCH_CHUNK_SIZE = 100;
private static final Logger ourLog = LoggerFactory.getLogger(TransactionProcessor.class);
@Autowired
private ApplicationContext myApplicationContext;
@ -229,12 +229,12 @@ public class TransactionProcessor extends BaseTransactionProcessor {
systemDao.preFetchResources(JpaPid.fromLongList(idsToPreFetch), true);
}
@Override
@SuppressWarnings("rawtypes")
protected void postTransactionProcess(TransactionDetails theTransactionDetails) {
Set<IResourcePersistentId> resourceIds = theTransactionDetails.getUpdatedResourceIds();
if (resourceIds != null && !resourceIds.isEmpty()) {
List<Long> ids = resourceIds.stream().map(r -> (Long) r.getId()).collect(Collectors.toList());
List<JpaPid> ids = resourceIds.stream().map(r -> (JpaPid) r).collect(Collectors.toList());
myResourceSearchUrlSvc.deleteByResIds(ids);
}
}
@ -463,7 +463,7 @@ public class TransactionProcessor extends BaseTransactionProcessor {
CriteriaBuilder cb = myEntityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
Root<ResourceIndexedSearchParamToken> from = cq.from(ResourceIndexedSearchParamToken.class);
cq.multiselect(from.get("myResourcePid"), from.get(theIndexColumnName));
cq.multiselect(from.get("myPartitionIdValue"), from.get("myResourcePid"), from.get(theIndexColumnName));
Predicate masterPredicate;
if (theHashesForIndexColumn.size() == 1) {
@ -507,21 +507,20 @@ public class TransactionProcessor extends BaseTransactionProcessor {
List<Tuple> results = query.getResultList();
for (Tuple nextResult : results) {
Long nextResourcePid = nextResult.get(0, Long.class);
Long nextHash = nextResult.get(1, Long.class);
Integer nextPartitionId = nextResult.get(0, Integer.class);
Long nextResourcePid = nextResult.get(1, Long.class);
Long nextHash = nextResult.get(2, Long.class);
List<MatchUrlToResolve> matchedSearch = hashToSearchMap.get(nextHash);
matchedSearch.forEach(matchUrl -> {
ourLog.debug("Matched url {} from database", matchUrl.myRequestUrl);
if (matchUrl.myShouldPreFetchResourceBody) {
theOutputPidsToLoadFully.add(nextResourcePid);
}
JpaPid pid = JpaPid.fromId(nextResourcePid, nextPartitionId);
myMatchResourceUrlService.matchUrlResolved(
theTransactionDetails,
matchUrl.myResourceDefinition.getName(),
matchUrl.myRequestUrl,
JpaPid.fromId(nextResourcePid));
theTransactionDetails.addResolvedMatchUrl(
myFhirContext, matchUrl.myRequestUrl, JpaPid.fromId(nextResourcePid));
theTransactionDetails, matchUrl.myResourceDefinition.getName(), matchUrl.myRequestUrl, pid);
theTransactionDetails.addResolvedMatchUrl(myFhirContext, matchUrl.myRequestUrl, pid);
matchUrl.setResolved(true);
});
}

View File

@ -38,17 +38,17 @@ import java.util.Optional;
public interface IMdmLinkJpaRepository
extends RevisionRepository<MdmLink, Long, Long>, JpaRepository<MdmLink, Long>, IHapiFhirJpaRepository {
@Modifying
@Query("DELETE FROM MdmLink f WHERE myGoldenResourcePid = :pid OR mySourcePid = :pid")
@Query("DELETE FROM MdmLink f WHERE f.myGoldenResourcePid = :pid OR f.mySourcePid = :pid")
int deleteWithAnyReferenceToPid(@Param("pid") Long thePid);
@Modifying
@Query(
"DELETE FROM MdmLink f WHERE (myGoldenResourcePid = :pid OR mySourcePid = :pid) AND myMatchResult <> :matchResult")
"DELETE FROM MdmLink f WHERE (f.myGoldenResourcePid = :pid OR f.mySourcePid = :pid) AND f.myMatchResult <> :matchResult")
int deleteWithAnyReferenceToPidAndMatchResultNot(
@Param("pid") Long thePid, @Param("matchResult") MdmMatchResultEnum theMatchResult);
@Modifying
@Query("DELETE FROM MdmLink f WHERE myGoldenResourcePid IN (:goldenPids) OR mySourcePid IN (:goldenPids)")
@Query("DELETE FROM MdmLink f WHERE f.myGoldenResourcePid IN (:goldenPids) OR f.mySourcePid IN (:goldenPids)")
void deleteLinksWithAnyReferenceToPids(@Param("goldenPids") List<Long> theResourcePids);
@Modifying
@ -64,7 +64,7 @@ public interface IMdmLinkJpaRepository
"SELECT lookup_links.myGoldenResourcePid as goldenPid, gld_rt.myPartitionIdValue as goldenPartitionId, lookup_links.mySourcePid as sourcePid, lookup_links.myPartitionIdValue as sourcePartitionId "
+ "FROM MdmLink lookup_links "
+ "INNER JOIN ResourceTable gld_rt "
+ "on lookup_links.myGoldenResourcePid=gld_rt.myId "
+ "on lookup_links.myGoldenResource=gld_rt "
+ "WHERE lookup_links.myMatchResult=:matchResult "
+ "AND lookup_links.myGoldenResourcePid IN ("
+ "SELECT inner_mdm_link.myGoldenResourcePid FROM MdmLink inner_mdm_link "
@ -97,7 +97,7 @@ public interface IMdmLinkJpaRepository
+ "INNER JOIN MdmLink gld_link "
+ "on lookup_link.myGoldenResourcePid=gld_link.myGoldenResourcePid "
+ "INNER JOIN ResourceTable gld_rt "
+ "on gld_link.myGoldenResourcePid=gld_rt.myId "
+ "on gld_link.myGoldenResource=gld_rt "
+ "WHERE gld_link.mySourcePid=:sourcePid "
+ "AND gld_link.myMatchResult=:matchResult "
+ "AND lookup_link.myMatchResult=:matchResult")
@ -117,7 +117,7 @@ public interface IMdmLinkJpaRepository
"SELECT lookup_link.myGoldenResourcePid as goldenPid, gld_rt.myPartitionIdValue as goldenPartitionId, lookup_link.mySourcePid as sourcePid, lookup_link.myPartitionIdValue as sourcePartitionId "
+ "FROM MdmLink lookup_link "
+ "INNER JOIN ResourceTable gld_rt "
+ "on lookup_link.myGoldenResourcePid=gld_rt.myId "
+ "on lookup_link.myGoldenResource=gld_rt "
+ "WHERE lookup_link.myGoldenResourcePid = :goldenPid "
+ "AND lookup_link.myMatchResult = :matchResult")
List<MdmPidTuple> expandPidsByGoldenResourcePidAndMatchResult(
@ -127,7 +127,7 @@ public interface IMdmLinkJpaRepository
"SELECT lookup_link.myGoldenResourcePid as goldenPid, gld_rt.myPartitionIdValue as goldenPartitionId, lookup_link.mySourcePid as sourcePid, lookup_link.myPartitionIdValue as sourcePartitionId "
+ "FROM MdmLink lookup_link "
+ "INNER JOIN ResourceTable gld_rt "
+ "on lookup_link.myGoldenResourcePid=gld_rt.myId "
+ "on lookup_link.myGoldenResource=gld_rt "
+ "WHERE "
+ " (lookup_link.myGoldenResourcePid IN (:pids) "
+ " OR"

View File

@ -19,6 +19,7 @@
*/
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryProvenanceEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
@ -26,7 +27,7 @@ import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface IResourceHistoryProvenanceDao
extends JpaRepository<ResourceHistoryProvenanceEntity, Long>, IHapiFhirJpaRepository {
extends JpaRepository<ResourceHistoryProvenanceEntity, IdAndPartitionId>, IHapiFhirJpaRepository {
@Modifying
@Query("DELETE FROM ResourceHistoryProvenanceEntity t WHERE t.myId = :pid")

View File

@ -19,7 +19,10 @@
*/
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.dao.JpaPidFk;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTablePk;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.repository.JpaRepository;
@ -29,54 +32,59 @@ import org.springframework.data.repository.query.Param;
import java.util.List;
public interface IResourceHistoryTableDao extends JpaRepository<ResourceHistoryTable, Long>, IHapiFhirJpaRepository {
public interface IResourceHistoryTableDao
extends JpaRepository<ResourceHistoryTable, ResourceHistoryTablePk>, IHapiFhirJpaRepository {
/**
* This is really only intended for unit tests - There can be many versions of resources in
* the real world, use a pageable query for real uses.
*/
@Query("SELECT t FROM ResourceHistoryTable t WHERE t.myResourceId = :resId ORDER BY t.myResourceVersion ASC")
List<ResourceHistoryTable> findAllVersionsForResourceIdInOrder(@Param("resId") Long theId);
@Query("SELECT t FROM ResourceHistoryTable t WHERE t.myResourcePid = :resId ORDER BY t.myResourceVersion ASC")
List<ResourceHistoryTable> findAllVersionsForResourceIdInOrder(@Param("resId") JpaPidFk theId);
@Query("SELECT t FROM ResourceHistoryTable t WHERE t.myResourceId = :id AND t.myResourceVersion = :version")
ResourceHistoryTable findForIdAndVersion(@Param("id") long theId, @Param("version") long theVersion);
@Query("SELECT t FROM ResourceHistoryTable t WHERE t.myResourcePid = :id AND t.myResourceVersion = :version")
ResourceHistoryTable findForIdAndVersion(@Param("id") JpaPidFk theId, @Param("version") long theVersion);
@Query(
"SELECT t.myId FROM ResourceHistoryTable t WHERE t.myResourceId = :resId AND t.myResourceVersion <> :dontWantVersion")
Slice<Long> findForResourceId(
Pageable thePage, @Param("resId") Long theId, @Param("dontWantVersion") Long theDontWantVersion);
"SELECT t.myId FROM ResourceHistoryTable t WHERE t.myResourcePid = :resId AND t.myResourceVersion <> :dontWantVersion")
Slice<ResourceHistoryTablePk> findForResourceId(
Pageable thePage, @Param("resId") JpaPidFk theId, @Param("dontWantVersion") Long theDontWantVersion);
@Query(
"SELECT t FROM ResourceHistoryTable t WHERE t.myResourceId = :resId AND t.myResourceVersion <> :dontWantVersion")
"SELECT t FROM ResourceHistoryTable t WHERE t.myResourcePid = :resId AND t.myResourceVersion <> :dontWantVersion")
Slice<ResourceHistoryTable> findAllVersionsExceptSpecificForResourcePid(
Pageable thePage, @Param("resId") Long theId, @Param("dontWantVersion") Long theDontWantVersion);
Pageable thePage, @Param("resId") JpaPidFk theId, @Param("dontWantVersion") Long theDontWantVersion);
@Query("" + "SELECT v.myId FROM ResourceHistoryTable v "
+ "LEFT OUTER JOIN ResourceTable t ON (v.myResourceId = t.myId) "
@Query("SELECT v.myId FROM ResourceHistoryTable v "
+ "LEFT OUTER JOIN ResourceTable t ON (v.myResourceTable = t) "
+ "WHERE v.myResourceVersion <> t.myVersion AND "
+ "t.myId = :resId")
Slice<Long> findIdsOfPreviousVersionsOfResourceId(Pageable thePage, @Param("resId") Long theResourceId);
+ "t.myPid = :resId")
Slice<ResourceHistoryTablePk> findIdsOfPreviousVersionsOfResourceId(
Pageable thePage, @Param("resId") JpaPid theResourceId);
@Query("" + "SELECT v.myId FROM ResourceHistoryTable v "
+ "LEFT OUTER JOIN ResourceTable t ON (v.myResourceId = t.myId) "
@Query("SELECT v.myId FROM ResourceHistoryTable v "
+ "LEFT OUTER JOIN ResourceTable t ON (v.myResourceTable = t) "
+ "WHERE v.myResourceVersion <> t.myVersion AND "
+ "t.myResourceType = :restype")
Slice<Long> findIdsOfPreviousVersionsOfResources(Pageable thePage, @Param("restype") String theResourceName);
Slice<ResourceHistoryTablePk> findIdsOfPreviousVersionsOfResources(
Pageable thePage, @Param("restype") String theResourceName);
@Query("" + "SELECT v.myId FROM ResourceHistoryTable v "
+ "LEFT OUTER JOIN ResourceTable t ON (v.myResourceId = t.myId) "
+ "LEFT OUTER JOIN ResourceTable t ON (v.myResourceTable = t) "
+ "WHERE v.myResourceVersion <> t.myVersion")
Slice<Long> findIdsOfPreviousVersionsOfResources(Pageable thePage);
Slice<ResourceHistoryTablePk> findIdsOfPreviousVersionsOfResources(Pageable thePage);
@Modifying
@Query(
"UPDATE ResourceHistoryTable r SET r.myResourceVersion = :newVersion WHERE r.myResourceId = :id AND r.myResourceVersion = :oldVersion")
"UPDATE ResourceHistoryTable r SET r.myResourceVersion = :newVersion WHERE r.myResourcePid = :id AND r.myResourceVersion = :oldVersion")
void updateVersion(
@Param("id") long theId, @Param("oldVersion") long theOldVersion, @Param("newVersion") long theNewVersion);
@Param("id") JpaPidFk theId,
@Param("oldVersion") long theOldVersion,
@Param("newVersion") long theNewVersion);
@Modifying
@Query("DELETE FROM ResourceHistoryTable t WHERE t.myId = :pid")
void deleteByPid(@Param("pid") Long theId);
void deleteByPid(@Param("pid") ResourceHistoryTablePk theId);
/**
* This method is only for use in unit tests - It is used to move the stored resource body contents from the new
@ -88,11 +96,11 @@ public interface IResourceHistoryTableDao extends JpaRepository<ResourceHistoryT
@Modifying
@Query(
"UPDATE ResourceHistoryTable r SET r.myResourceTextVc = null, r.myResource = :text, r.myEncoding = 'JSONC' WHERE r.myId = :pid")
void updateNonInlinedContents(@Param("text") byte[] theText, @Param("pid") long thePid);
void updateNonInlinedContents(@Param("text") byte[] theText, @Param("pid") ResourceHistoryTablePk thePid);
@Query("SELECT v FROM ResourceHistoryTable v " + "JOIN FETCH v.myResourceTable t "
+ "WHERE v.myResourceId IN (:pids) "
+ "WHERE v.myResourcePid IN (:pids) "
+ "AND t.myVersion = v.myResourceVersion")
List<ResourceHistoryTable> findCurrentVersionsByResourcePidsAndFetchResourceTable(
@Param("pids") List<Long> theVersionlessPids);
@Param("pids") List<JpaPidFk> theVersionlessPids);
}

View File

@ -19,6 +19,7 @@
*/
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTablePk;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTag;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
@ -30,10 +31,10 @@ import java.util.Collection;
public interface IResourceHistoryTagDao extends JpaRepository<ResourceHistoryTag, Long>, IHapiFhirJpaRepository {
@Modifying
@Query("DELETE FROM ResourceHistoryTag t WHERE t.myResourceHistoryPid = :historyPid")
void deleteByPid(@Param("historyPid") Long theResourceHistoryTablePid);
@Query("DELETE FROM ResourceHistoryTag t WHERE t.myResourceHistory.myId = :historyPid")
void deleteByPid(@Param("historyPid") ResourceHistoryTablePk theResourceHistoryTablePid);
@Query(
"SELECT t FROM ResourceHistoryTag t INNER JOIN FETCH t.myTag WHERE t.myResourceHistory.myId IN (:historyPids)")
Collection<ResourceHistoryTag> findByVersionIds(@Param("historyPids") Collection<Long> theIdList);
Collection<ResourceHistoryTag> findByVersionIds(@Param("historyPids") Collection<ResourceHistoryTablePk> theIdList);
}

View File

@ -19,6 +19,7 @@
*/
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboStringUnique;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
@ -32,10 +33,10 @@ public interface IResourceIndexedComboStringUniqueDao extends JpaRepository<Reso
@Query("SELECT r FROM ResourceIndexedComboStringUnique r WHERE r.myIndexString = :str")
ResourceIndexedComboStringUnique findByQueryString(@Param("str") String theQueryString);
@Query("SELECT r FROM ResourceIndexedComboStringUnique r WHERE r.myResourceId = :resId")
List<ResourceIndexedComboStringUnique> findAllForResourceIdForUnitTest(@Param("resId") Long theResourceId);
@Query("SELECT r FROM ResourceIndexedComboStringUnique r WHERE r.myResource.myPid = :resId")
List<ResourceIndexedComboStringUnique> findAllForResourceIdForUnitTest(@Param("resId") JpaPid theResourceId);
@Modifying
@Query("delete from ResourceIndexedComboStringUnique t WHERE t.myResourceId = :resid")
void deleteByResourceId(@Param("resid") Long theResourcePid);
@Query("delete from ResourceIndexedComboStringUnique t WHERE t.myResource.myPid = :resid")
void deleteByResourceId(@Param("resid") JpaPid theResourcePid);
}

View File

@ -19,6 +19,7 @@
*/
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboTokenNonUnique;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
@ -29,6 +30,6 @@ public interface IResourceIndexedComboTokensNonUniqueDao
extends JpaRepository<ResourceIndexedComboTokenNonUnique, Long> {
@Modifying
@Query("DELETE FROM ResourceIndexedComboTokenNonUnique t WHERE t.myResourceId = :res_id")
void deleteByResourceId(@Param("res_id") Long theResourcePid);
@Query("DELETE FROM ResourceIndexedComboTokenNonUnique t WHERE t.myResource.myPid = :res_id")
void deleteByResourceId(@Param("res_id") JpaPid theResourcePid);
}

View File

@ -19,6 +19,7 @@
*/
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
@ -28,6 +29,6 @@ import org.springframework.data.repository.query.Param;
public interface IResourceIndexedSearchParamCoordsDao
extends JpaRepository<ResourceIndexedSearchParamCoords, Long>, IHapiFhirJpaRepository {
@Modifying
@Query("delete from ResourceIndexedSearchParamCoords t WHERE t.myResourcePid = :resid")
void deleteByResourceId(@Param("resid") Long theResourcePid);
@Query("delete from ResourceIndexedSearchParamCoords t WHERE t.myResource.myPid = :resid")
void deleteByResourceId(@Param("resid") JpaPid theResourcePid);
}

View File

@ -19,6 +19,7 @@
*/
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
@ -30,9 +31,9 @@ import java.util.List;
public interface IResourceIndexedSearchParamDateDao
extends JpaRepository<ResourceIndexedSearchParamDate, Long>, IHapiFhirJpaRepository {
@Modifying
@Query("delete from ResourceIndexedSearchParamDate t WHERE t.myResourcePid = :resid")
void deleteByResourceId(@Param("resid") Long theResourcePid);
@Query("delete from ResourceIndexedSearchParamDate t WHERE t.myResource.myPid = :resid")
void deleteByResourceId(@Param("resid") JpaPid theResourcePid);
@Query("SELECT t FROM ResourceIndexedSearchParamDate t WHERE t.myResourcePid = :resId")
List<ResourceIndexedSearchParamDate> findAllForResourceId(@Param("resId") Long thePatientId);
@Query("SELECT t FROM ResourceIndexedSearchParamDate t WHERE t.myResource.myPid = :resId")
List<ResourceIndexedSearchParamDate> findAllForResourceId(@Param("resId") JpaPid thePatientId);
}

View File

@ -19,6 +19,7 @@
*/
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
@ -28,6 +29,6 @@ import org.springframework.data.repository.query.Param;
public interface IResourceIndexedSearchParamNumberDao
extends JpaRepository<ResourceIndexedSearchParamNumber, Long>, IHapiFhirJpaRepository {
@Modifying
@Query("delete from ResourceIndexedSearchParamNumber t WHERE t.myResourcePid = :resid")
void deleteByResourceId(@Param("resid") Long theResourcePid);
@Query("delete from ResourceIndexedSearchParamNumber t WHERE t.myResource.myPid = :resid")
void deleteByResourceId(@Param("resid") JpaPid theResourcePid);
}

View File

@ -19,6 +19,7 @@
*/
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
@ -28,6 +29,6 @@ import org.springframework.data.repository.query.Param;
public interface IResourceIndexedSearchParamQuantityDao
extends JpaRepository<ResourceIndexedSearchParamQuantity, Long>, IHapiFhirJpaRepository {
@Modifying
@Query("delete from ResourceIndexedSearchParamQuantity t WHERE t.myResourcePid = :resid")
void deleteByResourceId(@Param("resid") Long theResourcePid);
@Query("delete from ResourceIndexedSearchParamQuantity t WHERE t.myResource.myPid = :resid")
void deleteByResourceId(@Param("resid") JpaPid theResourcePid);
}

View File

@ -19,6 +19,7 @@
*/
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantityNormalized;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
@ -28,6 +29,6 @@ import org.springframework.data.repository.query.Param;
public interface IResourceIndexedSearchParamQuantityNormalizedDao
extends JpaRepository<ResourceIndexedSearchParamQuantityNormalized, Long>, IHapiFhirJpaRepository {
@Modifying
@Query("delete from ResourceIndexedSearchParamQuantityNormalized t WHERE t.myResourcePid = :resid")
void deleteByResourceId(@Param("resid") Long theResourcePid);
@Query("delete from ResourceIndexedSearchParamQuantityNormalized t WHERE t.myResource.myPid = :resid")
void deleteByResourceId(@Param("resid") JpaPid theResourcePid);
}

View File

@ -19,6 +19,7 @@
*/
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
@ -31,9 +32,9 @@ public interface IResourceIndexedSearchParamStringDao
extends JpaRepository<ResourceIndexedSearchParamString, Long>, IHapiFhirJpaRepository {
@Modifying
@Query("DELETE FROM ResourceIndexedSearchParamString t WHERE t.myResourcePid = :resId")
void deleteByResourceId(@Param("resId") Long theResourcePid);
@Query("DELETE FROM ResourceIndexedSearchParamString t WHERE t.myResource.myPid = :resId")
void deleteByResourceId(@Param("resId") JpaPid theResourcePid);
@Query("SELECT t FROM ResourceIndexedSearchParamString t WHERE t.myResourcePid = :resId")
List<ResourceIndexedSearchParamString> findAllForResourceId(@Param("resId") Long thePatientId);
@Query("SELECT t FROM ResourceIndexedSearchParamString t WHERE t.myResource.myPid = :resId")
List<ResourceIndexedSearchParamString> findAllForResourceId(@Param("resId") JpaPid thePatientId);
}

View File

@ -19,6 +19,7 @@
*/
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
@ -28,10 +29,10 @@ import org.springframework.data.repository.query.Param;
public interface IResourceIndexedSearchParamTokenDao
extends JpaRepository<ResourceIndexedSearchParamToken, Long>, IHapiFhirJpaRepository {
@Query("select count(*) from ResourceIndexedSearchParamToken t WHERE t.myResourcePid = :resid")
int countForResourceId(@Param("resid") Long theResourcePid);
@Query("select count(*) from ResourceIndexedSearchParamToken t WHERE t.myResource.myPid = :resid")
int countForResourceId(@Param("resid") JpaPid theResourcePid);
@Modifying
@Query("delete from ResourceIndexedSearchParamToken t WHERE t.myResourcePid = :resid")
void deleteByResourceId(@Param("resid") Long theResourcePid);
@Query("delete from ResourceIndexedSearchParamToken t WHERE t.myResource.myPid = :resid")
void deleteByResourceId(@Param("resid") JpaPid theResourcePid);
}

View File

@ -19,6 +19,7 @@
*/
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
@ -31,9 +32,9 @@ public interface IResourceIndexedSearchParamUriDao
extends JpaRepository<ResourceIndexedSearchParamUri, Long>, IHapiFhirJpaRepository {
@Query("SELECT DISTINCT p.myUri FROM ResourceIndexedSearchParamUri p WHERE p.myHashIdentity = :hash_identity")
public Collection<String> findAllByHashIdentity(@Param("hash_identity") long theHashIdentity);
Collection<String> findAllByHashIdentity(@Param("hash_identity") long theHashIdentity);
@Modifying
@Query("delete from ResourceIndexedSearchParamUri t WHERE t.myResourcePid = :resid")
void deleteByResourceId(@Param("resid") Long theResourcePid);
@Query("delete from ResourceIndexedSearchParamUri t WHERE t.myResource.myPid = :resid")
void deleteByResourceId(@Param("resid") JpaPid theResourcePid);
}

View File

@ -19,6 +19,7 @@
*/
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
@ -30,14 +31,14 @@ import java.util.List;
public interface IResourceLinkDao extends JpaRepository<ResourceLink, Long>, IHapiFhirJpaRepository {
@Modifying
@Query("DELETE FROM ResourceLink t WHERE t.mySourceResourcePid = :resId")
void deleteByResourceId(@Param("resId") Long theResourcePid);
@Query("DELETE FROM ResourceLink t WHERE t.mySourceResource.myPid = :resId")
void deleteByResourceId(@Param("resId") JpaPid theResourcePid);
@Query("SELECT t FROM ResourceLink t WHERE t.mySourceResourcePid = :resId")
List<ResourceLink> findAllForSourceResourceId(@Param("resId") Long thePatientId);
@Query("SELECT t FROM ResourceLink t WHERE t.mySourceResource.myPid = :resId")
List<ResourceLink> findAllForSourceResourceId(@Param("resId") JpaPid thePatientId);
@Query("SELECT t FROM ResourceLink t WHERE t.myTargetResourcePid in :resIds")
List<ResourceLink> findWithTargetPidIn(@Param("resIds") List<Long> thePids);
@Query("SELECT t FROM ResourceLink t WHERE t.myTargetResource.myPid in :resIds")
List<ResourceLink> findWithTargetPidIn(@Param("resIds") List<JpaPid> thePids);
/**
* Loads a collection of ResourceLink entities by PID, but also eagerly fetches

View File

@ -20,6 +20,7 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.dao.data.custom.IForcedIdQueries;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.EntityIndexStatusEnum;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import org.springframework.data.domain.Pageable;
@ -40,17 +41,17 @@ import java.util.stream.Stream;
@Transactional(propagation = Propagation.MANDATORY)
public interface IResourceTableDao
extends JpaRepository<ResourceTable, Long>, IHapiFhirJpaRepository, IForcedIdQueries {
extends JpaRepository<ResourceTable, JpaPid>, IHapiFhirJpaRepository, IForcedIdQueries {
@Query("SELECT t.myId FROM ResourceTable t WHERE t.myDeleted IS NOT NULL")
Slice<Long> findIdsOfDeletedResources(Pageable thePageable);
@Query("SELECT t.myPid FROM ResourceTable t WHERE t.myDeleted IS NOT NULL")
Slice<JpaPid> findIdsOfDeletedResources(Pageable thePageable);
@Query("SELECT t.myId FROM ResourceTable t WHERE t.myResourceType = :restype AND t.myDeleted IS NOT NULL")
Slice<Long> findIdsOfDeletedResourcesOfType(Pageable thePageable, @Param("restype") String theResourceName);
@Query("SELECT t.myPid FROM ResourceTable t WHERE t.myResourceType = :restype AND t.myDeleted IS NOT NULL")
Slice<JpaPid> findIdsOfDeletedResourcesOfType(Pageable thePageable, @Param("restype") String theResourceName);
@Query(
"SELECT t.myId FROM ResourceTable t WHERE t.myId = :resid AND t.myResourceType = :restype AND t.myDeleted IS NOT NULL")
Slice<Long> findIdsOfDeletedResourcesOfType(
"SELECT t.myPid FROM ResourceTable t WHERE t.myPid.myId = :resid AND t.myResourceType = :restype AND t.myDeleted IS NOT NULL")
Slice<JpaPid> findIdsOfDeletedResourcesOfType(
Pageable thePageable, @Param("resid") Long theResourceId, @Param("restype") String theResourceName);
@Query(
@ -58,94 +59,70 @@ public interface IResourceTableDao
List<Map<?, ?>> getResourceCounts();
@Query(
"SELECT t.myId FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high ORDER BY t.myUpdated DESC")
Slice<Long> findIdsOfResourcesWithinUpdatedRangeOrderedFromNewest(
"SELECT t.myPid FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high ORDER BY t.myUpdated DESC")
Slice<JpaPid> findIdsOfResourcesWithinUpdatedRangeOrderedFromNewest(
Pageable thePage, @Param("low") Date theLow, @Param("high") Date theHigh);
@Query(
"SELECT t.myId FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high ORDER BY t.myUpdated ASC")
Slice<Long> findIdsOfResourcesWithinUpdatedRangeOrderedFromOldest(
"SELECT t.myPid FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high ORDER BY t.myUpdated ASC")
Slice<JpaPid> findIdsOfResourcesWithinUpdatedRangeOrderedFromOldest(
Pageable thePage, @Param("low") Date theLow, @Param("high") Date theHigh);
@Query(
"SELECT t.myId, t.myResourceType, t.myUpdated FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high ORDER BY t.myUpdated ASC")
"SELECT t.myPid, t.myResourceType, t.myUpdated FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high ORDER BY t.myUpdated ASC")
Stream<Object[]> streamIdsTypesAndUpdateTimesOfResourcesWithinUpdatedRangeOrderedFromOldest(
@Param("low") Date theLow, @Param("high") Date theHigh);
/**
* @return List of arrays containing [PID, resourceType, lastUpdated]
*/
@Query(
"SELECT t.myId, t.myResourceType, t.myUpdated FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high AND t.myPartitionIdValue IN (:partition_ids) ORDER BY t.myUpdated ASC")
Slice<Object[]> findIdsTypesAndUpdateTimesOfResourcesWithinUpdatedRangeOrderedFromOldestForPartitionIds(
Pageable thePage,
@Param("low") Date theLow,
@Param("high") Date theHigh,
@Param("partition_ids") List<Integer> theRequestPartitionIds);
@Query(
"SELECT t.myId, t.myResourceType, t.myUpdated FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high AND t.myPartitionIdValue IN (:partition_ids) ORDER BY t.myUpdated ASC")
"SELECT t.myPid, t.myResourceType, t.myUpdated FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high AND t.myPartitionIdValue IN (:partition_ids) ORDER BY t.myUpdated ASC")
Stream<Object[]> streamIdsTypesAndUpdateTimesOfResourcesWithinUpdatedRangeOrderedFromOldestForPartitionIds(
@Param("low") Date theLow,
@Param("high") Date theHigh,
@Param("partition_ids") List<Integer> theRequestPartitionIds);
/**
* @return List of arrays containing [PID, resourceType, lastUpdated]
*/
@Query(
"SELECT t.myId, t.myResourceType, t.myUpdated FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high ORDER BY t.myUpdated ASC")
Slice<Object[]> findIdsTypesAndUpdateTimesOfResourcesWithinUpdatedRangeOrderedFromOldestForDefaultPartition(
Pageable thePage, @Param("low") Date theLow, @Param("high") Date theHigh);
@Query(
"SELECT t.myId, t.myResourceType, t.myUpdated FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high ORDER BY t.myUpdated ASC")
"SELECT t.myPid, t.myResourceType, t.myUpdated FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high ORDER BY t.myUpdated ASC")
Stream<Object[]> streamIdsTypesAndUpdateTimesOfResourcesWithinUpdatedRangeOrderedFromOldestForDefaultPartition(
@Param("low") Date theLow, @Param("high") Date theHigh);
// TODO in the future, consider sorting by pid as well so batch jobs process in the same order across restarts
@Query(
"SELECT t.myId FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high AND t.myPartitionIdValue = :partition_id ORDER BY t.myUpdated ASC")
Slice<Long> findIdsOfPartitionedResourcesWithinUpdatedRangeOrderedFromOldest(
Pageable thePage,
@Param("low") Date theLow,
@Param("high") Date theHigh,
@Param("partition_id") Integer theRequestPartitionId);
@Query(
"SELECT t.myId FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high AND t.myResourceType = :restype ORDER BY t.myUpdated ASC")
Slice<Long> findIdsOfResourcesWithinUpdatedRangeOrderedFromOldest(
"SELECT t.myPid FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high AND t.myResourceType = :restype ORDER BY t.myUpdated ASC")
Slice<JpaPid> findIdsOfResourcesWithinUpdatedRangeOrderedFromOldest(
Pageable thePage,
@Param("restype") String theResourceType,
@Param("low") Date theLow,
@Param("high") Date theHigh);
@Modifying
@Query("UPDATE ResourceTable t SET t.myIndexStatus = :status WHERE t.myId = :id")
void updateIndexStatus(@Param("id") Long theId, @Param("status") EntityIndexStatusEnum theIndexStatus);
@Query("UPDATE ResourceTable t SET t.myIndexStatus = :status WHERE t.myPid = :id")
void updateIndexStatus(@Param("id") JpaPid theId, @Param("status") EntityIndexStatusEnum theIndexStatus);
@Modifying
@Query("UPDATE ResourceTable t SET t.myUpdated = :updated WHERE t.myId = :id")
void updateLastUpdated(@Param("id") Long theId, @Param("updated") Date theUpdated);
@Query("UPDATE ResourceTable t SET t.myUpdated = :updated WHERE t.myPid = :id")
void updateLastUpdated(@Param("id") JpaPid theId, @Param("updated") Date theUpdated);
@Modifying
@Query("DELETE FROM ResourceTable t WHERE t.myId = :pid")
void deleteByPid(@Param("pid") Long theId);
@Query("DELETE FROM ResourceTable t WHERE t.myPid = :pid")
void deleteByPid(@Param("pid") JpaPid theId);
/**
* This method returns a Collection where each row is an element in the collection. Each element in the collection
* is an object array, where the order matters (the array represents columns returned by the query). Be careful if you change this query in any way.
*/
@Query(
"SELECT t.myResourceType, t.myId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue FROM ResourceTable t WHERE t.myId IN (:pid)")
"SELECT t.myResourceType, t.myPid.myId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue FROM ResourceTable t WHERE t.myPid.myId IN (:pid)")
Collection<Object[]> findLookupFieldsByResourcePid(@Param("pid") List<Long> thePids);
@Query(
"SELECT t.myResourceType, t.myPid.myId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue FROM ResourceTable t WHERE t.myPid IN (:pid)")
Collection<Object[]> findLookupFieldsByResourcePidWithPartitionId(@Param("pid") List<JpaPid> thePids);
/**
* This method returns a Collection where each row is an element in the collection. Each element in the collection
* is an object array, where the order matters (the array represents columns returned by the query). Be careful if you change this query in any way.
*/
@Query(
"SELECT t.myResourceType, t.myId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue FROM ResourceTable t WHERE t.myId IN (:pid) AND t.myPartitionIdValue IN :partition_id")
"SELECT t.myResourceType, t.myPid.myId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue FROM ResourceTable t WHERE t.myPid.myId IN (:pid) AND t.myPartitionIdValue IN :partition_id")
Collection<Object[]> findLookupFieldsByResourcePidInPartitionIds(
@Param("pid") List<Long> thePids, @Param("partition_id") Collection<Integer> thePartitionId);
@ -154,7 +131,7 @@ public interface IResourceTableDao
* is an object array, where the order matters (the array represents columns returned by the query). Be careful if you change this query in any way.
*/
@Query(
"SELECT t.myResourceType, t.myId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue FROM ResourceTable t WHERE t.myId IN (:pid) AND (t.myPartitionIdValue IS NULL OR t.myPartitionIdValue IN :partition_id)")
"SELECT t.myResourceType, t.myPid.myId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue FROM ResourceTable t WHERE t.myPid.myId IN (:pid) AND (t.myPartitionIdValue IS NULL OR t.myPartitionIdValue IN :partition_id)")
Collection<Object[]> findLookupFieldsByResourcePidInPartitionIdsOrNullPartition(
@Param("pid") List<Long> thePids, @Param("partition_id") Collection<Integer> thePartitionId);
@ -163,42 +140,49 @@ public interface IResourceTableDao
* is an object array, where the order matters (the array represents columns returned by the query). Be careful if you change this query in any way.
*/
@Query(
"SELECT t.myResourceType, t.myId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue FROM ResourceTable t WHERE t.myId IN (:pid) AND t.myPartitionIdValue IS NULL")
"SELECT t.myResourceType, t.myPid.myId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue FROM ResourceTable t WHERE t.myPid.myId IN (:pid) AND t.myPartitionIdValue IS NULL")
Collection<Object[]> findLookupFieldsByResourcePidInPartitionNull(@Param("pid") List<Long> thePids);
@Query("SELECT t.myVersion FROM ResourceTable t WHERE t.myId = :pid")
Long findCurrentVersionByPid(@Param("pid") Long thePid);
@Query("SELECT t.myVersion FROM ResourceTable t WHERE t.myPid = :pid")
Long findCurrentVersionByPid(@Param("pid") JpaPid thePid);
/**
* This query will return rows with the following values:
* Id (resource pid - long), ResourceType (Patient, etc), version (long)
* Id (JpaPid), FhirId, ResourceType (Patient, etc), version (long)
* Order matters!
*
* @param pid - list of pids to get versions for
* @return
*/
@Query("SELECT t.myId, t.myResourceType, t.myVersion FROM ResourceTable t WHERE t.myId IN ( :pid )")
Collection<Object[]> getResourceVersionsForPid(@Param("pid") List<Long> pid);
@Query("SELECT t.myPid, t.myResourceType, t.myFhirId, t.myVersion FROM ResourceTable t WHERE t.myPid IN ( :pid )")
Collection<Object[]> getResourceVersionsForPid(@Param("pid") Collection<JpaPid> pid);
@Query("SELECT t FROM ResourceTable t WHERE t.myPartitionId.myPartitionId IS NULL AND t.myId = :pid")
@Query("SELECT t FROM ResourceTable t WHERE t.myPartitionIdValue IS NULL AND t.myPid.myId = :pid")
Optional<ResourceTable> readByPartitionIdNull(@Param("pid") Long theResourceId);
@Query("SELECT t FROM ResourceTable t WHERE t.myPartitionId.myPartitionId = :partitionId AND t.myId = :pid")
@Query("SELECT t FROM ResourceTable t WHERE t.myPartitionIdValue = :partitionId AND t.myPid.myId = :pid")
Optional<ResourceTable> readByPartitionId(
@Param("partitionId") int thePartitionId, @Param("pid") Long theResourceId);
@Query(
"SELECT t FROM ResourceTable t WHERE (t.myPartitionId.myPartitionId IS NULL OR t.myPartitionId.myPartitionId IN (:partitionIds)) AND t.myId = :pid")
"SELECT t FROM ResourceTable t WHERE (t.myPartitionIdValue IS NULL OR t.myPartitionIdValue IN (:partitionIds)) AND t.myPid.myId = :pid")
Optional<ResourceTable> readByPartitionIdsOrNull(
@Param("partitionIds") Collection<Integer> thrValues, @Param("pid") Long theResourceId);
@Query("SELECT t FROM ResourceTable t WHERE t.myPartitionId.myPartitionId IN (:partitionIds) AND t.myId = :pid")
@Query("SELECT t FROM ResourceTable t WHERE t.myPartitionIdValue IN (:partitionIds) AND t.myPid.myId = :pid")
Optional<ResourceTable> readByPartitionIds(
@Param("partitionIds") Collection<Integer> thrValues, @Param("pid") Long theResourceId);
@Query("SELECT t FROM ResourceTable t WHERE t.myId IN :pids")
List<ResourceTable> findAllByIdAndLoadForcedIds(@Param("pids") List<Long> thePids);
@Query("SELECT t FROM ResourceTable t WHERE t.myPid IN :pids")
List<ResourceTable> findAllByIdAndLoadForcedIds(@Param("pids") List<JpaPid> thePids);
@Query("SELECT t FROM ResourceTable t where t.myResourceType = :restype and t.myFhirId = :fhirId")
Optional<ResourceTable> findByTypeAndFhirId(
@Param("restype") String theResourceName, @Param("fhirId") String theFhirId);
/**
* @deprecated Use {@link #findById(Object)}
*/
default Optional<ResourceTable> findById(Long theId) {
return findById(JpaPid.fromId(theId));
}
}

View File

@ -19,6 +19,7 @@
*/
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ResourceTag;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
@ -28,10 +29,10 @@ import org.springframework.data.repository.query.Param;
import java.util.Collection;
public interface IResourceTagDao extends JpaRepository<ResourceTag, Long>, IHapiFhirJpaRepository {
@Query("" + "SELECT t FROM ResourceTag t " + "INNER JOIN FETCH t.myTag td " + "WHERE t.myResourceId in (:pids)")
Collection<ResourceTag> findByResourceIds(@Param("pids") Collection<Long> pids);
@Query("SELECT t FROM ResourceTag t INNER JOIN FETCH t.myTag td WHERE t.myResource.myPid in (:pids)")
Collection<ResourceTag> findByResourceIds(@Param("pids") Collection<JpaPid> pids);
@Modifying
@Query("delete from ResourceTag t WHERE t.myResourceId = :resId")
void deleteByResourceId(@Param("resId") Long theResourcePid);
@Query("delete from ResourceTag t WHERE t.myResource.myPid = :resId")
void deleteByResourceId(@Param("resId") JpaPid theResourcePid);
}

View File

@ -19,6 +19,7 @@
*/
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.model.entity.SearchParamPresentEntity;
import org.springframework.data.jpa.repository.JpaRepository;
@ -34,6 +35,6 @@ public interface ISearchParamPresentDao extends JpaRepository<SearchParamPresent
List<SearchParamPresentEntity> findAllForResource(@Param("res") ResourceTable theResource);
@Modifying
@Query("delete from SearchParamPresentEntity t WHERE t.myResourcePid = :resid")
void deleteByResourceId(@Param("resid") Long theResourcePid);
@Query("delete from SearchParamPresentEntity t WHERE t.myResource.myPid = :resid")
void deleteByResourceId(@Param("resid") JpaPid theResourcePid);
}

View File

@ -35,11 +35,13 @@ import java.util.List;
public interface ISearchResultDao extends JpaRepository<SearchResult, Long>, IHapiFhirJpaRepository {
@Query(value = "SELECT r.myResourcePid FROM SearchResult r WHERE r.mySearchPid = :search ORDER BY r.myOrder ASC")
Slice<Long> findWithSearchPid(@Param("search") Long theSearchPid, Pageable thePage);
@Query(
value =
"SELECT r.myResourcePartitionId,r.myResourcePid FROM SearchResult r WHERE r.mySearchPid = :search ORDER BY r.myOrder ASC")
Slice<Object[]> findWithSearchPid(@Param("search") Long theSearchPid, Pageable thePage);
@Query(value = "SELECT r.myResourcePid FROM SearchResult r WHERE r.mySearchPid = :search")
List<Long> findWithSearchPidOrderIndependent(@Param("search") Long theSearchPid);
@Query(value = "SELECT r.myResourcePartitionId,r.myResourcePid FROM SearchResult r WHERE r.mySearchPid = :search")
List<Object[]> findWithSearchPidOrderIndependent(@Param("search") Long theSearchPid);
@Modifying
@Query("DELETE FROM SearchResult s WHERE s.mySearchPid IN :searchIds")
@ -62,10 +64,12 @@ public interface ISearchResultDao extends JpaRepository<SearchResult, Long>, IHa
* Converts a response from {@link #findWithSearchPid(Long, Pageable)} to
* a List of JpaPid objects
*/
static List<JpaPid> toJpaPidList(List<Long> theArrays) {
static List<JpaPid> toJpaPidList(List<Object[]> theArrays) {
List<JpaPid> retVal = new ArrayList<>(theArrays.size());
for (Long next : theArrays) {
retVal.add(JpaPid.fromId(next));
for (Object[] next : theArrays) {
Integer partitionId = (Integer) next[0];
Long resourcePid = (Long) next[1];
retVal.add(JpaPid.fromId(resourcePid, partitionId));
}
return retVal;
}

View File

@ -20,17 +20,20 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface ISubscriptionTableDao extends JpaRepository<SubscriptionTable, Long>, IHapiFhirJpaRepository {
// TODO: We deprecated this entity in 8.0.0 and stopped writing it - Eventually delete it
@Deprecated
public interface ISubscriptionTableDao
extends JpaRepository<SubscriptionTable, IdAndPartitionId>, IHapiFhirJpaRepository {
@Modifying
@Query("DELETE FROM SubscriptionTable t WHERE t.mySubscriptionResource = :subscription ")
void deleteAllForSubscription(@Param("subscription") ResourceTable theSubscription);
@Query("DELETE FROM SubscriptionTable t WHERE t.myResId = :res_id ")
void deleteAllForSubscription(@Param("res_id") Long theSubscriptionResourceId);
@Query("SELECT t FROM SubscriptionTable t WHERE t.myResId = :pid")
SubscriptionTable findOneByResourcePid(@Param("pid") Long theId);

View File

@ -20,20 +20,29 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.Optional;
public interface ITermCodeSystemDao extends JpaRepository<TermCodeSystem, Long>, IHapiFhirJpaRepository {
public interface ITermCodeSystemDao extends JpaRepository<TermCodeSystem, IdAndPartitionId>, IHapiFhirJpaRepository {
@Query("SELECT cs FROM TermCodeSystem cs WHERE cs.myCodeSystemUri = :code_system_uri")
TermCodeSystem findByCodeSystemUri(@Param("code_system_uri") String theCodeSystemUri);
@Query("SELECT cs FROM TermCodeSystem cs WHERE cs.myResourcePid = :resource_pid")
TermCodeSystem findByResourcePid(@Param("resource_pid") Long theResourcePid);
@Query("SELECT cs FROM TermCodeSystem cs WHERE cs.myResource.myPid = :resource_pid")
TermCodeSystem findByResourcePid(@Param("resource_pid") JpaPid theResourcePid);
@Query("SELECT cs FROM TermCodeSystem cs WHERE cs.myCurrentVersion.myId = :csv_pid")
Optional<TermCodeSystem> findWithCodeSystemVersionAsCurrentVersion(@Param("csv_pid") Long theCodeSystemVersionPid);
/**
* // TODO: JA2 Use partitioned query here
*/
@Deprecated
@Query("SELECT cs FROM TermCodeSystem cs WHERE cs.myId = :pid")
Optional<TermCodeSystem> findByPid(@Param("pid") long thePid);
}

View File

@ -21,21 +21,29 @@ package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
import java.util.Optional;
public interface ITermCodeSystemVersionDao extends JpaRepository<TermCodeSystemVersion, Long>, IHapiFhirJpaRepository {
public interface ITermCodeSystemVersionDao
extends JpaRepository<TermCodeSystemVersion, IdAndPartitionId>, IHapiFhirJpaRepository {
@Modifying
@Query("DELETE FROM TermCodeSystemVersion csv WHERE csv.myCodeSystem = :cs")
void deleteForCodeSystem(@Param("cs") TermCodeSystem theCodeSystem);
@Query("SELECT myId FROM TermCodeSystemVersion WHERE myCodeSystemPid = :codesystem_pid order by myId")
List<Long> findSortedPidsByCodeSystemPid(@Param("codesystem_pid") Long theCodeSystemPid);
/**
* @return Return type is [PartitionId,Pid]
*/
@Query(
"SELECT t.myPartitionIdValue, t.myId FROM TermCodeSystemVersion t WHERE t.myCodeSystemPid = :codesystem_pid order by t.myId")
List<Object[]> findSortedPidsByCodeSystemPid(@Param("codesystem_pid") Long theCodeSystemPid);
@Query(
"SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myCodeSystemPid = :codesystem_pid AND cs.myCodeSystemVersionId = :codesystem_version_id")
@ -43,9 +51,8 @@ public interface ITermCodeSystemVersionDao extends JpaRepository<TermCodeSystemV
@Param("codesystem_pid") Long theCodeSystemPid,
@Param("codesystem_version_id") String theCodeSystemVersionId);
@Query(
"SELECT tcsv FROM TermCodeSystemVersion tcsv INNER JOIN FETCH TermCodeSystem tcs on tcs.myPid = tcsv.myCodeSystemPid "
+ "WHERE tcs.myCodeSystemUri = :code_system_uri AND tcsv.myCodeSystemVersionId = :codesystem_version_id")
@Query("SELECT tcsv FROM TermCodeSystemVersion tcsv INNER JOIN FETCH TermCodeSystem tcs on tcs = tcsv.myCodeSystem "
+ "WHERE tcs.myCodeSystemUri = :code_system_uri AND tcsv.myCodeSystemVersionId = :codesystem_version_id")
TermCodeSystemVersion findByCodeSystemUriAndVersion(
@Param("code_system_uri") String theCodeSystemUri,
@Param("codesystem_version_id") String theCodeSystemVersionId);
@ -54,11 +61,18 @@ public interface ITermCodeSystemVersionDao extends JpaRepository<TermCodeSystemV
"SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myCodeSystemPid = :codesystem_pid AND cs.myCodeSystemVersionId IS NULL")
TermCodeSystemVersion findByCodeSystemPidVersionIsNull(@Param("codesystem_pid") Long theCodeSystemPid);
@Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myResourcePid = :resource_id")
List<TermCodeSystemVersion> findByCodeSystemResourcePid(@Param("resource_id") Long theCodeSystemResourcePid);
@Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myResource.myPid = :resource_id")
List<TermCodeSystemVersion> findByCodeSystemResourcePid(@Param("resource_id") JpaPid theCodeSystemResourcePid);
@Query(
"SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myCodeSystemHavingThisVersionAsCurrentVersionIfAny.myResource.myId = :resource_id")
@Query("SELECT csv FROM TermCodeSystemVersion csv " + "JOIN TermCodeSystem cs ON (cs.myCurrentVersion = csv) "
+ "WHERE cs.myResource.myPid.myId = :resource_id")
TermCodeSystemVersion findCurrentVersionForCodeSystemResourcePid(
@Param("resource_id") Long theCodeSystemResourcePid);
/**
* // TODO: JA2 Use partitioned query here
*/
@Deprecated
@Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myId = :pid")
Optional<TermCodeSystemVersion> findByPid(@Param("pid") long theVersionPid);
}

View File

@ -31,10 +31,10 @@ import org.springframework.data.repository.query.Param;
import java.util.List;
import java.util.Optional;
public interface ITermConceptDao extends JpaRepository<TermConcept, Long>, IHapiFhirJpaRepository {
public interface ITermConceptDao extends JpaRepository<TermConcept, TermConcept.TermConceptPk>, IHapiFhirJpaRepository {
@Query("SELECT t FROM TermConcept t " + "LEFT JOIN FETCH t.myDesignations d " + "WHERE t.myId IN :pids")
List<TermConcept> fetchConceptsAndDesignationsByPid(@Param("pids") List<Long> thePids);
List<TermConcept> fetchConceptsAndDesignationsByPid(@Param("pids") List<TermConcept.TermConceptPk> thePids);
@Query("SELECT t FROM TermConcept t " + "LEFT JOIN FETCH t.myDesignations d "
+ "WHERE t.myCodeSystemVersionPid = :pid")

View File

@ -20,13 +20,14 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.TermConceptDesignation;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface ITermConceptDesignationDao
extends JpaRepository<TermConceptDesignation, Long>, IHapiFhirJpaRepository {
extends JpaRepository<TermConceptDesignation, IdAndPartitionId>, IHapiFhirJpaRepository {
@Modifying
@Query("DELETE FROM TermConceptDesignation WHERE myCodeSystemVersion.myId = :csv_pid")

View File

@ -20,6 +20,7 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.TermConceptMap;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
@ -29,7 +30,7 @@ import org.springframework.data.repository.query.Param;
import java.util.List;
import java.util.Optional;
public interface ITermConceptMapDao extends JpaRepository<TermConceptMap, Long>, IHapiFhirJpaRepository {
public interface ITermConceptMapDao extends JpaRepository<TermConceptMap, IdAndPartitionId>, IHapiFhirJpaRepository {
@Query("DELETE FROM TermConceptMap cm WHERE cm.myId = :pid")
@Modifying
void deleteTermConceptMapById(@Param("pid") Long theId);
@ -48,7 +49,7 @@ public interface ITermConceptMapDao extends JpaRepository<TermConceptMap, Long>,
// Note that last updated version is considered current version.
@Query(
value =
"SELECT cm FROM TermConceptMap cm INNER JOIN ResourceTable r ON r.myId = cm.myResourcePid WHERE cm.myUrl = :url ORDER BY r.myUpdated DESC")
"SELECT cm FROM TermConceptMap cm INNER JOIN ResourceTable r ON r = cm.myResource WHERE cm.myUrl = :url ORDER BY r.myUpdated DESC")
List<TermConceptMap> getTermConceptMapEntitiesByUrlOrderByMostRecentUpdate(
Pageable thePage, @Param("url") String theUrl);

View File

@ -20,12 +20,14 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.TermConceptMapGroup;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface ITermConceptMapGroupDao extends JpaRepository<TermConceptMapGroup, Long>, IHapiFhirJpaRepository {
public interface ITermConceptMapGroupDao
extends JpaRepository<TermConceptMapGroup, IdAndPartitionId>, IHapiFhirJpaRepository {
@Query("DELETE FROM TermConceptMapGroup g WHERE g.myId = :pid")
@Modifying
void deleteTermConceptMapGroupById(@Param("pid") Long theId);

View File

@ -20,13 +20,14 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElement;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface ITermConceptMapGroupElementDao
extends JpaRepository<TermConceptMapGroupElement, Long>, IHapiFhirJpaRepository {
extends JpaRepository<TermConceptMapGroupElement, IdAndPartitionId>, IHapiFhirJpaRepository {
@Query("DELETE FROM TermConceptMapGroupElement e WHERE e.myId = :pid")
@Modifying
void deleteTermConceptMapGroupElementById(@Param("pid") Long theId);

View File

@ -20,13 +20,14 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElementTarget;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface ITermConceptMapGroupElementTargetDao
extends JpaRepository<TermConceptMapGroupElementTarget, Long>, IHapiFhirJpaRepository {
extends JpaRepository<TermConceptMapGroupElementTarget, IdAndPartitionId>, IHapiFhirJpaRepository {
@Query("DELETE FROM TermConceptMapGroupElementTarget t WHERE t.myId = :pid")
@Modifying
void deleteTermConceptMapGroupElementTargetById(@Param("pid") Long theId);

View File

@ -28,7 +28,8 @@ import org.springframework.data.repository.query.Param;
import java.util.Collection;
public interface ITermConceptParentChildLinkDao
extends JpaRepository<TermConceptParentChildLink, Long>, IHapiFhirJpaRepository {
extends JpaRepository<TermConceptParentChildLink, TermConceptParentChildLink.TermConceptParentChildLinkPk>,
IHapiFhirJpaRepository {
@Query("SELECT t.myParentPid FROM TermConceptParentChildLink t WHERE t.myChildPid = :child_pid")
Collection<Long> findAllWithChild(@Param("child_pid") Long theConceptPid);

View File

@ -20,12 +20,14 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.TermConceptProperty;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface ITermConceptPropertyDao extends JpaRepository<TermConceptProperty, Long>, IHapiFhirJpaRepository {
public interface ITermConceptPropertyDao
extends JpaRepository<TermConceptProperty, IdAndPartitionId>, IHapiFhirJpaRepository {
@Modifying
@Query("DELETE FROM TermConceptProperty WHERE myCodeSystemVersion.myId = :cs_pid")

View File

@ -20,6 +20,7 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.TermValueSetConcept;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
@ -29,7 +30,8 @@ import org.springframework.data.repository.query.Param;
import java.util.List;
import java.util.Optional;
public interface ITermValueSetConceptDao extends JpaRepository<TermValueSetConcept, Long>, IHapiFhirJpaRepository {
public interface ITermValueSetConceptDao
extends JpaRepository<TermValueSetConcept, IdAndPartitionId>, IHapiFhirJpaRepository {
@Query("SELECT COUNT(*) FROM TermValueSetConcept vsc WHERE vsc.myValueSetPid = :pid")
Integer countByTermValueSetId(@Param("pid") Long theValueSetId);

View File

@ -20,13 +20,14 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.TermValueSetConceptDesignation;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface ITermValueSetConceptDesignationDao
extends JpaRepository<TermValueSetConceptDesignation, Long>, IHapiFhirJpaRepository {
extends JpaRepository<TermValueSetConceptDesignation, IdAndPartitionId>, IHapiFhirJpaRepository {
@Query("SELECT COUNT(vscd) FROM TermValueSetConceptDesignation vscd WHERE vscd.myValueSetPid = :pid")
Integer countByTermValueSetId(@Param("pid") Long theValueSetId);

View File

@ -20,6 +20,7 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.TermValueSetConceptView;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
@ -27,7 +28,7 @@ import org.springframework.data.repository.query.Param;
import java.util.List;
public interface ITermValueSetConceptViewDao
extends JpaRepository<TermValueSetConceptView, Long>, IHapiFhirJpaRepository {
extends JpaRepository<TermValueSetConceptView, IdAndPartitionId>, IHapiFhirJpaRepository {
@Query(
"SELECT v FROM TermValueSetConceptView v WHERE v.myConceptValueSetPid = :pid AND v.myConceptOrder >= :from AND v.myConceptOrder < :to ORDER BY v.myConceptOrder")

View File

@ -20,6 +20,7 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.TermValueSetConceptViewOracle;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
@ -27,7 +28,7 @@ import org.springframework.data.repository.query.Param;
import java.util.List;
public interface ITermValueSetConceptViewOracleDao
extends JpaRepository<TermValueSetConceptViewOracle, Long>, IHapiFhirJpaRepository {
extends JpaRepository<TermValueSetConceptViewOracle, IdAndPartitionId>, IHapiFhirJpaRepository {
@Query(
"SELECT v FROM TermValueSetConceptViewOracle v WHERE v.myConceptValueSetPid = :pid AND v.myConceptOrder >= :from AND v.myConceptOrder < :to ORDER BY v.myConceptOrder")
List<TermValueSetConceptViewOracle> findByTermValueSetId(

View File

@ -21,6 +21,8 @@ package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.TermValueSet;
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.repository.JpaRepository;
@ -30,10 +32,10 @@ import org.springframework.data.repository.query.Param;
import java.util.List;
import java.util.Optional;
public interface ITermValueSetDao extends JpaRepository<TermValueSet, Long>, IHapiFhirJpaRepository {
public interface ITermValueSetDao extends JpaRepository<TermValueSet, IdAndPartitionId>, IHapiFhirJpaRepository {
@Query("SELECT vs FROM TermValueSet vs WHERE vs.myResourcePid = :resource_pid")
Optional<TermValueSet> findByResourcePid(@Param("resource_pid") Long theResourcePid);
@Query("SELECT vs FROM TermValueSet vs WHERE vs.myResource.myPid = :resource_pid")
Optional<TermValueSet> findByResourcePid(@Param("resource_pid") JpaPid theResourcePid);
// Keeping for backwards compatibility but recommend using findTermValueSetByUrlAndNullVersion instead.
@Deprecated
@ -46,7 +48,7 @@ public interface ITermValueSetDao extends JpaRepository<TermValueSet, Long>, IHa
@Query(
value =
"SELECT vs FROM TermValueSet vs INNER JOIN ResourceTable r ON r.myId = vs.myResourcePid WHERE vs.myUrl = :url ORDER BY r.myUpdated DESC")
"SELECT vs FROM TermValueSet vs INNER JOIN ResourceTable r ON r = vs.myResource WHERE vs.myUrl = :url ORDER BY r.myUpdated DESC")
List<TermValueSet> findTermValueSetByUrl(Pageable thePage, @Param("url") String theUrl);
/**

View File

@ -57,7 +57,7 @@ public class IResourceTableDaoImpl implements IForcedIdQueries {
public Collection<Object[]> findAndResolveByForcedIdWithNoType(
String theResourceType, Collection<String> theForcedIds, boolean theExcludeDeleted) {
String query =
"SELECT t.myResourceType, t.myId, t.myFhirId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue "
"SELECT t.myResourceType, t.myPid.myId, t.myFhirId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue "
+ "FROM ResourceTable t "
+ "WHERE t.myResourceType = :resource_type AND t.myFhirId IN ( :forced_id )";
@ -84,7 +84,7 @@ public class IResourceTableDaoImpl implements IForcedIdQueries {
Collection<Integer> thePartitionId,
boolean theExcludeDeleted) {
String query =
"SELECT t.myResourceType, t.myId, t.myFhirId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue "
"SELECT t.myResourceType, t.myPid.myId, t.myFhirId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue "
+ "FROM ResourceTable t "
+ "WHERE t.myResourceType = :resource_type AND t.myFhirId IN ( :forced_id ) AND t.myPartitionIdValue IN ( :partition_id )";
@ -110,7 +110,7 @@ public class IResourceTableDaoImpl implements IForcedIdQueries {
String theResourceType, Collection<String> theForcedIds, boolean theExcludeDeleted) {
// we fetch myPartitionIdValue and myPartitionDateValue for resultSet processing consistency
String query =
"SELECT t.myResourceType, t.myId, t.myFhirId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue "
"SELECT t.myResourceType, t.myPid.myId, t.myFhirId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue "
+ "FROM ResourceTable t "
+ "WHERE t.myResourceType = :resource_type AND t.myFhirId IN ( :forced_id ) AND t.myPartitionIdValue IS NULL";
@ -137,7 +137,7 @@ public class IResourceTableDaoImpl implements IForcedIdQueries {
List<Integer> thePartitionIdsWithoutDefault,
boolean theExcludeDeleted) {
String query =
"SELECT t.myResourceType, t.myId, t.myFhirId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue "
"SELECT t.myResourceType, t.myPid.myId, t.myFhirId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue "
+ "FROM ResourceTable t "
+ "WHERE t.myResourceType = :resource_type AND t.myFhirId IN ( :forced_id ) AND (t.myPartitionIdValue IS NULL OR t.myPartitionIdValue IN ( :partition_id ))";

View File

@ -40,32 +40,18 @@ public class FhirResourceDaoSubscriptionDstu3 extends BaseHapiFhirResourceDao<Su
@Autowired
private ISubscriptionTableDao mySubscriptionTableDao;
private void createSubscriptionTable(ResourceTable theEntity, Subscription theSubscription) {
SubscriptionTable subscriptionEntity = new SubscriptionTable();
subscriptionEntity.setCreated(new Date());
subscriptionEntity.setSubscriptionResource(theEntity);
myEntityManager.persist(subscriptionEntity);
}
@Override
public Long getSubscriptionTablePidForSubscriptionResource(
IIdType theId, RequestDetails theRequest, TransactionDetails theTransactionDetails) {
ResourceTable entity = readEntityLatestVersion(theId, theRequest, theTransactionDetails);
SubscriptionTable table = mySubscriptionTableDao.findOneByResourcePid(entity.getId());
SubscriptionTable table =
mySubscriptionTableDao.findOneByResourcePid(entity.getId().getId());
if (table == null) {
return null;
}
return table.getId();
}
@Override
protected void postPersist(
ResourceTable theEntity, Subscription theSubscription, RequestDetails theRequestDetails) {
super.postPersist(theEntity, theSubscription, theRequestDetails);
createSubscriptionTable(theEntity, theSubscription);
}
@Override
public ResourceTable updateEntity(
RequestDetails theRequest,
@ -89,7 +75,8 @@ public class FhirResourceDaoSubscriptionDstu3 extends BaseHapiFhirResourceDao<Su
theCreateNewHistoryEntry);
if (theDeletedTimestampOrNull != null) {
mySubscriptionTableDao.deleteAllForSubscription((ResourceTable) theEntity);
mySubscriptionTableDao.deleteAllForSubscription(
((ResourceTable) theEntity).getResourceId().getId());
}
return retVal;
}

View File

@ -70,6 +70,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceTag;
import ca.uhn.fhir.jpa.model.entity.SearchParamPresentEntity;
import ca.uhn.fhir.jpa.model.entity.TagDefinition;
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
import ca.uhn.fhir.jpa.search.builder.SearchBuilder;
import ca.uhn.fhir.jpa.util.MemoryCacheService;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
@ -92,7 +93,10 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.util.comparator.Comparators;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
@ -308,25 +312,59 @@ public class ExpungeEverythingService implements IExpungeEverythingService {
Metamodel metamodel = myEntityManager.getMetamodel();
EntityType<T> entity = metamodel.entity(theEntityType);
Set<SingularAttribute<? super T, ?>> singularAttributes = entity.getSingularAttributes();
String idProperty = null;
List<String> idProperty = new ArrayList<>();
for (SingularAttribute<? super T, ?> singularAttribute : singularAttributes) {
if (singularAttribute.isId()) {
idProperty = singularAttribute.getName();
break;
idProperty.add(singularAttribute.getName());
}
}
idProperty.sort(Comparators.comparable());
String idPropertyNames = String.join(",", idProperty);
Query nativeQuery = myEntityManager.createQuery(
"SELECT " + idProperty + " FROM " + theEntityType.getSimpleName());
nativeQuery.setMaxResults(800);
List pids = nativeQuery.getResultList();
"SELECT (" + idPropertyNames + ") FROM " + theEntityType.getSimpleName());
if (!pids.isEmpty()) {
nativeQuery = myEntityManager.createQuery("DELETE FROM " + theEntityType.getSimpleName()
+ " WHERE " + idProperty + " IN (:pids)");
nativeQuery.setParameter("pids", pids);
nativeQuery.executeUpdate();
// Each ID is 2 parameters in DB partition mode, so this
// is the maximum we should allow
nativeQuery.setMaxResults(SearchBuilder.getMaximumPageSize() / 2);
List pids = nativeQuery.getResultList();
if (pids.isEmpty()) {
return 0;
}
StringBuilder deleteBuilder = new StringBuilder();
deleteBuilder.append("DELETE FROM ");
deleteBuilder.append(theEntityType.getSimpleName());
deleteBuilder.append(" WHERE (");
deleteBuilder.append(idPropertyNames);
deleteBuilder.append(") IN ");
if (idProperty.size() > 1) {
deleteBuilder.append('(');
for (Iterator<Object> iter = pids.iterator(); iter.hasNext(); ) {
Object[] pid = (Object[]) iter.next();
deleteBuilder.append('(');
for (int i = 0; i < pid.length; i++) {
if (i > 0) {
deleteBuilder.append(',');
}
deleteBuilder.append(pid[i]);
}
deleteBuilder.append(')');
if (iter.hasNext()) {
deleteBuilder.append(',');
}
}
deleteBuilder.append(')');
} else {
deleteBuilder.append("(:pids)");
}
String deleteSql = deleteBuilder.toString();
nativeQuery = myEntityManager.createQuery(deleteSql);
if (idProperty.size() == 1) {
nativeQuery.setParameter("pids", pids);
}
nativeQuery.executeUpdate();
return pids.size();
});

View File

@ -24,8 +24,6 @@ import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.dao.IJpaStorageResourceParser;
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryProvenanceDao;
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
@ -47,6 +45,7 @@ import ca.uhn.fhir.jpa.dao.data.ISearchParamPresentDao;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryProvenanceEntity;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTablePk;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.util.MemoryCacheService;
import ca.uhn.fhir.model.primitive.IdDt;
@ -76,7 +75,7 @@ import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
@Service
public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid> {
public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid, ResourceHistoryTablePk> {
private static final Logger ourLog = LoggerFactory.getLogger(JpaResourceExpungeService.class);
@Autowired
@ -121,18 +120,12 @@ public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid
@Autowired
private IResourceTagDao myResourceTagDao;
@Autowired
private IIdHelperService myIdHelperService;
@Autowired
private IResourceHistoryTagDao myResourceHistoryTagDao;
@Autowired
private IInterceptorBroadcaster myInterceptorBroadcaster;
@Autowired
private DaoRegistry myDaoRegistry;
@Autowired
private IResourceHistoryProvenanceDao myResourceHistoryProvenanceTableDao;
@ -150,20 +143,20 @@ public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid
@Override
@Transactional
public List<JpaPid> findHistoricalVersionsOfNonDeletedResources(
public List<ResourceHistoryTablePk> findHistoricalVersionsOfNonDeletedResources(
String theResourceName, JpaPid theJpaPid, int theRemainingCount) {
if (isEmptyQuery(theRemainingCount)) {
return Collections.EMPTY_LIST;
return Collections.emptyList();
}
Pageable page = PageRequest.of(0, theRemainingCount);
Slice<Long> ids;
Slice<ResourceHistoryTablePk> ids;
if (theJpaPid != null && theJpaPid.getId() != null) {
if (theJpaPid.getVersion() != null) {
ids = toSlice(myResourceHistoryTableDao.findForIdAndVersion(theJpaPid.getId(), theJpaPid.getVersion()));
ids = toSlice(myResourceHistoryTableDao.findForIdAndVersion(theJpaPid.toFk(), theJpaPid.getVersion()));
} else {
ids = myResourceHistoryTableDao.findIdsOfPreviousVersionsOfResourceId(page, theJpaPid.getId());
ids = myResourceHistoryTableDao.findIdsOfPreviousVersionsOfResourceId(page, theJpaPid);
}
} else {
if (theResourceName != null) {
@ -173,7 +166,7 @@ public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid
}
}
return JpaPid.fromLongList(ids.getContent());
return ids.getContent();
}
@Override
@ -181,11 +174,11 @@ public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid
public List<JpaPid> findHistoricalVersionsOfDeletedResources(
String theResourceName, JpaPid theResourceId, int theRemainingCount) {
if (isEmptyQuery(theRemainingCount)) {
return Collections.EMPTY_LIST;
return Collections.emptyList();
}
Pageable page = PageRequest.of(0, theRemainingCount);
Slice<Long> ids;
Slice<JpaPid> ids;
if (theResourceId != null) {
ids = myResourceTableDao.findIdsOfDeletedResourcesOfType(page, theResourceId.getId(), theResourceName);
ourLog.info(
@ -202,7 +195,7 @@ public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid
ourLog.info("Expunging {} deleted resources (all types)", ids.getNumberOfElements());
}
}
return JpaPid.fromLongList(ids.getContent());
return ids.getContent();
}
@Override
@ -210,7 +203,7 @@ public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid
public void expungeCurrentVersionOfResources(
RequestDetails theRequestDetails, List<JpaPid> theResourceIds, AtomicInteger theRemainingCount) {
for (JpaPid next : theResourceIds) {
expungeCurrentVersionOfResource(theRequestDetails, (next).getId(), theRemainingCount);
expungeCurrentVersionOfResource(theRequestDetails, next, theRemainingCount);
if (expungeLimitReached(theRemainingCount)) {
return;
}
@ -232,7 +225,9 @@ public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid
}
private void expungeHistoricalVersion(
RequestDetails theRequestDetails, Long theNextVersionId, AtomicInteger theRemainingCount) {
RequestDetails theRequestDetails,
ResourceHistoryTablePk theNextVersionId,
AtomicInteger theRemainingCount) {
ResourceHistoryTable version =
myResourceHistoryTableDao.findById(theNextVersionId).orElseThrow(IllegalArgumentException::new);
IdDt id = version.getIdDt();
@ -242,7 +237,7 @@ public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid
if (myStorageSettings.isAccessMetaSourceInformationFromProvenanceTable()) {
Optional<ResourceHistoryProvenanceEntity> provenanceOpt =
myResourceHistoryProvenanceTableDao.findById(theNextVersionId);
myResourceHistoryProvenanceTableDao.findById(theNextVersionId.asIdAndPartitionId());
provenanceOpt.ifPresent(entity -> myResourceHistoryProvenanceTableDao.deleteByPid(entity.getId()));
}
@ -277,9 +272,7 @@ public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid
@Transactional
public void expungeHistoricalVersionsOfIds(
RequestDetails theRequestDetails, List<JpaPid> theResourceIds, AtomicInteger theRemainingCount) {
List<Long> pids = JpaPid.toLongList(theResourceIds);
List<ResourceTable> resourcesToDelete = myResourceTableDao.findAllByIdAndLoadForcedIds(pids);
List<ResourceTable> resourcesToDelete = myResourceTableDao.findAllByIdAndLoadForcedIds(theResourceIds);
for (ResourceTable next : resourcesToDelete) {
expungeHistoricalVersionsOfId(theRequestDetails, next, theRemainingCount);
if (expungeLimitReached(theRemainingCount)) {
@ -291,9 +284,11 @@ public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid
@Override
@Transactional
public void expungeHistoricalVersions(
RequestDetails theRequestDetails, List<JpaPid> theHistoricalIds, AtomicInteger theRemainingCount) {
for (JpaPid next : theHistoricalIds) {
expungeHistoricalVersion(theRequestDetails, (next).getId(), theRemainingCount);
RequestDetails theRequestDetails,
List<ResourceHistoryTablePk> theHistoricalIds,
AtomicInteger theRemainingCount) {
for (ResourceHistoryTablePk next : theHistoricalIds) {
expungeHistoricalVersion(theRequestDetails, next, theRemainingCount);
if (expungeLimitReached(theRemainingCount)) {
return;
}
@ -301,11 +296,12 @@ public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid
}
protected void expungeCurrentVersionOfResource(
RequestDetails theRequestDetails, Long theResourceId, AtomicInteger theRemainingCount) {
RequestDetails theRequestDetails, JpaPid theResourceId, AtomicInteger theRemainingCount) {
ResourceTable resource = myResourceTableDao.findById(theResourceId).orElseThrow(IllegalStateException::new);
ResourceHistoryTable currentVersion =
myResourceHistoryTableDao.findForIdAndVersion(resource.getId(), resource.getVersion());
myResourceHistoryTableDao.findForIdAndVersion(resource.getId().toFk(), resource.getVersion());
if (currentVersion != null) {
expungeHistoricalVersion(theRequestDetails, currentVersion.getId(), theRemainingCount);
}
@ -329,44 +325,43 @@ public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid
@Override
@Transactional
public void deleteAllSearchParams(JpaPid theResourceId) {
Long theResourceLongId = theResourceId.getId();
ResourceTable resource = myResourceTableDao.findById(theResourceLongId).orElse(null);
ResourceTable resource = myResourceTableDao.findById(theResourceId).orElse(null);
if (resource == null || resource.isParamsUriPopulated()) {
myResourceIndexedSearchParamUriDao.deleteByResourceId(theResourceLongId);
myResourceIndexedSearchParamUriDao.deleteByResourceId(theResourceId);
}
if (resource == null || resource.isParamsCoordsPopulated()) {
myResourceIndexedSearchParamCoordsDao.deleteByResourceId(theResourceLongId);
myResourceIndexedSearchParamCoordsDao.deleteByResourceId(theResourceId);
}
if (resource == null || resource.isParamsDatePopulated()) {
myResourceIndexedSearchParamDateDao.deleteByResourceId(theResourceLongId);
myResourceIndexedSearchParamDateDao.deleteByResourceId(theResourceId);
}
if (resource == null || resource.isParamsNumberPopulated()) {
myResourceIndexedSearchParamNumberDao.deleteByResourceId(theResourceLongId);
myResourceIndexedSearchParamNumberDao.deleteByResourceId(theResourceId);
}
if (resource == null || resource.isParamsQuantityPopulated()) {
myResourceIndexedSearchParamQuantityDao.deleteByResourceId(theResourceLongId);
myResourceIndexedSearchParamQuantityDao.deleteByResourceId(theResourceId);
}
if (resource == null || resource.isParamsQuantityNormalizedPopulated()) {
myResourceIndexedSearchParamQuantityNormalizedDao.deleteByResourceId(theResourceLongId);
myResourceIndexedSearchParamQuantityNormalizedDao.deleteByResourceId(theResourceId);
}
if (resource == null || resource.isParamsStringPopulated()) {
myResourceIndexedSearchParamStringDao.deleteByResourceId(theResourceLongId);
myResourceIndexedSearchParamStringDao.deleteByResourceId(theResourceId);
}
if (resource == null || resource.isParamsTokenPopulated()) {
myResourceIndexedSearchParamTokenDao.deleteByResourceId(theResourceLongId);
myResourceIndexedSearchParamTokenDao.deleteByResourceId(theResourceId);
}
if (resource == null || resource.isParamsComboStringUniquePresent()) {
myResourceIndexedCompositeStringUniqueDao.deleteByResourceId(theResourceLongId);
myResourceIndexedCompositeStringUniqueDao.deleteByResourceId(theResourceId);
}
if (resource == null || resource.isParamsComboTokensNonUniquePresent()) {
myResourceIndexedComboTokensNonUniqueDao.deleteByResourceId(theResourceLongId);
myResourceIndexedComboTokensNonUniqueDao.deleteByResourceId(theResourceId);
}
if (myStorageSettings.getIndexMissingFields() == JpaStorageSettings.IndexEnabledEnum.ENABLED) {
mySearchParamPresentDao.deleteByResourceId(theResourceLongId);
mySearchParamPresentDao.deleteByResourceId(theResourceId);
}
if (resource == null || resource.isHasLinks()) {
myResourceLinkDao.deleteByResourceId(theResourceLongId);
myResourceLinkDao.deleteByResourceId(theResourceId);
}
}
@ -380,13 +375,13 @@ public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid
page = PageRequest.of(0, theRemainingCount.get());
}
Slice<Long> versionIds =
myResourceHistoryTableDao.findForResourceId(page, theResource.getId(), theResource.getVersion());
Slice<ResourceHistoryTablePk> versionIds = myResourceHistoryTableDao.findForResourceId(
page, theResource.getId().toFk(), theResource.getVersion());
ourLog.debug(
"Found {} versions of resource {} to expunge",
versionIds.getNumberOfElements(),
theResource.getIdDt().getValue());
for (Long nextVersionId : versionIds) {
for (ResourceHistoryTablePk nextVersionId : versionIds) {
expungeHistoricalVersion(theRequestDetails, nextVersionId, theRemainingCount);
if (expungeLimitReached(theRemainingCount)) {
return;
@ -394,9 +389,9 @@ public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid
}
}
private Slice<Long> toSlice(ResourceHistoryTable myVersion) {
Validate.notNull(myVersion);
return new SliceImpl<>(Collections.singletonList(myVersion.getId()));
private Slice<ResourceHistoryTablePk> toSlice(ResourceHistoryTable theVersion) {
Validate.notNull(theVersion, "theVersion must not be null");
return new SliceImpl<>(Collections.singletonList(theVersion.getId()));
}
private boolean isEmptyQuery(int theCount) {

View File

@ -19,18 +19,21 @@
*/
package ca.uhn.fhir.jpa.dao.expunge;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
public class ResourceForeignKey {
public final String table;
public final String key;
public final String myTable;
public final String myResourceIdColumn;
public final String myPartitionIdColumn;
public ResourceForeignKey(String theTable, String theKey) {
table = theTable;
key = theKey;
public ResourceForeignKey(String theTable, String thePartitionIdColumn, String theResourceIdColumn) {
myTable = theTable;
myPartitionIdColumn = thePartitionIdColumn;
myResourceIdColumn = theResourceIdColumn;
}
@Override
@ -42,21 +45,56 @@ public class ResourceForeignKey {
ResourceForeignKey that = (ResourceForeignKey) theO;
return new EqualsBuilder()
.append(table, that.table)
.append(key, that.key)
.append(myTable, that.myTable)
.append(myResourceIdColumn, that.myResourceIdColumn)
.append(myPartitionIdColumn, that.myPartitionIdColumn)
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 37).append(table).append(key).toHashCode();
return new HashCodeBuilder(17, 37)
.append(myTable)
.append(myPartitionIdColumn)
.append(myResourceIdColumn)
.toHashCode();
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("table", table)
.append("key", key)
.append("table", myTable)
.append("resourceIdColumn", myResourceIdColumn)
.append("partitionIdColumn", myPartitionIdColumn)
.toString();
}
public static final class ResourceForeignKeyBuilder {
private String myTable;
private String myResourceIdColumn;
private String myPartitionIdColumn;
public ResourceForeignKeyBuilder() {}
public void withTable(String myTable) {
this.myTable = myTable;
}
public void withResourceIdColumn(String myResourceIdColumn) {
this.myResourceIdColumn = myResourceIdColumn;
}
public void withPartitionIdColumn(String myPartitionIdColumn) {
this.myPartitionIdColumn = myPartitionIdColumn;
}
public ResourceForeignKey build() {
Validate.notBlank(myTable, "Table is required");
Validate.notBlank(myResourceIdColumn, "ResourceIdColumn is required");
Validate.notBlank(
myPartitionIdColumn,
"PartitionIdColumn is required for table " + myTable + " and resource ID: " + myResourceIdColumn);
return new ResourceForeignKey(this.myTable, this.myPartitionIdColumn, this.myResourceIdColumn);
}
}
}

View File

@ -27,6 +27,16 @@ import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import static ca.uhn.fhir.jpa.entity.MdmLink.GOLDEN_RESOURCE_PARTITION_ID;
import static ca.uhn.fhir.jpa.entity.MdmLink.GOLDEN_RESOURCE_PID;
import static ca.uhn.fhir.jpa.entity.MdmLink.PERSON_PARTITION_ID;
import static ca.uhn.fhir.jpa.entity.MdmLink.PERSON_PID;
import static ca.uhn.fhir.jpa.entity.MdmLink.TARGET_PARTITION_ID;
import static ca.uhn.fhir.jpa.entity.MdmLink.TARGET_PID;
import static ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId.PARTITION_ID;
import static ca.uhn.fhir.jpa.model.entity.ResourceLink.TARGET_RESOURCE_ID;
import static ca.uhn.fhir.jpa.model.entity.ResourceLink.TARGET_RES_PARTITION_ID;
@Service
public class ResourceTableFKProvider {
@Autowired(required = false)
@ -40,39 +50,38 @@ public class ResourceTableFKProvider {
// SELECT FKTABLE_NAME, FKCOLUMN_NAME FROM CROSS_REFERENCES WHERE PKTABLE_NAME = 'HFJ_RESOURCE'
// Add some secondary related records that don't have foreign keys
retval.add(new ResourceForeignKey("HFJ_HISTORY_TAG", "RES_ID")); // NOT covered by index.
retval.add(new ResourceForeignKey("HFJ_RES_VER_PROV", "RES_PID"));
retval.add(new ResourceForeignKey("HFJ_HISTORY_TAG", PARTITION_ID, "RES_ID")); // NOT covered by index.
retval.add(new ResourceForeignKey("HFJ_RES_VER_PROV", PARTITION_ID, "RES_PID"));
// These have the possibility of touching all resource types.
retval.add(new ResourceForeignKey("HFJ_IDX_CMP_STRING_UNIQ", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_IDX_CMB_TOK_NU", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_LINK", "SRC_RESOURCE_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_LINK", "TARGET_RESOURCE_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_PARAM_PRESENT", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_TAG", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_VER", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_COORDS", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_DATE", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_NUMBER", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_QUANTITY", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_QUANTITY_NRML", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_STRING", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_TOKEN", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_URI", "RES_ID"));
retval.add(new ResourceForeignKey("MPI_LINK", "GOLDEN_RESOURCE_PID"));
retval.add(new ResourceForeignKey("MPI_LINK", "TARGET_PID"));
retval.add(new ResourceForeignKey("MPI_LINK", "PERSON_PID"));
retval.add(new ResourceForeignKey("HFJ_IDX_CMP_STRING_UNIQ", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_IDX_CMB_TOK_NU", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_LINK", PARTITION_ID, "SRC_RESOURCE_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_LINK", TARGET_RES_PARTITION_ID, TARGET_RESOURCE_ID));
retval.add(new ResourceForeignKey("HFJ_RES_PARAM_PRESENT", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_TAG", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_VER", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_COORDS", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_DATE", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_NUMBER", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_QUANTITY", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_QUANTITY_NRML", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_STRING", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_TOKEN", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_URI", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("MPI_LINK", GOLDEN_RESOURCE_PARTITION_ID, GOLDEN_RESOURCE_PID));
retval.add(new ResourceForeignKey("MPI_LINK", TARGET_PARTITION_ID, TARGET_PID));
retval.add(new ResourceForeignKey("MPI_LINK", PERSON_PARTITION_ID, PERSON_PID));
// These only touch certain resource types.
retval.add(new ResourceForeignKey("TRM_CODESYSTEM_VER", "RES_ID"));
retval.add(new ResourceForeignKey("TRM_CODESYSTEM", "RES_ID"));
retval.add(new ResourceForeignKey("TRM_VALUESET", "RES_ID"));
retval.add(new ResourceForeignKey("TRM_CONCEPT_MAP", "RES_ID"));
retval.add(new ResourceForeignKey("NPM_PACKAGE_VER", "BINARY_RES_ID"));
retval.add(new ResourceForeignKey("NPM_PACKAGE_VER_RES", "BINARY_RES_ID"));
retval.add(new ResourceForeignKey("TRM_CODESYSTEM_VER", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("TRM_CODESYSTEM", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("TRM_VALUESET", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("TRM_CONCEPT_MAP", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("NPM_PACKAGE_VER", PARTITION_ID, "BINARY_RES_ID"));
retval.add(new ResourceForeignKey("NPM_PACKAGE_VER_RES", PARTITION_ID, "BINARY_RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SUBSCRIPTION_STATS", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_SEARCH_URL", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_SEARCH_URL", PARTITION_ID, "RES_ID"));
return retval;
}
@ -81,50 +90,56 @@ public class ResourceTableFKProvider {
public List<ResourceForeignKey> getResourceForeignKeysByResourceType(String theResourceType) {
List<ResourceForeignKey> retval = new ArrayList<>();
// These have the possibility of touching all resource types.
retval.add(new ResourceForeignKey("HFJ_HISTORY_TAG", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_VER_PROV", "RES_PID"));
retval.add(new ResourceForeignKey("HFJ_IDX_CMP_STRING_UNIQ", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_IDX_CMB_TOK_NU", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_LINK", "SRC_RESOURCE_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_LINK", "TARGET_RESOURCE_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_PARAM_PRESENT", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_TAG", "RES_ID")); // TODO GGG: Res_ID + TAG_ID? is that enough?
retval.add(new ResourceForeignKey("HFJ_RES_VER", "RES_ID")); // TODO GGG: RES_ID + updated? is that enough?
retval.add(new ResourceForeignKey("HFJ_SPIDX_COORDS", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_DATE", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_NUMBER", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_QUANTITY", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_QUANTITY_NRML", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_STRING", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_TOKEN", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_URI", "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_HISTORY_TAG", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_VER_PROV", PARTITION_ID, "RES_PID"));
retval.add(new ResourceForeignKey("HFJ_IDX_CMP_STRING_UNIQ", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_IDX_CMB_TOK_NU", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_LINK", PARTITION_ID, "SRC_RESOURCE_ID"));
retval.add(new ResourceForeignKey("HFJ_RES_LINK", TARGET_PARTITION_ID, TARGET_RESOURCE_ID));
retval.add(new ResourceForeignKey("HFJ_RES_PARAM_PRESENT", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey(
"HFJ_RES_TAG", PARTITION_ID, "RES_ID")); // TODO GGG: Res_ID + TAG_ID? is that enough?
retval.add(new ResourceForeignKey(
"HFJ_RES_VER", PARTITION_ID, "RES_ID")); // TODO GGG: RES_ID + updated? is that enough?
retval.add(new ResourceForeignKey("HFJ_SPIDX_COORDS", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_DATE", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_NUMBER", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_QUANTITY", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_QUANTITY_NRML", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_STRING", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_TOKEN", PARTITION_ID, "RES_ID"));
retval.add(new ResourceForeignKey("HFJ_SPIDX_URI", PARTITION_ID, "RES_ID"));
if (myMdmSettings != null && myMdmSettings.isEnabled()) {
retval.add(new ResourceForeignKey("MPI_LINK", "GOLDEN_RESOURCE_PID")); // NOT covered by index.
retval.add(new ResourceForeignKey("MPI_LINK", "TARGET_PID")); // Possibly covered, partial index
retval.add(new ResourceForeignKey(
"MPI_LINK", GOLDEN_RESOURCE_PARTITION_ID, GOLDEN_RESOURCE_PID)); // NOT covered by index.
retval.add(new ResourceForeignKey(
"MPI_LINK", TARGET_PARTITION_ID, TARGET_PID)); // Possibly covered, partial index
retval.add(new ResourceForeignKey(
"MPI_LINK",
"PERSON_PID")); // TODO GGG: I don't even think we need this... this field is deprecated, and the
PERSON_PARTITION_ID,
PERSON_PID)); // TODO GGG: I don't even think we need this... this field is deprecated, and the
// deletion is covered by GOLDEN_RESOURCE_PID
}
switch (theResourceType.toLowerCase()) {
case "binary":
retval.add(new ResourceForeignKey("NPM_PACKAGE_VER", "BINARY_RES_ID")); // Not covered
retval.add(new ResourceForeignKey("NPM_PACKAGE_VER_RES", "BINARY_RES_ID")); // Not covered
retval.add(new ResourceForeignKey("NPM_PACKAGE_VER", PARTITION_ID, "BINARY_RES_ID")); // Not covered
retval.add(new ResourceForeignKey("NPM_PACKAGE_VER_RES", PARTITION_ID, "BINARY_RES_ID")); // Not covered
break;
case "subscription":
retval.add(new ResourceForeignKey("HFJ_SUBSCRIPTION_STATS", "RES_ID")); // Covered by index.
retval.add(
new ResourceForeignKey("HFJ_SUBSCRIPTION_STATS", PARTITION_ID, "RES_ID")); // Covered by index.
break;
case "codesystem":
retval.add(new ResourceForeignKey("TRM_CODESYSTEM_VER", "RES_ID")); // Not covered
retval.add(new ResourceForeignKey("TRM_CODESYSTEM", "RES_ID")); // Not covered
retval.add(new ResourceForeignKey("TRM_CODESYSTEM_VER", PARTITION_ID, "RES_ID")); // Not covered
retval.add(new ResourceForeignKey("TRM_CODESYSTEM", PARTITION_ID, "RES_ID")); // Not covered
break;
case "valueset":
retval.add(new ResourceForeignKey("TRM_VALUESET", "RES_ID")); // Not covered
retval.add(new ResourceForeignKey("TRM_VALUESET", PARTITION_ID, "RES_ID")); // Not covered
break;
case "conceptmap":
retval.add(new ResourceForeignKey("TRM_CONCEPT_MAP", "RES_ID")); // Not covered
retval.add(new ResourceForeignKey("TRM_CONCEPT_MAP", PARTITION_ID, "RES_ID")); // Not covered
break;
default:
}

View File

@ -115,6 +115,7 @@ public class DaoSearchParamSynchronizer {
@Nullable IPreSaveHook<T> theAddParamPreSaveHook) {
Collection<T> newParams = theNewParams;
for (T next : newParams) {
next.setResourceId(theEntity.getId().getId());
next.setPartitionId(theEntity.getPartitionId());
next.calculateHashes();
}
@ -169,12 +170,24 @@ public class DaoSearchParamSynchronizer {
}
for (T next : paramsToAdd) {
myEntityManager.merge(next);
if (next.getId() == null) {
myEntityManager.persist(next);
} else {
myEntityManager.merge(next);
}
}
// TODO: are there any unintended consequences to fixing this bug?
theAddRemoveCount.addToAddCount(paramsToAdd.size());
theAddRemoveCount.addToRemoveCount(paramsToRemove.size());
// Replace the existing "new set" with the set of params we should be adding.
// We're going to add them back into the entity just in case it gets updated
// a second time within the same transaction
theNewParams.clear();
theNewParams.addAll(theExistingParams);
theNewParams.addAll(paramsToAdd);
theNewParams.removeAll(paramsToRemove);
}
/**

View File

@ -331,7 +331,7 @@ public class IdHelperService implements IIdHelperService<JpaPid> {
CriteriaQuery<Tuple> criteriaQuery = cb.createTupleQuery();
Root<ResourceTable> from = criteriaQuery.from(ResourceTable.class);
criteriaQuery.multiselect(
from.get("myId"),
from.get("myPid"),
from.get("myResourceType"),
from.get("myFhirId"),
from.get("myDeleted"),
@ -363,12 +363,15 @@ public class IdHelperService implements IIdHelperService<JpaPid> {
List<Tuple> results = query.getResultList();
for (Tuple nextId : results) {
// Check if the nextId has a resource ID. It may have a null resource ID if a commit is still pending.
Long resourcePid = nextId.get(0, Long.class);
JpaPid resourcePid = nextId.get(0, JpaPid.class);
String resourceType = nextId.get(1, String.class);
String fhirId = nextId.get(2, String.class);
Date deletedAd = nextId.get(3, Date.class);
Integer partitionId = nextId.get(4, Integer.class);
if (resourcePid != null) {
if (resourcePid.getPartitionId() == null && partitionId != null) {
resourcePid.setPartitionId(partitionId);
}
JpaResourceLookup lookup = new JpaResourceLookup(
resourceType, fhirId, resourcePid, deletedAd, PartitionablePartitionId.with(partitionId, null));
@ -458,7 +461,7 @@ public class IdHelperService implements IIdHelperService<JpaPid> {
if (forcedId.isPresent()) {
retVal.setValue(forcedId.get());
} else {
retVal.setValue(theResourceType + '/' + theId);
retVal.setValue(theResourceType + '/' + theId.getId());
}
return retVal;
@ -469,14 +472,14 @@ public class IdHelperService implements IIdHelperService<JpaPid> {
public Optional<String> translatePidIdToForcedIdWithCache(JpaPid theId) {
// do getIfPresent and then put to avoid doing I/O inside the cache.
Optional<String> forcedId =
myMemoryCacheService.getIfPresent(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, theId.getId());
myMemoryCacheService.getIfPresent(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, theId);
if (forcedId == null) {
// This is only called when we know the resource exists.
// So this optional is only empty when there is no hfj_forced_id table
// note: this is obsolete with the new fhir_id column, and will go away.
forcedId = myResourceTableDao.findById(theId.getId()).map(ResourceTable::asTypedFhirResourceId);
myMemoryCacheService.put(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, theId.getId(), forcedId);
forcedId = myResourceTableDao.findById(theId).map(ResourceTable::asTypedFhirResourceId);
myMemoryCacheService.put(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, theId, forcedId);
}
return forcedId;
@ -497,18 +500,17 @@ public class IdHelperService implements IIdHelperService<JpaPid> {
@Override
public PersistentIdToForcedIdMap<JpaPid> translatePidsToForcedIds(Set<JpaPid> theResourceIds) {
assert myDontCheckActiveTransactionForUnitTest || TransactionSynchronizationManager.isSynchronizationActive();
Set<Long> thePids = theResourceIds.stream().map(JpaPid::getId).collect(Collectors.toSet());
Map<Long, Optional<String>> retVal = new HashMap<>(
myMemoryCacheService.getAllPresent(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, thePids));
HashMap<JpaPid, Optional<String>> retVal = new HashMap<>(
myMemoryCacheService.getAllPresent(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, theResourceIds));
List<Long> remainingPids =
thePids.stream().filter(t -> !retVal.containsKey(t)).collect(Collectors.toList());
List<JpaPid> remainingPids =
theResourceIds.stream().filter(t -> !retVal.containsKey(t)).collect(Collectors.toList());
QueryChunker.chunk(remainingPids, t -> {
new QueryChunker<JpaPid>().chunk(remainingPids, t -> {
List<ResourceTable> resourceEntities = myResourceTableDao.findAllById(t);
for (ResourceTable nextResourceEntity : resourceEntities) {
Long nextResourcePid = nextResourceEntity.getId();
JpaPid nextResourcePid = nextResourceEntity.getPersistentId();
Optional<String> nextForcedId = Optional.of(nextResourceEntity.asTypedFhirResourceId());
retVal.put(nextResourcePid, nextForcedId);
myMemoryCacheService.putAfterCommit(
@ -516,14 +518,14 @@ public class IdHelperService implements IIdHelperService<JpaPid> {
}
});
remainingPids = thePids.stream().filter(t -> !retVal.containsKey(t)).collect(Collectors.toList());
for (Long nextResourcePid : remainingPids) {
remainingPids =
theResourceIds.stream().filter(t -> !retVal.containsKey(t)).collect(Collectors.toList());
for (JpaPid nextResourcePid : remainingPids) {
retVal.put(nextResourcePid, Optional.empty());
myMemoryCacheService.putAfterCommit(
MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, nextResourcePid, Optional.empty());
}
Map<JpaPid, Optional<String>> convertRetVal = new HashMap<>();
retVal.forEach((k, v) -> convertRetVal.put(JpaPid.fromId(k), v));
Map<JpaPid, Optional<String>> convertRetVal = new HashMap<>(retVal);
return new PersistentIdToForcedIdMap<>(convertRetVal);
}
@ -548,7 +550,7 @@ public class IdHelperService implements IIdHelperService<JpaPid> {
myMemoryCacheService.putAfterCommit(
MemoryCacheService.CacheEnum.PID_TO_FORCED_ID,
theJpaPid.getId(),
theJpaPid,
Optional.of(theResourceType + "/" + theFhirId));
JpaResourceLookup lookup = new JpaResourceLookup(
@ -592,7 +594,7 @@ public class IdHelperService implements IIdHelperService<JpaPid> {
retVal = null;
}
} else {
retVal = JpaPid.fromId(Long.parseLong(resourceId.toString()));
retVal = (JpaPid) resourceId;
}
return retVal;
}
@ -600,19 +602,19 @@ public class IdHelperService implements IIdHelperService<JpaPid> {
@Override
@Nonnull
public JpaPid getPidOrThrowException(@Nonnull IAnyResource theResource) {
Long theResourcePID = (Long) theResource.getUserData(RESOURCE_PID);
JpaPid theResourcePID = (JpaPid) theResource.getUserData(RESOURCE_PID);
if (theResourcePID == null) {
throw new IllegalStateException(Msg.code(2108)
+ String.format(
"Unable to find %s in the user data for %s with ID %s",
RESOURCE_PID, theResource, theResource.getId()));
}
return JpaPid.fromId(theResourcePID);
return theResourcePID;
}
@Override
public IIdType resourceIdFromPidOrThrowException(JpaPid thePid, String theResourceType) {
Optional<ResourceTable> optionalResource = myResourceTableDao.findById(thePid.getId());
Optional<ResourceTable> optionalResource = myResourceTableDao.findById(thePid);
if (optionalResource.isEmpty()) {
throw new ResourceNotFoundException(Msg.code(2124) + "Requested resource not found");
}
@ -645,8 +647,15 @@ public class IdHelperService implements IIdHelperService<JpaPid> {
}
@Override
public JpaPid newPidFromStringIdAndResourceName(String thePid, String theResourceName) {
return JpaPid.fromIdAndResourceType(Long.parseLong(thePid), theResourceName);
public JpaPid newPid(Object thePid, Integer thePartitionId) {
return JpaPid.fromId((Long) thePid, thePartitionId);
}
@Override
public JpaPid newPidFromStringIdAndResourceName(Integer thePartitionId, String thePid, String theResourceName) {
JpaPid retVal = JpaPid.fromId(Long.parseLong(thePid), thePartitionId);
retVal.setResourceType(theResourceName);
return retVal;
}
private IIdType newIdType(String theValue) {

View File

@ -40,32 +40,18 @@ public class FhirResourceDaoSubscriptionR4 extends BaseHapiFhirResourceDao<Subsc
@Autowired
private ISubscriptionTableDao mySubscriptionTableDao;
private void createSubscriptionTable(ResourceTable theEntity, Subscription theSubscription) {
SubscriptionTable subscriptionEntity = new SubscriptionTable();
subscriptionEntity.setCreated(new Date());
subscriptionEntity.setSubscriptionResource(theEntity);
myEntityManager.persist(subscriptionEntity);
}
@Override
public Long getSubscriptionTablePidForSubscriptionResource(
IIdType theId, RequestDetails theRequest, TransactionDetails theTransactionDetails) {
ResourceTable entity = readEntityLatestVersion(theId, theRequest, theTransactionDetails);
SubscriptionTable table = mySubscriptionTableDao.findOneByResourcePid(entity.getId());
SubscriptionTable table =
mySubscriptionTableDao.findOneByResourcePid(entity.getId().getId());
if (table == null) {
return null;
}
return table.getId();
}
@Override
protected void postPersist(
ResourceTable theEntity, Subscription theSubscription, RequestDetails theRequestDetails) {
super.postPersist(theEntity, theSubscription, theRequestDetails);
createSubscriptionTable(theEntity, theSubscription);
}
@Override
public ResourceTable updateEntity(
RequestDetails theRequest,
@ -92,7 +78,8 @@ public class FhirResourceDaoSubscriptionR4 extends BaseHapiFhirResourceDao<Subsc
Long subscriptionId = getSubscriptionTablePidForSubscriptionResource(
theEntity.getIdDt(), theRequest, theTransactionDetails);
if (subscriptionId != null) {
mySubscriptionTableDao.deleteAllForSubscription(retVal);
mySubscriptionTableDao.deleteAllForSubscription(
retVal.getResourceId().getId());
}
}

View File

@ -40,32 +40,18 @@ public class FhirResourceDaoSubscriptionR5 extends BaseHapiFhirResourceDao<Subsc
@Autowired
private ISubscriptionTableDao mySubscriptionTableDao;
private void createSubscriptionTable(ResourceTable theEntity, Subscription theSubscription) {
SubscriptionTable subscriptionEntity = new SubscriptionTable();
subscriptionEntity.setCreated(new Date());
subscriptionEntity.setSubscriptionResource(theEntity);
myEntityManager.persist(subscriptionEntity);
}
@Override
public Long getSubscriptionTablePidForSubscriptionResource(
IIdType theId, RequestDetails theRequest, TransactionDetails theTransactionDetails) {
ResourceTable entity = readEntityLatestVersion(theId, theRequest, theTransactionDetails);
SubscriptionTable table = mySubscriptionTableDao.findOneByResourcePid(entity.getId());
SubscriptionTable table =
mySubscriptionTableDao.findOneByResourcePid(entity.getId().getId());
if (table == null) {
return null;
}
return table.getId();
}
@Override
protected void postPersist(
ResourceTable theEntity, Subscription theSubscription, RequestDetails theRequestDetails) {
super.postPersist(theEntity, theSubscription, theRequestDetails);
createSubscriptionTable(theEntity, theSubscription);
}
@Override
public ResourceTable updateEntity(
RequestDetails theRequest,
@ -92,7 +78,8 @@ public class FhirResourceDaoSubscriptionR5 extends BaseHapiFhirResourceDao<Subsc
Long subscriptionId = getSubscriptionTablePidForSubscriptionResource(
theEntity.getIdDt(), theRequest, theTransactionDetails);
if (subscriptionId != null) {
mySubscriptionTableDao.deleteAllForSubscription(retVal);
mySubscriptionTableDao.deleteAllForSubscription(
retVal.getResourceId().getId());
}
}

View File

@ -20,6 +20,7 @@
package ca.uhn.fhir.jpa.dao.search;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.parser.IParser;
import org.apache.commons.lang3.StringUtils;
@ -31,11 +32,11 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
public class ExtendedHSearchResourceProjection {
public static final String RESOURCE_NOT_STORED_ERROR = "Resource not stored in search index: ";
final long myPid;
final JpaPid myPid;
final String myForcedId;
final String myResourceString;
public ExtendedHSearchResourceProjection(long thePid, String theForcedId, String theResourceString) {
public ExtendedHSearchResourceProjection(JpaPid thePid, String theForcedId, String theResourceString) {
if (StringUtils.isEmpty(theResourceString)) {
throw new ResourceNotFoundInIndexException(Msg.code(2130) + RESOURCE_NOT_STORED_ERROR + thePid);
}
@ -51,7 +52,7 @@ public class ExtendedHSearchResourceProjection {
if (myForcedId != null) {
id = new IdDt(myForcedId);
} else {
id = new IdDt(myPid);
id = new IdDt(myPid.getId());
}
result.setId(id);
@ -59,6 +60,6 @@ public class ExtendedHSearchResourceProjection {
}
public long getPid() {
return myPid;
return myPid.getId();
}
}

View File

@ -30,10 +30,10 @@ import java.util.Iterator;
* Adapt Hibernate Search SearchScroll paging result to our ISearchQueryExecutor
*/
public class SearchScrollQueryExecutorAdaptor implements ISearchQueryExecutor {
private final SearchScroll<Long> myScroll;
private Iterator<Long> myCurrentIterator;
private final SearchScroll<JpaPid> myScroll;
private Iterator<JpaPid> myCurrentIterator;
public SearchScrollQueryExecutorAdaptor(SearchScroll<Long> theScroll) {
public SearchScrollQueryExecutorAdaptor(SearchScroll<JpaPid> theScroll) {
myScroll = theScroll;
advanceNextScrollPage();
}
@ -43,7 +43,7 @@ public class SearchScrollQueryExecutorAdaptor implements ISearchQueryExecutor {
* Note: the last page will have 0 hits.
*/
private void advanceNextScrollPage() {
SearchScrollResult<Long> scrollResults = myScroll.next();
SearchScrollResult<JpaPid> scrollResults = myScroll.next();
myCurrentIterator = scrollResults.hits().iterator();
}
@ -59,11 +59,11 @@ public class SearchScrollQueryExecutorAdaptor implements ISearchQueryExecutor {
@Override
public JpaPid next() {
Long result = myCurrentIterator.next();
JpaPid result = myCurrentIterator.next();
// was this the last in the current scroll page?
if (!myCurrentIterator.hasNext()) {
advanceNextScrollPage();
}
return JpaPid.fromId(result);
return result;
}
}

View File

@ -36,7 +36,7 @@ public class DeleteConflictFinderService {
List<ResourceLink> findConflicts(ResourceTable theEntity, int maxResults) {
TypedQuery<ResourceLink> query = myEntityManager.createQuery(
"SELECT l FROM ResourceLink l WHERE l.myTargetResourcePid = :target_pid", ResourceLink.class);
"SELECT l FROM ResourceLink l WHERE l.myTargetResource.myPid = :target_pid", ResourceLink.class);
query.setParameter("target_pid", theEntity.getId());
query.setMaxResults(maxResults);
return query.getResultList();

View File

@ -25,6 +25,7 @@ import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.dao.data.IResourceLinkDao;
import ca.uhn.fhir.jpa.dao.expunge.ResourceForeignKey;
import ca.uhn.fhir.jpa.dao.expunge.ResourceTableFKProvider;
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
@ -34,57 +35,63 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId.PARTITION_ID;
public class DeleteExpungeSqlBuilder {
private static final Logger ourLog = LoggerFactory.getLogger(DeleteExpungeSqlBuilder.class);
private final ResourceTableFKProvider myResourceTableFKProvider;
private final JpaStorageSettings myStorageSettings;
private final IIdHelperService myIdHelper;
private final PartitionSettings myPartitionSettings;
private final IIdHelperService<JpaPid> myIdHelper;
private final IResourceLinkDao myResourceLinkDao;
public DeleteExpungeSqlBuilder(
ResourceTableFKProvider theResourceTableFKProvider,
JpaStorageSettings theStorageSettings,
IIdHelperService theIdHelper,
IResourceLinkDao theResourceLinkDao) {
IIdHelperService<JpaPid> theIdHelper,
IResourceLinkDao theResourceLinkDao,
PartitionSettings thePartitionSettings) {
myResourceTableFKProvider = theResourceTableFKProvider;
myStorageSettings = theStorageSettings;
myIdHelper = theIdHelper;
myResourceLinkDao = theResourceLinkDao;
myPartitionSettings = thePartitionSettings;
}
@Nonnull
DeleteExpungeSqlResult convertPidsToDeleteExpungeSql(
List<JpaPid> theJpaPids, boolean theCascade, Integer theCascadeMaxRounds) {
Set<Long> pids = JpaPid.toLongSet(theJpaPids);
Set<JpaPid> pids = new HashSet<>(theJpaPids);
validateOkToDeleteAndExpunge(pids, theCascade, theCascadeMaxRounds);
List<String> rawSql = new ArrayList<>();
String pidListString = pids.toString().replace("[", "(").replace("]", ")");
List<ResourceForeignKey> resourceForeignKeys = myResourceTableFKProvider.getResourceForeignKeys();
for (ResourceForeignKey resourceForeignKey : resourceForeignKeys) {
rawSql.add(deleteRecordsByColumnSql(pidListString, resourceForeignKey));
rawSql.add(deleteRecordsByColumnSql(pids, resourceForeignKey));
}
// Lastly we need to delete records from the resource table all of these other tables link to:
ResourceForeignKey resourceTablePk = new ResourceForeignKey("HFJ_RESOURCE", "RES_ID");
rawSql.add(deleteRecordsByColumnSql(pidListString, resourceTablePk));
ResourceForeignKey resourceTablePk = new ResourceForeignKey("HFJ_RESOURCE", PARTITION_ID, "RES_ID");
rawSql.add(deleteRecordsByColumnSql(pids, resourceTablePk));
return new DeleteExpungeSqlResult(rawSql, pids.size());
}
public void validateOkToDeleteAndExpunge(Set<Long> thePids, boolean theCascade, Integer theCascadeMaxRounds) {
public void validateOkToDeleteAndExpunge(Set<JpaPid> thePids, boolean theCascade, Integer theCascadeMaxRounds) {
if (!myStorageSettings.isEnforceReferentialIntegrityOnDelete()) {
ourLog.info("Referential integrity on delete disabled. Skipping referential integrity check.");
return;
}
List<JpaPid> targetPidsAsResourceIds = JpaPid.fromLongList(thePids);
List<JpaPid> targetPidsAsResourceIds = List.copyOf(thePids);
List<ResourceLink> conflictResourceLinks = Collections.synchronizedList(new ArrayList<>());
findResourceLinksWithTargetPidIn(targetPidsAsResourceIds, targetPidsAsResourceIds, conflictResourceLinks);
@ -106,9 +113,9 @@ public class DeleteExpungeSqlBuilder {
while (true) {
List<JpaPid> addedThisRound = new ArrayList<>();
for (ResourceLink next : conflictResourceLinks) {
Long nextPid = next.getSourceResourcePid();
JpaPid nextPid = next.getSourceResourcePk();
if (thePids.add(nextPid)) {
addedThisRound.add(JpaPid.fromId(nextPid));
addedThisRound.add(nextPid);
}
}
@ -131,11 +138,11 @@ public class DeleteExpungeSqlBuilder {
// NB-GGG: We previously instantiated these ID values from firstConflict.getSourceResource().getIdDt(), but in a
// situation where we
// actually had to run delete conflict checks in multiple partitions, the executor service starts its own
// sessions on a per thread basis, and by the time
// sessions on a per-thread basis, and by the time
// we arrive here, those sessions are closed. So instead, we resolve them from PIDs, which are eagerly loaded.
String sourceResourceId = myIdHelper
.resourceIdFromPidOrThrowException(
JpaPid.fromId(firstConflict.getSourceResourcePid()), firstConflict.getSourceResourceType())
firstConflict.getSourceResourcePk(), firstConflict.getSourceResourceType())
.toVersionless()
.getValue();
String targetResourceId = myIdHelper
@ -153,19 +160,17 @@ public class DeleteExpungeSqlBuilder {
List<JpaPid> theAllTargetPids,
List<JpaPid> theSomeTargetPids,
List<ResourceLink> theConflictResourceLinks) {
List<Long> allTargetPidsAsLongs = JpaPid.toLongList(theAllTargetPids);
List<Long> someTargetPidsAsLongs = JpaPid.toLongList(theSomeTargetPids);
// We only need to find one conflict, so if we found one already in an earlier partition run, we can skip the
// rest of the searches
if (theConflictResourceLinks.isEmpty()) {
List<ResourceLink> conflictResourceLinks =
myResourceLinkDao.findWithTargetPidIn(someTargetPidsAsLongs).stream()
myResourceLinkDao.findWithTargetPidIn((theSomeTargetPids)).stream()
// Filter out resource links for which we are planning to delete the source.
// theAllTargetPids contains a list of all the pids we are planning to delete. So we only
// want
// to consider a link to be a conflict if the source of that link is not in
// theAllTargetPids.
.filter(link -> !allTargetPidsAsLongs.contains(link.getSourceResourcePid()))
.filter(link -> !(theAllTargetPids).contains(link.getSourceResourcePk()))
.collect(Collectors.toList());
// We do this in two steps to avoid lock contention on this synchronized list
@ -173,9 +178,39 @@ public class DeleteExpungeSqlBuilder {
}
}
private String deleteRecordsByColumnSql(String thePidListString, ResourceForeignKey theResourceForeignKey) {
return "DELETE FROM " + theResourceForeignKey.table + " WHERE " + theResourceForeignKey.key + " IN "
+ thePidListString;
private String deleteRecordsByColumnSql(Set<JpaPid> thePids, ResourceForeignKey theResourceForeignKey) {
StringBuilder builder = new StringBuilder();
builder.append("DELETE FROM ");
builder.append(theResourceForeignKey.myTable);
builder.append(" WHERE ");
if (myPartitionSettings.isPartitionIdsInPrimaryKeys()) {
builder.append("(");
builder.append(theResourceForeignKey.myPartitionIdColumn);
builder.append(",");
builder.append(theResourceForeignKey.myResourceIdColumn);
builder.append(")");
} else {
builder.append(theResourceForeignKey.myResourceIdColumn);
}
builder.append(" IN (");
for (Iterator<JpaPid> iter = thePids.iterator(); iter.hasNext(); ) {
JpaPid pid = iter.next();
if (myPartitionSettings.isPartitionIdsInPrimaryKeys()) {
builder.append("(");
builder.append(pid.getPartitionId());
builder.append(",");
builder.append(pid.getId());
builder.append(")");
} else {
builder.append(pid.getId());
}
if (iter.hasNext()) {
builder.append(",");
}
}
builder.append(")");
return builder.toString();
}
public static class DeleteExpungeSqlResult {
@ -183,8 +218,8 @@ public class DeleteExpungeSqlBuilder {
private final List<String> mySqlStatements;
private final int myRecordCount;
public DeleteExpungeSqlResult(List<String> theSqlStatments, int theRecordCount) {
mySqlStatements = theSqlStatments;
public DeleteExpungeSqlResult(List<String> theSqlStatements, int theRecordCount) {
mySqlStatements = theSqlStatements;
myRecordCount = theRecordCount;
}

View File

@ -28,8 +28,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class DeleteExpungeSvcImpl implements IDeleteExpungeSvc<JpaPid> {
private static final Logger ourLog = LoggerFactory.getLogger(DeleteExpungeSvcImpl.class);
@ -78,8 +78,7 @@ public class DeleteExpungeSvcImpl implements IDeleteExpungeSvc<JpaPid> {
*/
private void clearHibernateSearchIndex(List<JpaPid> thePersistentIds) {
if (myFullTextSearchSvc != null && !myFullTextSearchSvc.isDisabled()) {
List<Object> objectIds =
thePersistentIds.stream().map(JpaPid::getId).collect(Collectors.toList());
List<Object> objectIds = new ArrayList<>(thePersistentIds);
myFullTextSearchSvc.deleteIndexedDocumentsByTypeAndId(ResourceTable.class, objectIds);
ourLog.info("Cleared Hibernate Search indexes.");
}

View File

@ -37,6 +37,7 @@ import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
@ -79,6 +80,12 @@ public class MdmLink extends AuditableBasePartitionable implements IMdmLink<JpaP
private static final int MATCH_RESULT_LENGTH = 16;
private static final int LINK_SOURCE_LENGTH = 16;
public static final int SOURCE_TYPE_LENGTH = 40;
public static final String GOLDEN_RESOURCE_PID = "GOLDEN_RESOURCE_PID";
public static final String GOLDEN_RESOURCE_PARTITION_ID = "GOLDEN_RESOURCE_PARTITION_ID";
public static final String PERSON_PID = "PERSON_PID";
public static final String PERSON_PARTITION_ID = "PERSON_PARTITION_ID";
public static final String TARGET_PID = "TARGET_PID";
public static final String TARGET_PARTITION_ID = "TARGET_PARTITION_ID";
@SequenceGenerator(name = "SEQ_EMPI_LINK_ID", sequenceName = "SEQ_EMPI_LINK_ID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_EMPI_LINK_ID")
@ -90,31 +97,52 @@ public class MdmLink extends AuditableBasePartitionable implements IMdmLink<JpaP
optional = false,
fetch = FetchType.LAZY,
cascade = {})
@JoinColumn(
name = "GOLDEN_RESOURCE_PID",
referencedColumnName = "RES_ID",
foreignKey = @ForeignKey(name = "FK_EMPI_LINK_GOLDEN_RESOURCE"),
insertable = false,
updatable = false,
nullable = false)
@JoinColumns(
value = {
@JoinColumn(
name = GOLDEN_RESOURCE_PID,
referencedColumnName = "RES_ID",
insertable = false,
updatable = false,
nullable = false),
// @JoinColumn(
// name = GOLDEN_RESOURCE_PARTITION_ID,
// referencedColumnName = "PARTITION_ID",
// insertable = false,
// updatable = false,
// nullable = false)
},
foreignKey = @ForeignKey(name = "FK_EMPI_LINK_GOLDEN_RESOURCE"))
@NotAudited
private ResourceTable myGoldenResource;
@Column(name = "GOLDEN_RESOURCE_PID", nullable = false)
@Column(name = GOLDEN_RESOURCE_PID, nullable = false)
private Long myGoldenResourcePid;
@Column(name = GOLDEN_RESOURCE_PARTITION_ID, nullable = true)
private Integer myGoldenResourcePartitionId;
@Deprecated
@ManyToOne(
optional = false,
fetch = FetchType.LAZY,
cascade = {})
@JoinColumn(
name = "PERSON_PID",
referencedColumnName = "RES_ID",
foreignKey = @ForeignKey(name = "FK_EMPI_LINK_PERSON"),
insertable = false,
updatable = false,
nullable = false)
@JoinColumns(
value = {
@JoinColumn(
name = PERSON_PID,
referencedColumnName = "RES_ID",
insertable = false,
updatable = false,
nullable = false),
// @JoinColumn(
// name = PERSON_PARTITION_ID,
// referencedColumnName = "PARTITION_ID",
// insertable = false,
// updatable = false,
// nullable = false)
},
foreignKey = @ForeignKey(name = "FK_EMPI_LINK_PERSON"))
@NotAudited
private ResourceTable myPerson;
@ -122,23 +150,39 @@ public class MdmLink extends AuditableBasePartitionable implements IMdmLink<JpaP
@Column(name = "PERSON_PID", nullable = false)
private Long myPersonPid;
@Deprecated
@Column(name = PERSON_PARTITION_ID, nullable = true)
private Integer myPersonPartitionId;
@ManyToOne(
optional = false,
fetch = FetchType.LAZY,
cascade = {})
@JoinColumn(
name = "TARGET_PID",
referencedColumnName = "RES_ID",
foreignKey = @ForeignKey(name = "FK_EMPI_LINK_TARGET"),
insertable = false,
updatable = false,
nullable = false)
@JoinColumns(
value = {
@JoinColumn(
name = TARGET_PID,
referencedColumnName = "RES_ID",
insertable = false,
updatable = false,
nullable = false),
// @JoinColumn(
// name = TARGET_PARTITION_ID,
// referencedColumnName = "PARTITION_ID",
// insertable = false,
// updatable = false,
// nullable = false)
},
foreignKey = @ForeignKey(name = "FK_EMPI_LINK_TARGET"))
@NotAudited
private ResourceTable mySource;
@Column(name = "TARGET_PID", updatable = false, nullable = false)
private Long mySourcePid;
@Column(name = TARGET_PARTITION_ID, updatable = false, nullable = true)
private Integer mySourcePartitionId;
@Column(name = "MATCH_RESULT", nullable = false)
@Enumerated(EnumType.ORDINAL)
@JdbcTypeCode(SqlTypes.INTEGER)
@ -210,6 +254,7 @@ public class MdmLink extends AuditableBasePartitionable implements IMdmLink<JpaP
setPersonPid(longPid);
myGoldenResourcePid = longPid;
myGoldenResourcePartitionId = theGoldenResourcePid.getPartitionId();
return this;
}
@ -221,6 +266,7 @@ public class MdmLink extends AuditableBasePartitionable implements IMdmLink<JpaP
@Override
public IMdmLink setSourcePersistenceId(JpaPid theSourcePid) {
mySourcePid = theSourcePid.getId();
mySourcePartitionId = theSourcePid.getPartitionId();
return this;
}
@ -230,10 +276,12 @@ public class MdmLink extends AuditableBasePartitionable implements IMdmLink<JpaP
public MdmLink setGoldenResource(ResourceTable theGoldenResource) {
myGoldenResource = theGoldenResource;
myGoldenResourcePid = theGoldenResource.getId();
myGoldenResourcePid = theGoldenResource.getId().getId();
myGoldenResourcePartitionId = theGoldenResource.getPersistentId().getPartitionId();
myPerson = theGoldenResource;
myPersonPid = theGoldenResource.getId();
myPersonPid = theGoldenResource.getId().getId();
myPersonPartitionId = theGoldenResource.getPersistentId().getPartitionId();
return this;
}
@ -269,7 +317,8 @@ public class MdmLink extends AuditableBasePartitionable implements IMdmLink<JpaP
public MdmLink setSource(ResourceTable theSource) {
mySource = theSource;
mySourcePid = theSource.getId();
mySourcePid = theSource.getId().getId();
mySourcePartitionId = theSource.getPersistentId().getPartitionId();
return this;
}
@ -364,6 +413,7 @@ public class MdmLink extends AuditableBasePartitionable implements IMdmLink<JpaP
return this;
}
@Override
public Boolean getEidMatch() {
return myEidMatch;
}
@ -395,6 +445,7 @@ public class MdmLink extends AuditableBasePartitionable implements IMdmLink<JpaP
return this;
}
@Override
public MdmLink setMdmSourceType(String mdmSourceType) {
myMdmSourceType = mdmSourceType;
return this;
@ -417,14 +468,17 @@ public class MdmLink extends AuditableBasePartitionable implements IMdmLink<JpaP
.toString();
}
@Override
public String getMdmSourceType() {
return myMdmSourceType;
}
@Override
public Long getRuleCount() {
return myRuleCount;
}
@Override
public MdmLink setRuleCount(Long theRuleCount) {
myRuleCount = theRuleCount;
return this;

View File

@ -20,6 +20,7 @@
package ca.uhn.fhir.jpa.entity;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.search.SearchStatusEnum;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.model.api.Include;
@ -28,6 +29,7 @@ import ca.uhn.fhir.rest.param.HistorySearchStyleEnum;
import ca.uhn.fhir.rest.server.util.ICachedSearchDetails;
import ca.uhn.fhir.system.HapiSystemProperties;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import jakarta.persistence.Basic;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
@ -87,11 +89,11 @@ public class Search implements ICachedSearchDetails, Serializable {
public static final int SEARCH_UUID_COLUMN_LENGTH = 48;
public static final String HFJ_SEARCH = "HFJ_SEARCH";
public static final String SEARCH_UUID = "SEARCH_UUID";
private static final int MAX_SEARCH_QUERY_STRING = 10000;
private static final int FAILURE_MESSAGE_LENGTH = 500;
private static final long serialVersionUID = 1L;
private static final Logger ourLog = LoggerFactory.getLogger(Search.class);
public static final String SEARCH_UUID = "SEARCH_UUID";
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "CREATED", nullable = false, updatable = false)
@ -140,9 +142,11 @@ public class Search implements ICachedSearchDetails, Serializable {
@Column(name = "RESOURCE_ID", nullable = true)
private Long myResourceId;
@Column(name = "PARTITION_ID", nullable = true)
private Integer myPartitionId;
@Column(name = "RESOURCE_TYPE", length = 200, nullable = true)
private String myResourceType;
/**
* Note that this field may have the request partition IDs prepended to it
*/
@ -150,7 +154,6 @@ public class Search implements ICachedSearchDetails, Serializable {
@Basic(fetch = FetchType.LAZY)
@Column(name = "SEARCH_QUERY_STRING", nullable = true, updatable = false, length = MAX_SEARCH_QUERY_STRING)
private String mySearchQueryString;
/**
* Note that this field may have the request partition IDs prepended to it
*/
@ -190,7 +193,6 @@ public class Search implements ICachedSearchDetails, Serializable {
@Transient
private transient SearchParameterMap mySearchParameterMapTransient;
/**
* This isn't currently persisted in the DB as it's only used for offset mode. We could
* change this if needed in the future.
@ -203,7 +205,6 @@ public class Search implements ICachedSearchDetails, Serializable {
*/
@Transient
private Integer mySizeModeSize;
/**
* This isn't currently persisted in the DB. When there is search criteria defined in the
* search parameter, this is used to keep the search criteria type.
@ -342,14 +343,17 @@ public class Search implements ICachedSearchDetails, Serializable {
myPreferredPageSize = thePreferredPageSize;
}
public Long getResourceId() {
return myResourceId;
@Nullable
public JpaPid getResourceId() {
return myResourceId != null ? JpaPid.fromId(myResourceId, myPartitionId) : null;
}
public void setResourceId(Long theResourceId) {
myResourceId = theResourceId;
public void setResourceId(@Nullable JpaPid theResourceId) {
myResourceId = theResourceId != null ? theResourceId.getId() : null;
myPartitionId = theResourceId != null ? theResourceId.getPartitionId() : null;
}
@Override
public String getResourceType() {
return myResourceType;
}

View File

@ -60,6 +60,9 @@ public class SearchResult implements Serializable {
@Column(name = "RESOURCE_PID", insertable = true, updatable = false, nullable = false)
private Long myResourcePid;
@Column(name = "RESOURCE_PARTITION_ID", insertable = true, updatable = false, nullable = true)
private Integer myResourcePartitionId;
/**
* Constructor
*/
@ -81,6 +84,7 @@ public class SearchResult implements Serializable {
.append("search", mySearchPid)
.append("order", myOrder)
.append("resourcePid", myResourcePid)
.append("resourcePartitionId", myResourcePartitionId)
.toString();
}
@ -109,6 +113,14 @@ public class SearchResult implements Serializable {
return this;
}
public Integer getResourcePartitionId() {
return myResourcePartitionId;
}
public void setResourcePartitionId(Integer theResourcePartitionId) {
myResourcePartitionId = theResourcePartitionId;
}
@Override
public int hashCode() {
return myResourcePid.hashCode();

View File

@ -19,15 +19,11 @@
*/
package ca.uhn.fhir.jpa.entity;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.ForeignKey;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
@ -56,18 +52,9 @@ public class SubscriptionTable {
@Column(name = "PID", insertable = false, updatable = false)
private Long myId;
@Column(name = "RES_ID", insertable = false, updatable = false)
@Column(name = "RES_ID", nullable = true)
private Long myResId;
@OneToOne()
@JoinColumn(
name = "RES_ID",
insertable = true,
updatable = false,
referencedColumnName = "RES_ID",
foreignKey = @ForeignKey(name = "FK_SUBSC_RESOURCE_ID"))
private ResourceTable mySubscriptionResource;
/**
* Constructor
*/
@ -86,12 +73,4 @@ public class SubscriptionTable {
public Long getId() {
return myId;
}
public ResourceTable getSubscriptionResource() {
return mySubscriptionResource;
}
public void setSubscriptionResource(ResourceTable theSubscriptionResource) {
mySubscriptionResource = theSubscriptionResource;
}
}

View File

@ -19,6 +19,8 @@
*/
package ca.uhn.fhir.jpa.entity;
import ca.uhn.fhir.jpa.model.entity.BasePartitionable;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.util.ValidateUtil;
import jakarta.annotation.Nonnull;
@ -29,9 +31,11 @@ import jakarta.persistence.ForeignKey;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
@ -45,7 +49,6 @@ import java.io.Serializable;
import static org.apache.commons.lang3.StringUtils.left;
import static org.apache.commons.lang3.StringUtils.length;
// @formatter:off
@Table(
name = "TRM_CODESYSTEM",
uniqueConstraints = {
@ -58,8 +61,8 @@ import static org.apache.commons.lang3.StringUtils.length;
@Index(name = "FK_TRMCODESYSTEM_CURVER", columnList = "CURRENT_VERSION_PID")
})
@Entity()
// @formatter:on
public class TermCodeSystem implements Serializable {
@IdClass(IdAndPartitionId.class)
public class TermCodeSystem extends BasePartitionable implements Serializable {
public static final int MAX_URL_LENGTH = 200;
private static final long serialVersionUID = 1L;
private static final int MAX_NAME_LENGTH = 200;
@ -67,33 +70,62 @@ public class TermCodeSystem implements Serializable {
@Column(name = "CODE_SYSTEM_URI", nullable = false, length = MAX_URL_LENGTH)
private String myCodeSystemUri;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "CURRENT_VERSION_PID",
referencedColumnName = "PID",
nullable = true,
/**
* Note that this uses a separate partition_id column because it needs
* to be nullable, unlike the PK one which has to be non-nullable
* when we're including partition IDs in PKs.
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns(
value = {
@JoinColumn(
name = "CURRENT_VERSION_PID",
referencedColumnName = "PID",
insertable = false,
updatable = false,
nullable = true),
// @JoinColumn(
// name = "CURRENT_VERSION_PARTITION_ID",
// referencedColumnName = "PARTITION_ID",
// insertable = false,
// updatable = false,
// nullable = true)
},
foreignKey = @ForeignKey(name = "FK_TRMCODESYSTEM_CURVER"))
private TermCodeSystemVersion myCurrentVersion;
@Column(name = "CURRENT_VERSION_PID", nullable = true, insertable = false, updatable = false)
@Column(name = "CURRENT_VERSION_PID", nullable = true, insertable = true, updatable = true)
private Long myCurrentVersionPid;
@Column(name = "CURRENT_VERSION_PARTITION_ID", nullable = true, insertable = true, updatable = true)
private Integer myCurrentVersionPartitionId;
@Id()
@SequenceGenerator(name = "SEQ_CODESYSTEM_PID", sequenceName = "SEQ_CODESYSTEM_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CODESYSTEM_PID")
@Column(name = "PID")
private Long myPid;
private Long myId;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "RES_ID",
referencedColumnName = "RES_ID",
nullable = false,
updatable = true,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns(
value = {
@JoinColumn(
name = "RES_ID",
referencedColumnName = "RES_ID",
nullable = false,
updatable = false,
insertable = false),
// @JoinColumn(
// name = "PARTITION_ID",
// referencedColumnName = "PARTITION_ID",
// nullable = false,
// updatable = false,
// insertable = false)
},
foreignKey = @ForeignKey(name = "FK_TRMCODESYSTEM_RES"))
private ResourceTable myResource;
@Column(name = "RES_ID", insertable = false, updatable = false)
@Column(name = "RES_ID", nullable = false)
private Long myResourcePid;
@Column(name = "CS_NAME", nullable = true, length = MAX_NAME_LENGTH)
@ -158,12 +190,25 @@ public class TermCodeSystem implements Serializable {
}
public TermCodeSystem setCurrentVersion(TermCodeSystemVersion theCurrentVersion) {
myCurrentVersion = theCurrentVersion;
if (theCurrentVersion == null) {
myCurrentVersion = null;
myCurrentVersionPid = null;
myCurrentVersionPartitionId = null;
} else {
myCurrentVersion = theCurrentVersion;
myCurrentVersionPid = theCurrentVersion.getPid();
assert myCurrentVersionPid != null;
myCurrentVersionPartitionId = theCurrentVersion.getPartitionId().getPartitionId();
}
return this;
}
public Long getPid() {
return myPid;
return myId;
}
public IdAndPartitionId getPartitionedId() {
return IdAndPartitionId.forId(myId, this);
}
public ResourceTable getResource() {
@ -172,13 +217,15 @@ public class TermCodeSystem implements Serializable {
public TermCodeSystem setResource(ResourceTable theResource) {
myResource = theResource;
myResourcePid = theResource.getId().getId();
setPartitionId(theResource.getPartitionId());
return this;
}
@Override
public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
b.append("pid", myPid);
b.append("pid", myId);
b.append("codeSystemUri", myCodeSystemUri);
b.append("currentVersionPid", myCurrentVersionPid);
b.append("resourcePid", myResourcePid);

View File

@ -19,8 +19,12 @@
*/
package ca.uhn.fhir.jpa.entity;
import ca.uhn.fhir.jpa.model.entity.BasePartitionable;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.util.ValidateUtil;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
@ -28,11 +32,12 @@ import jakarta.persistence.ForeignKey;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
@ -60,7 +65,8 @@ import static org.apache.commons.lang3.StringUtils.length;
@Index(name = "FK_CODESYSVER_CS_ID", columnList = "CODESYSTEM_PID")
})
@Entity()
public class TermCodeSystemVersion implements Serializable {
@IdClass(IdAndPartitionId.class)
public class TermCodeSystemVersion extends BasePartitionable implements Serializable {
public static final String IDX_CODESYSTEM_AND_VER = "IDX_CODESYSTEM_AND_VER";
public static final int MAX_VERSION_LENGTH = 200;
private static final long serialVersionUID = 1L;
@ -68,22 +74,32 @@ public class TermCodeSystemVersion implements Serializable {
@OneToMany(fetch = FetchType.LAZY, mappedBy = "myCodeSystem")
private Collection<TermConcept> myConcepts;
@Id()
@Id
@SequenceGenerator(name = "SEQ_CODESYSTEMVER_PID", sequenceName = "SEQ_CODESYSTEMVER_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CODESYSTEMVER_PID")
@Column(name = "PID")
private Long myId;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "RES_ID",
referencedColumnName = "RES_ID",
nullable = false,
updatable = false,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns(
value = {
@JoinColumn(
name = "RES_ID",
referencedColumnName = "RES_ID",
nullable = false,
insertable = false,
updatable = false),
// @JoinColumn(
// name = "PARTITION_ID",
// referencedColumnName = "PARTITION_ID",
// nullable = false,
// insertable = false,
// updatable = false)
},
foreignKey = @ForeignKey(name = "FK_CODESYSVER_RES_ID"))
private ResourceTable myResource;
@Column(name = "RES_ID", nullable = false, insertable = false, updatable = false)
@Column(name = "RES_ID", nullable = false)
private Long myResourcePid;
@Column(name = "CS_VERSION_ID", nullable = true, updatable = true, length = MAX_VERSION_LENGTH)
@ -94,20 +110,27 @@ public class TermCodeSystemVersion implements Serializable {
* issued. It should be made non-nullable at some point.
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "CODESYSTEM_PID",
referencedColumnName = "PID",
nullable = true,
@JoinColumns(
value = {
@JoinColumn(
name = "CODESYSTEM_PID",
referencedColumnName = "PID",
insertable = false,
updatable = false,
nullable = true),
// @JoinColumn(
// name = "PARTITION_ID",
// referencedColumnName = "PARTITION_ID",
// insertable = false,
// nullable = true,
// updatable = false)
},
foreignKey = @ForeignKey(name = "FK_CODESYSVER_CS_ID"))
private TermCodeSystem myCodeSystem;
@Column(name = "CODESYSTEM_PID", insertable = false, updatable = false)
@Column(name = "CODESYSTEM_PID", insertable = true, updatable = true, nullable = true)
private Long myCodeSystemPid;
@SuppressWarnings("unused")
@OneToOne(mappedBy = "myCurrentVersion", optional = true, fetch = FetchType.LAZY)
private TermCodeSystem myCodeSystemHavingThisVersionAsCurrentVersionIfAny;
@Column(name = "CS_DISPLAY", nullable = true, updatable = true, length = MAX_VERSION_LENGTH)
private String myCodeSystemDisplayName;
@ -124,6 +147,8 @@ public class TermCodeSystemVersion implements Serializable {
public TermCodeSystemVersion setCodeSystem(TermCodeSystem theCodeSystem) {
myCodeSystem = theCodeSystem;
myCodeSystemPid = theCodeSystem.getPid();
assert myCodeSystemPid != null;
return this;
}
@ -147,16 +172,24 @@ public class TermCodeSystemVersion implements Serializable {
return myConcepts;
}
@Nullable
public Long getPid() {
return myId;
}
@Nonnull
public IdAndPartitionId getId() {
return IdAndPartitionId.forId(myId, this);
}
public ResourceTable getResource() {
return myResource;
}
public TermCodeSystemVersion setResource(ResourceTable theResource) {
myResource = theResource;
myResourcePid = theResource.getId().getId();
setPartitionId(theResource.getPartitionId());
return this;
}

View File

@ -21,11 +21,14 @@ package ca.uhn.fhir.jpa.entity;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.jpa.model.entity.EntityIndexStatusEnum;
import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
import ca.uhn.fhir.jpa.search.DeferConceptIndexingRoutingBinder;
import ca.uhn.fhir.util.ValidateUtil;
import com.google.common.annotations.VisibleForTesting;
import jakarta.annotation.Nonnull;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
@ -33,9 +36,9 @@ import jakarta.persistence.FetchType;
import jakarta.persistence.ForeignKey;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.Lob;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
@ -56,8 +59,16 @@ import org.hibernate.Length;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.search.engine.backend.types.Projectable;
import org.hibernate.search.engine.backend.types.Searchable;
import org.hibernate.search.mapper.pojo.bridge.IdentifierBridge;
import org.hibernate.search.mapper.pojo.bridge.ValueBridge;
import org.hibernate.search.mapper.pojo.bridge.mapping.annotation.IdentifierBridgeRef;
import org.hibernate.search.mapper.pojo.bridge.mapping.annotation.PropertyBinderRef;
import org.hibernate.search.mapper.pojo.bridge.mapping.annotation.RoutingBinderRef;
import org.hibernate.search.mapper.pojo.bridge.mapping.annotation.ValueBridgeRef;
import org.hibernate.search.mapper.pojo.bridge.runtime.IdentifierBridgeFromDocumentIdentifierContext;
import org.hibernate.search.mapper.pojo.bridge.runtime.IdentifierBridgeToDocumentIdentifierContext;
import org.hibernate.search.mapper.pojo.bridge.runtime.ValueBridgeToIndexedValueContext;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.DocumentId;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.GenericField;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed;
@ -71,6 +82,7 @@ import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@ -118,16 +130,27 @@ public class TermConcept implements Serializable {
private Date myUpdated;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "CODESYSTEM_PID",
nullable = false,
referencedColumnName = "PID",
@JoinColumns(
value = {
@JoinColumn(
name = "CODESYSTEM_PID",
insertable = false,
updatable = false,
nullable = false,
referencedColumnName = "PID"),
// @JoinColumn(
// name = "PARTITION_ID",
// referencedColumnName = "PARTITION_ID",
// insertable = false,
// updatable = false,
// nullable = false)
},
foreignKey = @ForeignKey(name = "FK_CONCEPT_PID_CS_PID"))
private TermCodeSystemVersion myCodeSystem;
@Column(name = "CODESYSTEM_PID", insertable = false, updatable = false, nullable = false)
@Column(name = "CODESYSTEM_PID", insertable = true, updatable = false, nullable = false)
@GenericField(name = "myCodeSystemVersionPid")
private long myCodeSystemVersionPid;
private Long myCodeSystemVersionPid;
@Column(name = "DISPLAY", nullable = true, length = MAX_DESC_LENGTH)
@FullTextField(
@ -164,12 +187,16 @@ public class TermConcept implements Serializable {
@OneToMany(mappedBy = "myConcept", orphanRemoval = false, fetch = FetchType.LAZY)
private Collection<TermConceptDesignation> myDesignations;
@Id
@SequenceGenerator(name = "SEQ_CONCEPT_PID", sequenceName = "SEQ_CONCEPT_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_PID")
@Column(name = "PID")
@GenericField
private Long myId;
@EmbeddedId
@DocumentId(identifierBridge = @IdentifierBridgeRef(type = TermConceptPkIdentifierBridge.class))
@GenericField(
name = "myId",
projectable = Projectable.YES,
valueBridge = @ValueBridgeRef(type = TermConceptPkValueBridge.class))
private TermConceptPk myId;
@Column(name = PartitionablePartitionId.PARTITION_ID, nullable = true, insertable = false, updatable = false)
private Integer myPartitionIdValue;
/**
* See {@link EntityIndexStatusEnum} for values
@ -323,6 +350,8 @@ public class TermConcept implements Serializable {
myCodeSystem = theCodeSystemVersion;
if (theCodeSystemVersion != null && theCodeSystemVersion.getPid() != null) {
myCodeSystemVersionPid = theCodeSystemVersion.getPid();
assert myCodeSystemVersionPid != null;
myPartitionIdValue = theCodeSystemVersion.getPartitionId().getPartitionId();
}
return this;
}
@ -359,12 +388,19 @@ public class TermConcept implements Serializable {
return this;
}
public Long getId() {
public TermConceptPk getPid() {
if (myId == null) {
myId = new TermConceptPk();
}
return myId;
}
public Long getId() {
return getPid().myId;
}
public TermConcept setId(Long theId) {
myId = theId;
getPid().myId = theId;
return this;
}
@ -526,4 +562,76 @@ public class TermConcept implements Serializable {
public boolean hasParentPidsLobForTesting() {
return nonNull(myParentPids);
}
public PartitionablePartitionId getPartitionId() {
return PartitionablePartitionId.with(myPartitionIdValue, null);
}
public static class TermConceptPkValueBridge implements ValueBridge<TermConceptPk, Long> {
@Override
public Long toIndexedValue(TermConceptPk value, ValueBridgeToIndexedValueContext context) {
return value.myId;
}
}
public static class TermConceptPkIdentifierBridge implements IdentifierBridge<TermConceptPk> {
@Override
public String toDocumentIdentifier(
TermConceptPk propertyValue, IdentifierBridgeToDocumentIdentifierContext context) {
return Long.toString(propertyValue.myId);
}
@Override
public TermConceptPk fromDocumentIdentifier(
String documentIdentifier, IdentifierBridgeFromDocumentIdentifierContext context) {
TermConceptPk retVal = new TermConceptPk();
retVal.myId = Long.parseLong(documentIdentifier);
return retVal;
}
}
@Embeddable
public static class TermConceptPk implements Serializable {
@SequenceGenerator(name = "SEQ_CONCEPT_PID", sequenceName = "SEQ_CONCEPT_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_PID")
@Column(name = "PID")
@GenericField(projectable = Projectable.YES)
private Long myId;
/**
* Constructor
*/
public TermConceptPk() {
super();
}
/**
* Constructor
*/
public TermConceptPk(Long theId, Integer thePartitionId) {
myId = theId;
}
@Override
public boolean equals(Object theO) {
if (this == theO) {
return true;
}
if (!(theO instanceof TermConceptPk)) {
return false;
}
TermConceptPk that = (TermConceptPk) theO;
return Objects.equals(myId, that.myId);
}
@Override
public int hashCode() {
return Objects.hash(myId);
}
@Override
public String toString() {
return String.valueOf(myId);
}
}
}

View File

@ -19,6 +19,8 @@
*/
package ca.uhn.fhir.jpa.entity;
import ca.uhn.fhir.jpa.model.entity.BasePartitionable;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import ca.uhn.fhir.util.ValidateUtil;
import jakarta.annotation.Nonnull;
import jakarta.persistence.Column;
@ -28,9 +30,12 @@ import jakarta.persistence.ForeignKey;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.PrePersist;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import org.apache.commons.lang3.builder.ToStringBuilder;
@ -53,19 +58,35 @@ import static org.apache.commons.lang3.StringUtils.length;
@Index(name = "FK_CONCEPTDESIG_CONCEPT", columnList = "CONCEPT_PID", unique = false),
@Index(name = "FK_CONCEPTDESIG_CSV", columnList = "CS_VER_PID")
})
public class TermConceptDesignation implements Serializable {
@IdClass(IdAndPartitionId.class)
public class TermConceptDesignation extends BasePartitionable implements Serializable {
private static final long serialVersionUID = 1L;
public static final int MAX_LENGTH = 500;
public static final int MAX_VAL_LENGTH = 2000;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "CONCEPT_PID",
referencedColumnName = "PID",
@JoinColumns(
value = {
@JoinColumn(
name = "CONCEPT_PID",
referencedColumnName = "PID",
insertable = false,
updatable = false,
nullable = false),
// @JoinColumn(
// name = "PARTITION_ID",
// referencedColumnName = "PARTITION_ID",
// insertable = false,
// updatable = false,
// nullable = false)
},
foreignKey = @ForeignKey(name = "FK_CONCEPTDESIG_CONCEPT"))
private TermConcept myConcept;
@Column(name = "CONCEPT_PID", insertable = true, updatable = true, nullable = false)
private Long myConceptPid;
@Id()
@SequenceGenerator(name = "SEQ_CONCEPT_DESIG_PID", sequenceName = "SEQ_CONCEPT_DESIG_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_DESIG_PID")
@ -95,10 +116,21 @@ public class TermConceptDesignation implements Serializable {
* @since 3.5.0
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "CS_VER_PID",
nullable = true,
referencedColumnName = "PID",
@JoinColumns(
value = {
@JoinColumn(
name = "CS_VER_PID",
insertable = true,
updatable = false,
nullable = false,
referencedColumnName = "PID"),
// @JoinColumn(
// name = "PARTITION_ID",
// referencedColumnName = "PARTITION_ID",
// insertable = true,
// updatable = false,
// nullable = false)
},
foreignKey = @ForeignKey(name = "FK_CONCEPTDESIG_CSV"))
private TermCodeSystemVersion myCodeSystemVersion;
@ -164,13 +196,27 @@ public class TermConceptDesignation implements Serializable {
public TermConceptDesignation setConcept(TermConcept theConcept) {
myConcept = theConcept;
myConceptPid = theConcept.getId();
setPartitionId(theConcept.getPartitionId());
return this;
}
@PrePersist
public void prePersist() {
if (myConceptPid == null) {
myConceptPid = myConcept.getId();
assert myConceptPid != null;
}
}
public Long getPid() {
return myId;
}
public IdAndPartitionId getPartitionedId() {
return IdAndPartitionId.forId(myId, this);
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
@ -183,4 +229,8 @@ public class TermConceptDesignation implements Serializable {
.append("value", myValue)
.toString();
}
public Long getId() {
return myId;
}
}

View File

@ -19,6 +19,8 @@
*/
package ca.uhn.fhir.jpa.entity;
import ca.uhn.fhir.jpa.model.entity.BasePartitionable;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.util.ValidateUtil;
import jakarta.annotation.Nonnull;
@ -28,10 +30,12 @@ import jakarta.persistence.ForeignKey;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
@ -57,7 +61,8 @@ import static org.apache.commons.lang3.StringUtils.length;
// automatically
@Index(name = "FK_TRMCONCEPTMAP_RES", columnList = "RES_ID")
})
public class TermConceptMap implements Serializable {
@IdClass(IdAndPartitionId.class)
public class TermConceptMap extends BasePartitionable implements Serializable {
private static final long serialVersionUID = 1L;
static final int MAX_URL_LENGTH = 200;
@ -76,16 +81,26 @@ public class TermConceptMap implements Serializable {
@Column(name = "PID")
private Long myId;
@OneToOne()
@JoinColumn(
name = "RES_ID",
referencedColumnName = "RES_ID",
nullable = false,
updatable = false,
@ManyToOne()
@JoinColumns(
value = {
@JoinColumn(
name = "RES_ID",
referencedColumnName = "RES_ID",
nullable = false,
insertable = false,
updatable = false),
// @JoinColumn(
// name = "PARTITION_ID",
// referencedColumnName = "PARTITION_ID",
// nullable = false,
// insertable = false,
// updatable = false)
},
foreignKey = @ForeignKey(name = "FK_TRMCONCEPTMAP_RES"))
private ResourceTable myResource;
@Column(name = "RES_ID", insertable = false, updatable = false)
@Column(name = "RES_ID", nullable = false)
private Long myResourcePid;
@Column(name = "SOURCE_URL", nullable = true, length = TermValueSet.MAX_URL_LENGTH)
@ -121,15 +136,8 @@ public class TermConceptMap implements Serializable {
public TermConceptMap setResource(ResourceTable theResource) {
myResource = theResource;
return this;
}
public Long getResourcePid() {
return myResourcePid;
}
public TermConceptMap setResourcePid(Long theResourcePid) {
myResourcePid = theResourcePid;
myResourcePid = theResource.getId().getId();
setPartitionId(theResource.getPartitionId());
return this;
}

View File

@ -19,6 +19,8 @@
*/
package ca.uhn.fhir.jpa.entity;
import ca.uhn.fhir.jpa.model.entity.BasePartitionable;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import ca.uhn.fhir.util.ValidateUtil;
import jakarta.annotation.Nonnull;
import jakarta.persistence.Column;
@ -27,8 +29,10 @@ import jakarta.persistence.ForeignKey;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.SequenceGenerator;
@ -46,7 +50,8 @@ import static org.apache.commons.lang3.StringUtils.length;
@Table(
name = "TRM_CONCEPT_MAP_GROUP",
indexes = {@Index(name = "FK_TCMGROUP_CONCEPTMAP", columnList = "CONCEPT_MAP_PID")})
public class TermConceptMapGroup implements Serializable {
@IdClass(IdAndPartitionId.class)
public class TermConceptMapGroup extends BasePartitionable implements Serializable {
private static final long serialVersionUID = 1L;
@Id()
@ -56,10 +61,21 @@ public class TermConceptMapGroup implements Serializable {
private Long myId;
@ManyToOne()
@JoinColumn(
name = "CONCEPT_MAP_PID",
nullable = false,
referencedColumnName = "PID",
@JoinColumns(
value = {
@JoinColumn(
name = "CONCEPT_MAP_PID",
insertable = true,
updatable = false,
nullable = false,
referencedColumnName = "PID"),
// @JoinColumn(
// name = "PARTITION_ID",
// referencedColumnName = "PARTITION_ID",
// insertable = true,
// updatable = false,
// nullable = false)
},
foreignKey = @ForeignKey(name = "FK_TCMGROUP_CONCEPTMAP"))
private TermConceptMap myConceptMap;
@ -93,6 +109,7 @@ public class TermConceptMapGroup implements Serializable {
public TermConceptMapGroup setConceptMap(TermConceptMap theTermConceptMap) {
myConceptMap = theTermConceptMap;
setPartitionId(theTermConceptMap.getPartitionId());
return this;
}

View File

@ -19,6 +19,8 @@
*/
package ca.uhn.fhir.jpa.entity;
import ca.uhn.fhir.jpa.model.entity.BasePartitionable;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import ca.uhn.fhir.util.ValidateUtil;
import jakarta.annotation.Nonnull;
import jakarta.persistence.Column;
@ -27,8 +29,10 @@ import jakarta.persistence.ForeignKey;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.SequenceGenerator;
@ -52,7 +56,8 @@ import static org.apache.commons.lang3.StringUtils.length;
@Index(name = "IDX_CNCPT_MAP_GRP_CD", columnList = "SOURCE_CODE"),
@Index(name = "FK_TCMGELEMENT_GROUP", columnList = "CONCEPT_MAP_GROUP_PID")
})
public class TermConceptMapGroupElement implements Serializable {
@IdClass(IdAndPartitionId.class)
public class TermConceptMapGroupElement extends BasePartitionable implements Serializable {
private static final long serialVersionUID = 1L;
@Id()
@ -62,10 +67,21 @@ public class TermConceptMapGroupElement implements Serializable {
private Long myId;
@ManyToOne()
@JoinColumn(
name = "CONCEPT_MAP_GROUP_PID",
nullable = false,
referencedColumnName = "PID",
@JoinColumns(
value = {
@JoinColumn(
name = "CONCEPT_MAP_GROUP_PID",
insertable = true,
updatable = false,
nullable = false,
referencedColumnName = "PID"),
// @JoinColumn(
// name = "PARTITION_ID",
// referencedColumnName = "PARTITION_ID",
// insertable = true,
// updatable = false,
// nullable = false)
},
foreignKey = @ForeignKey(name = "FK_TCMGELEMENT_GROUP"))
private TermConceptMapGroup myConceptMapGroup;
@ -110,6 +126,7 @@ public class TermConceptMapGroupElement implements Serializable {
public TermConceptMapGroupElement setConceptMapGroup(TermConceptMapGroup theTermConceptMapGroup) {
myConceptMapGroup = theTermConceptMapGroup;
setPartitionId(theTermConceptMapGroup.getPartitionId());
return this;
}

View File

@ -19,6 +19,8 @@
*/
package ca.uhn.fhir.jpa.entity;
import ca.uhn.fhir.jpa.model.entity.BasePartitionable;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import ca.uhn.fhir.util.ValidateUtil;
import jakarta.annotation.Nonnull;
import jakarta.persistence.Column;
@ -29,8 +31,10 @@ import jakarta.persistence.ForeignKey;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
@ -53,7 +57,8 @@ import static org.apache.commons.lang3.StringUtils.length;
@Index(name = "IDX_CNCPT_MP_GRP_ELM_TGT_CD", columnList = "TARGET_CODE"),
@Index(name = "FK_TCMGETARGET_ELEMENT", columnList = "CONCEPT_MAP_GRP_ELM_PID")
})
public class TermConceptMapGroupElementTarget implements Serializable {
@IdClass(IdAndPartitionId.class)
public class TermConceptMapGroupElementTarget extends BasePartitionable implements Serializable {
private static final long serialVersionUID = 1L;
static final int MAX_EQUIVALENCE_LENGTH = 50;
@ -65,10 +70,21 @@ public class TermConceptMapGroupElementTarget implements Serializable {
private Long myId;
@ManyToOne()
@JoinColumn(
name = "CONCEPT_MAP_GRP_ELM_PID",
nullable = false,
referencedColumnName = "PID",
@JoinColumns(
value = {
@JoinColumn(
name = "CONCEPT_MAP_GRP_ELM_PID",
insertable = true,
updatable = false,
nullable = false,
referencedColumnName = "PID"),
// @JoinColumn(
// name = "PARTITION_ID",
// referencedColumnName = "PARTITION_ID",
// insertable = true,
// updatable = false,
// nullable = false)
},
foreignKey = @ForeignKey(name = "FK_TCMGETARGET_ELEMENT"))
private TermConceptMapGroupElement myConceptMapGroupElement;
@ -115,6 +131,7 @@ public class TermConceptMapGroupElementTarget implements Serializable {
public void setConceptMapGroupElement(TermConceptMapGroupElement theTermConceptMapGroupElement) {
myConceptMapGroupElement = theTermConceptMapGroupElement;
setPartitionId(theTermConceptMapGroupElement.getPartitionId());
}
public String getConceptMapUrl() {

View File

@ -19,7 +19,10 @@
*/
package ca.uhn.fhir.jpa.entity;
import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
@ -27,17 +30,22 @@ import jakarta.persistence.FetchType;
import jakarta.persistence.ForeignKey;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.PrePersist;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import jakarta.persistence.Transient;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField;
import org.hibernate.type.SqlTypes;
import java.io.Serializable;
import java.util.Objects;
@Entity
@Table(
@ -53,42 +61,79 @@ public class TermConceptParentChildLink implements Serializable {
private static final long serialVersionUID = 1L;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "CHILD_PID",
nullable = false,
referencedColumnName = "PID",
@JoinColumns(
value = {
@JoinColumn(
name = "CHILD_PID",
insertable = false,
updatable = false,
nullable = false,
referencedColumnName = "PID"),
// @JoinColumn(
// name = "PARTITION_ID",
// referencedColumnName = "PARTITION_ID",
// insertable = false,
// updatable = false,
// nullable = false)
},
foreignKey = @ForeignKey(name = "FK_TERM_CONCEPTPC_CHILD"))
private TermConcept myChild;
@Column(name = "CHILD_PID", insertable = false, updatable = false)
@Column(name = "CHILD_PID", insertable = true, updatable = true, nullable = false)
private Long myChildPid;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "CODESYSTEM_PID", nullable = false, foreignKey = @ForeignKey(name = "FK_TERM_CONCEPTPC_CS"))
@JoinColumns(
value = {
@JoinColumn(
name = "CODESYSTEM_PID",
referencedColumnName = "PID",
insertable = false,
updatable = false,
nullable = false),
// @JoinColumn(
// name = "PARTITION_ID",
// referencedColumnName = "PARTITION_ID",
// insertable = false,
// updatable = false,
// nullable = false)
},
foreignKey = @ForeignKey(name = "FK_TERM_CONCEPTPC_CS"))
private TermCodeSystemVersion myCodeSystem;
@Column(name = "CODESYSTEM_PID", insertable = false, updatable = false, nullable = false)
@Column(name = "CODESYSTEM_PID", insertable = true, updatable = true, nullable = false)
@FullTextField(name = "myCodeSystemVersionPid")
private long myCodeSystemVersionPid;
private Long myCodeSystemVersionPid;
@ManyToOne(
fetch = FetchType.LAZY,
cascade = {})
@JoinColumn(
name = "PARENT_PID",
nullable = false,
referencedColumnName = "PID",
@JoinColumns(
value = {
@JoinColumn(
name = "PARENT_PID",
insertable = false,
updatable = false,
nullable = false,
referencedColumnName = "PID"),
// @JoinColumn(
// name = "PARTITION_ID",
// referencedColumnName = "PARTITION_ID",
// insertable = false,
// updatable = false,
// nullable = false)
},
foreignKey = @ForeignKey(name = "FK_TERM_CONCEPTPC_PARENT"))
private TermConcept myParent;
@Column(name = "PARENT_PID", insertable = false, updatable = false)
@Column(name = "PARENT_PID", insertable = true, updatable = true, nullable = false)
private Long myParentPid;
@Id()
@SequenceGenerator(name = "SEQ_CONCEPT_PC_PID", sequenceName = "SEQ_CONCEPT_PC_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_PC_PID")
@Column(name = "PID")
private Long myPid;
@EmbeddedId
private TermConceptParentChildLinkPk myId;
@Column(name = PartitionablePartitionId.PARTITION_ID, nullable = true, insertable = true, updatable = false)
private Integer myPartitionIdValue;
@Enumerated(EnumType.ORDINAL)
@Column(name = "REL_TYPE", length = 5, nullable = true)
@ -126,8 +171,15 @@ public class TermConceptParentChildLink implements Serializable {
return myCodeSystem;
}
public TermConceptParentChildLinkPk getPid() {
if (myId == null) {
myId = new TermConceptParentChildLinkPk();
}
return myId;
}
public Long getId() {
return myPid;
return getPid().myId;
}
public TermConcept getParent() {
@ -142,6 +194,22 @@ public class TermConceptParentChildLink implements Serializable {
return myRelationshipType;
}
@PrePersist
public void prePersist() {
if (myChildPid == null) {
myChildPid = myChild.getId();
assert myChildPid != null;
}
if (myParentPid == null) {
myParentPid = myParent.getId();
assert myParentPid != null;
}
if (myCodeSystemVersionPid == null) {
myCodeSystemVersionPid = myCodeSystem.getPid();
assert myCodeSystemVersionPid != null;
}
}
@Override
public int hashCode() {
final int prime = 31;
@ -155,16 +223,21 @@ public class TermConceptParentChildLink implements Serializable {
public TermConceptParentChildLink setChild(TermConcept theChild) {
myChild = theChild;
myChildPid = theChild.getId();
return this;
}
public TermConceptParentChildLink setCodeSystem(TermCodeSystemVersion theCodeSystem) {
myCodeSystem = theCodeSystem;
public TermConceptParentChildLink setCodeSystem(TermCodeSystemVersion theCodeSystemVersion) {
myCodeSystem = theCodeSystemVersion;
myCodeSystemVersionPid = theCodeSystemVersion.getPid();
return this;
}
public TermConceptParentChildLink setParent(TermConcept theParent) {
myParent = theParent;
myParentPid = theParent.getId();
myPartitionIdValue = theParent.getPartitionId().getPartitionId();
getPid().myPartitionIdValue = myPartitionIdValue;
return this;
}
@ -173,9 +246,54 @@ public class TermConceptParentChildLink implements Serializable {
return this;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("pid", myId)
.append("csvPid", myCodeSystemVersionPid)
.append("parentPid", myParentPid)
.append("childPid", myChildPid)
.append("rel", myRelationshipType)
.toString();
}
public enum RelationshipTypeEnum {
// ********************************************
// IF YOU ADD HERE MAKE SURE ORDER IS PRESERVED
ISA
}
@Embeddable
public static class TermConceptParentChildLinkPk implements Serializable {
@SequenceGenerator(name = "SEQ_CONCEPT_PC_PID", sequenceName = "SEQ_CONCEPT_PC_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_PC_PID")
@Column(name = "PID")
private Long myId;
@Transient
private Integer myPartitionIdValue;
@Override
public int hashCode() {
return Objects.hash(myId);
}
@Override
public boolean equals(Object theO) {
if (this == theO) {
return true;
}
if (!(theO instanceof TermConceptParentChildLinkPk)) {
return false;
}
TermConceptParentChildLinkPk that = (TermConceptParentChildLinkPk) theO;
return Objects.equals(myId, that.myId);
}
@Override
public String toString() {
return myPartitionIdValue + "/" + myId;
}
}
}

View File

@ -19,6 +19,8 @@
*/
package ca.uhn.fhir.jpa.entity;
import ca.uhn.fhir.jpa.model.entity.BasePartitionable;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import ca.uhn.fhir.util.ValidateUtil;
import com.google.common.annotations.VisibleForTesting;
import jakarta.annotation.Nonnull;
@ -31,10 +33,13 @@ import jakarta.persistence.ForeignKey;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.Lob;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.PrePersist;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import org.apache.commons.lang3.Validate;
@ -68,31 +73,61 @@ import static org.apache.commons.lang3.StringUtils.length;
@Index(name = "FK_CONCEPTPROP_CONCEPT", columnList = "CONCEPT_PID", unique = false),
@Index(name = "FK_CONCEPTPROP_CSV", columnList = "CS_VER_PID")
})
public class TermConceptProperty implements Serializable {
@IdClass(IdAndPartitionId.class)
public class TermConceptProperty extends BasePartitionable implements Serializable {
public static final int MAX_PROPTYPE_ENUM_LENGTH = 6;
private static final long serialVersionUID = 1L;
public static final int MAX_LENGTH = 500;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "CONCEPT_PID",
referencedColumnName = "PID",
@JoinColumns(
value = {
@JoinColumn(
name = "CONCEPT_PID",
referencedColumnName = "PID",
insertable = false,
updatable = false,
nullable = false),
// @JoinColumn(
// name = "PARTITION_ID",
// referencedColumnName = "PARTITION_ID",
// insertable = false,
// updatable = false,
// nullable = false)
},
foreignKey = @ForeignKey(name = "FK_CONCEPTPROP_CONCEPT"))
private TermConcept myConcept;
@Column(name = "CONCEPT_PID", insertable = true, updatable = true, nullable = false)
private Long myConceptPid;
/**
* TODO: Make this non-null
*
* @since 3.5.0
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "CS_VER_PID",
nullable = true,
referencedColumnName = "PID",
@JoinColumns(
value = {
@JoinColumn(
name = "CS_VER_PID",
insertable = false,
updatable = false,
nullable = false,
referencedColumnName = "PID"),
// @JoinColumn(
// name = "PARTITION_ID",
// referencedColumnName = "PARTITION_ID",
// insertable = false,
// updatable = false,
// nullable = false)
},
foreignKey = @ForeignKey(name = "FK_CONCEPTPROP_CSV"))
private TermCodeSystemVersion myCodeSystemVersion;
@Column(name = "CS_VER_PID")
private Long myCodeSystemVersionPid;
@Id()
@SequenceGenerator(name = "SEQ_CONCEPT_PROP_PID", sequenceName = "SEQ_CONCEPT_PROP_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_PROP_PID")
@ -255,14 +290,25 @@ public class TermConceptProperty implements Serializable {
public TermConceptProperty setCodeSystemVersion(TermCodeSystemVersion theCodeSystemVersion) {
myCodeSystemVersion = theCodeSystemVersion;
myCodeSystemVersionPid = theCodeSystemVersion.getPid();
return this;
}
public TermConceptProperty setConcept(TermConcept theConcept) {
myConcept = theConcept;
myConceptPid = theConcept.getId();
setPartitionId(theConcept.getPartitionId());
return this;
}
@PrePersist
public void prePersist() {
if (myConceptPid == null) {
myConceptPid = myConcept.getId();
assert myConceptPid != null;
}
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
@ -308,6 +354,10 @@ public class TermConceptProperty implements Serializable {
return myId;
}
public IdAndPartitionId getPartitionedId() {
return IdAndPartitionId.forId(myId, this);
}
public void performLegacyLobSupport(boolean theSupportLegacyLob) {
if (!theSupportLegacyLob) {
myValueLob = null;
@ -333,4 +383,8 @@ public class TermConceptProperty implements Serializable {
public void setValueBinForTesting(byte[] theValuebin) {
myValueBin = theValuebin;
}
public Long getId() {
return myId;
}
}

View File

@ -19,6 +19,8 @@
*/
package ca.uhn.fhir.jpa.entity;
import ca.uhn.fhir.jpa.model.entity.BasePartitionable;
import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.util.ValidateUtil;
import jakarta.annotation.Nonnull;
@ -31,10 +33,12 @@ import jakarta.persistence.ForeignKey;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
@ -69,7 +73,8 @@ import static org.apache.commons.lang3.StringUtils.length;
@Index(name = "FK_TRMVALUESET_RES", columnList = "RES_ID")
})
@Entity()
public class TermValueSet implements Serializable {
@IdClass(IdAndPartitionId.class)
public class TermValueSet extends BasePartitionable implements Serializable {
public static final int MAX_EXPANSION_STATUS_LENGTH = 50;
public static final int MAX_NAME_LENGTH = 200;
public static final int MAX_URL_LENGTH = 200;
@ -88,16 +93,26 @@ public class TermValueSet implements Serializable {
@Column(name = "VER", nullable = true, length = MAX_VER_LENGTH)
private String myVersion;
@OneToOne()
@JoinColumn(
name = "RES_ID",
referencedColumnName = "RES_ID",
nullable = false,
updatable = false,
@ManyToOne()
@JoinColumns(
value = {
@JoinColumn(
name = "RES_ID",
referencedColumnName = "RES_ID",
nullable = false,
insertable = false,
updatable = false),
// @JoinColumn(
// name = "PARTITION_ID",
// referencedColumnName = "PARTITION_ID",
// nullable = false,
// insertable = false,
// updatable = false)
},
foreignKey = @ForeignKey(name = "FK_TRMVALUESET_RES"))
private ResourceTable myResource;
@Column(name = "RES_ID", insertable = false, updatable = false)
@Column(name = "RES_ID", nullable = false)
private Long myResourcePid;
@Column(name = "VSNAME", nullable = true, length = MAX_NAME_LENGTH)
@ -145,6 +160,10 @@ public class TermValueSet implements Serializable {
return myId;
}
public IdAndPartitionId getPartitionedId() {
return IdAndPartitionId.forId(myId, this);
}
public String getUrl() {
return myUrl;
}
@ -163,6 +182,8 @@ public class TermValueSet implements Serializable {
public TermValueSet setResource(ResourceTable theResource) {
myResource = theResource;
myResourcePid = theResource.getId().getId();
setPartitionId(theResource.getPartitionId());
return this;
}

Some files were not shown because too many files have changed in this diff Show More