Transaction with delete then update should not fail (#4831)
* Fixed * Test fixes * Add test * Ongoing work * Work on xactx * Cleanup * Changelog cleanup * Resolve fixme * Rework broken APIs * Version bump * Add license headers * License header update * License * rk on fixes * Test fixes * Address review comments * Test fixes * Add license headers * License header
This commit is contained in:
parent
8cf14c8c0e
commit
483ddca3be
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -249,6 +249,22 @@ public class BundleBuilder {
|
||||||
return new CreateBuilder(request);
|
return new CreateBuilder(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an entry containing a delete (DELETE) request.
|
||||||
|
* Also sets the Bundle.type value to "transaction" if it is not already set.
|
||||||
|
* <p>
|
||||||
|
* Note that the resource is only used to extract its ID and type, and the body of the resource is not included in the entry,
|
||||||
|
*
|
||||||
|
* @param theCondition The conditional URL, e.g. "Patient?identifier=foo|bar"
|
||||||
|
* @since 6.8.0
|
||||||
|
*/
|
||||||
|
public DeleteBuilder addTransactionDeleteConditionalEntry(String theCondition) {
|
||||||
|
Validate.notBlank(theCondition, "theCondition must not be blank");
|
||||||
|
|
||||||
|
setBundleField("type", "transaction");
|
||||||
|
return addDeleteEntry(theCondition);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an entry containing a delete (DELETE) request.
|
* Adds an entry containing a delete (DELETE) request.
|
||||||
* Also sets the Bundle.type value to "transaction" if it is not already set.
|
* Also sets the Bundle.type value to "transaction" if it is not already set.
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-bom</artifactId>
|
<artifactId>hapi-fhir-bom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<name>HAPI FHIR BOM</name>
|
<name>HAPI FHIR BOM</name>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-cli</artifactId>
|
<artifactId>hapi-fhir-cli</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Docs
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
package ca.uhn.hapi.fhir.docs;
|
package ca.uhn.hapi.fhir.docs;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 4831
|
||||||
|
title: "When performing a FHIR transaction containing both a conditional delete as well as a
|
||||||
|
conditional create/update for the same resource, the resource was left in an inconsistent
|
||||||
|
state. This has been corrected. Thanks to Laxman Singh for raising this issue."
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: perf
|
||||||
|
issue: 4831
|
||||||
|
title: "Conditional deletes that delete multiple resources at once have been optimized to perform
|
||||||
|
fewer SQL select statements, which should improve performance on large deletes."
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
- item:
|
||||||
|
type: "add"
|
||||||
|
title: "The version of a few dependencies have been bumped to the latest versions
|
||||||
|
(dependent HAPI modules listed in brackets):
|
||||||
|
<ul>
|
||||||
|
<li>Hibernate ORM (JPA): 5.6.12.Final -> 5.6.15.Final</li>
|
||||||
|
</ul>"
|
|
@ -11,7 +11,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -536,20 +536,16 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
||||||
|
|
||||||
|
|
||||||
void incrementId(T theResource, ResourceTable theSavedEntity, IIdType theResourceId) {
|
void incrementId(T theResource, ResourceTable theSavedEntity, IIdType theResourceId) {
|
||||||
String newVersion;
|
|
||||||
long newVersionLong;
|
|
||||||
if (theResourceId == null || theResourceId.getVersionIdPart() == null) {
|
if (theResourceId == null || theResourceId.getVersionIdPart() == null) {
|
||||||
newVersion = "1";
|
theSavedEntity.initializeVersion();
|
||||||
newVersionLong = 1;
|
|
||||||
} else {
|
} else {
|
||||||
newVersionLong = theResourceId.getVersionIdPartAsLong() + 1;
|
theSavedEntity.markVersionUpdatedInCurrentTransaction();
|
||||||
newVersion = Long.toString(newVersionLong);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert theResourceId != null;
|
assert theResourceId != null;
|
||||||
|
String newVersion = Long.toString(theSavedEntity.getVersion());
|
||||||
IIdType newId = theResourceId.withVersion(newVersion);
|
IIdType newId = theResourceId.withVersion(newVersion);
|
||||||
theResource.getIdElement().setValue(newId.getValue());
|
theResource.getIdElement().setValue(newId.getValue());
|
||||||
theSavedEntity.setVersion(newVersionLong);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLogicalReference(IIdType theId) {
|
public boolean isLogicalReference(IIdType theId) {
|
||||||
|
@ -1090,9 +1086,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theUpdateVersion) {
|
if (entity.getId() != null && theUpdateVersion) {
|
||||||
long newVersion = entity.getVersion() + 1;
|
entity.markVersionUpdatedInCurrentTransaction();
|
||||||
entity.setVersion(newVersion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1295,6 +1290,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
||||||
|
|
||||||
private void createHistoryEntry(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, EncodedResource theChanged) {
|
private void createHistoryEntry(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, EncodedResource theChanged) {
|
||||||
boolean versionedTags = getStorageSettings().getTagStorageMode() == JpaStorageSettings.TagStorageModeEnum.VERSIONED;
|
boolean versionedTags = getStorageSettings().getTagStorageMode() == JpaStorageSettings.TagStorageModeEnum.VERSIONED;
|
||||||
|
|
||||||
final ResourceHistoryTable historyEntry = theEntity.toHistory(versionedTags);
|
final ResourceHistoryTable historyEntry = theEntity.toHistory(versionedTags);
|
||||||
historyEntry.setEncoding(theChanged.getEncoding());
|
historyEntry.setEncoding(theChanged.getEncoding());
|
||||||
historyEntry.setResource(theChanged.getResourceBinary());
|
historyEntry.setResource(theChanged.getResourceBinary());
|
||||||
|
|
|
@ -35,6 +35,7 @@ import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
|
import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
|
||||||
import ca.uhn.fhir.jpa.api.dao.ReindexOutcome;
|
import ca.uhn.fhir.jpa.api.dao.ReindexOutcome;
|
||||||
import ca.uhn.fhir.jpa.api.dao.ReindexParameters;
|
import ca.uhn.fhir.jpa.api.dao.ReindexParameters;
|
||||||
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
||||||
|
@ -199,9 +200,10 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
private TransactionTemplate myTxTemplate;
|
private TransactionTemplate myTxTemplate;
|
||||||
@Autowired
|
@Autowired
|
||||||
private UrlPartitioner myUrlPartitioner;
|
private UrlPartitioner myUrlPartitioner;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ResourceSearchUrlSvc myResourceSearchUrlSvc;
|
private ResourceSearchUrlSvc myResourceSearchUrlSvc;
|
||||||
|
@Autowired
|
||||||
|
private IFhirSystemDao<?, ?> mySystemDao;
|
||||||
|
|
||||||
public static <T extends IBaseResource> T invokeStoragePreShowResources(IInterceptorBroadcaster theInterceptorBroadcaster, RequestDetails theRequest, T retVal) {
|
public static <T extends IBaseResource> T invokeStoragePreShowResources(IInterceptorBroadcaster theInterceptorBroadcaster, RequestDetails theRequest, T retVal) {
|
||||||
if (CompositeInterceptorBroadcaster.hasHooks(Pointcut.STORAGE_PRESHOW_RESOURCES, theInterceptorBroadcaster, theRequest)) {
|
if (CompositeInterceptorBroadcaster.hasHooks(Pointcut.STORAGE_PRESHOW_RESOURCES, theInterceptorBroadcaster, theRequest)) {
|
||||||
|
@ -263,12 +265,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public DaoMethodOutcome create(final T theResource) {
|
public DaoMethodOutcome create(final T theResource) {
|
||||||
return create(theResource, null, true, new TransactionDetails(), null);
|
return create(theResource, null, true, null, new TransactionDetails());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DaoMethodOutcome create(final T theResource, RequestDetails theRequestDetails) {
|
public DaoMethodOutcome create(final T theResource, RequestDetails theRequestDetails) {
|
||||||
return create(theResource, null, true, new TransactionDetails(), theRequestDetails);
|
return create(theResource, null, true, theRequestDetails, new TransactionDetails());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -281,11 +283,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DaoMethodOutcome create(final T theResource, String theIfNoneExist, RequestDetails theRequestDetails) {
|
public DaoMethodOutcome create(final T theResource, String theIfNoneExist, RequestDetails theRequestDetails) {
|
||||||
return create(theResource, theIfNoneExist, true, new TransactionDetails(), theRequestDetails);
|
return create(theResource, theIfNoneExist, true, theRequestDetails, new TransactionDetails());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DaoMethodOutcome create(T theResource, String theIfNoneExist, boolean thePerformIndexing, @Nonnull TransactionDetails theTransactionDetails, RequestDetails theRequestDetails) {
|
public DaoMethodOutcome create(T theResource, String theIfNoneExist, boolean thePerformIndexing, RequestDetails theRequestDetails, @Nonnull TransactionDetails theTransactionDetails) {
|
||||||
RequestPartitionId requestPartitionId = myRequestPartitionHelperService.determineCreatePartitionForRequest(theRequestDetails, theResource, getResourceName());
|
RequestPartitionId requestPartitionId = myRequestPartitionHelperService.determineCreatePartitionForRequest(theRequestDetails, theResource, getResourceName());
|
||||||
return myTransactionService
|
return myTransactionService
|
||||||
.withRequest(theRequestDetails)
|
.withRequest(theRequestDetails)
|
||||||
|
@ -340,7 +342,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
entity.setResourceType(toResourceName(theResource));
|
entity.setResourceType(toResourceName(theResource));
|
||||||
entity.setPartitionId(PartitionablePartitionId.toStoragePartition(theRequestPartitionId, myPartitionSettings));
|
entity.setPartitionId(PartitionablePartitionId.toStoragePartition(theRequestPartitionId, myPartitionSettings));
|
||||||
entity.setCreatedByMatchUrl(theMatchUrl);
|
entity.setCreatedByMatchUrl(theMatchUrl);
|
||||||
entity.setVersion(1);
|
entity.initializeVersion();
|
||||||
|
|
||||||
if (isNotBlank(theMatchUrl) && theProcessMatchUrl) {
|
if (isNotBlank(theMatchUrl) && theProcessMatchUrl) {
|
||||||
Set<JpaPid> match = myMatchResourceUrlService.processMatchUrl(theMatchUrl, myResourceType, theTransactionDetails, theRequest);
|
Set<JpaPid> match = myMatchResourceUrlService.processMatchUrl(theMatchUrl, myResourceType, theTransactionDetails, theRequest);
|
||||||
|
@ -348,19 +350,51 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
String msg = getContext().getLocalizer().getMessageSanitized(BaseStorageDao.class, "transactionOperationWithMultipleMatchFailure", "CREATE", theMatchUrl, match.size());
|
String msg = getContext().getLocalizer().getMessageSanitized(BaseStorageDao.class, "transactionOperationWithMultipleMatchFailure", "CREATE", theMatchUrl, match.size());
|
||||||
throw new PreconditionFailedException(Msg.code(958) + msg);
|
throw new PreconditionFailedException(Msg.code(958) + msg);
|
||||||
} else if (match.size() == 1) {
|
} else if (match.size() == 1) {
|
||||||
JpaPid pid = match.iterator().next();
|
|
||||||
|
|
||||||
Supplier<LazyDaoMethodOutcome.EntityAndResource> entitySupplier = () -> {
|
/*
|
||||||
return myTxTemplate.execute(tx -> {
|
* Ok, so we've found a single PID that matches the conditional URL.
|
||||||
|
* That's good, there are two possibilities below.
|
||||||
|
*/
|
||||||
|
|
||||||
|
JpaPid pid = match.iterator().next();
|
||||||
|
if (theTransactionDetails.getDeletedResourceIds().contains(pid)) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the resource matching the given match URL has already been
|
||||||
|
* deleted within this transaction. This is a really rare case, since
|
||||||
|
* it means the client has performed a FHIR transaction with both
|
||||||
|
* a delete and a create on the same conditional URL. This is rare
|
||||||
|
* but allowed, and means that it's now ok to create a new one resource
|
||||||
|
* matching the conditional URL since we'll be deleting any existing
|
||||||
|
* index rows on the existing resource as a part of this transaction.
|
||||||
|
* We can also un-resolve the previous match URL in the TransactionDetails
|
||||||
|
* since we'll resolve it to the new resource ID below
|
||||||
|
*/
|
||||||
|
|
||||||
|
myMatchResourceUrlService.unresolveMatchUrl(theTransactionDetails, getResourceName(), theMatchUrl);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the normal path where the conditional URL matched exactly
|
||||||
|
* one resource, so we won't be creating anything but instead
|
||||||
|
* just returning the existing ID. We now have a PID for the matching
|
||||||
|
* resource, but we haven't loaded anything else (e.g. the forced ID
|
||||||
|
* or the resource body aren't yet loaded from the DB). We're going to
|
||||||
|
* return a LazyDaoOutcome with two lazy loaded providers for loading the
|
||||||
|
* entity and the forced ID since we can avoid these extra SQL loads
|
||||||
|
* unless we know we're actually going to use them. For example, if
|
||||||
|
* the client has specified "Prefer: return=minimal" then we won't be
|
||||||
|
* needing the load the body.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Supplier<LazyDaoMethodOutcome.EntityAndResource> entitySupplier = () -> myTxTemplate.execute(tx -> {
|
||||||
ResourceTable foundEntity = myEntityManager.find(ResourceTable.class, pid.getId());
|
ResourceTable foundEntity = myEntityManager.find(ResourceTable.class, pid.getId());
|
||||||
IBaseResource resource = myJpaStorageResourceParser.toResource(foundEntity, false);
|
IBaseResource resource = myJpaStorageResourceParser.toResource(foundEntity, false);
|
||||||
theResource.setId(resource.getIdElement().getValue());
|
theResource.setId(resource.getIdElement().getValue());
|
||||||
return new LazyDaoMethodOutcome.EntityAndResource(foundEntity, resource);
|
return new LazyDaoMethodOutcome.EntityAndResource(foundEntity, resource);
|
||||||
});
|
});
|
||||||
};
|
Supplier<IIdType> idSupplier = () -> myTxTemplate.execute(tx -> {
|
||||||
|
|
||||||
Supplier<IIdType> idSupplier = () -> {
|
|
||||||
return myTxTemplate.execute(tx -> {
|
|
||||||
IIdType retVal = myIdHelperService.translatePidIdToForcedId(myFhirContext, myResourceName, pid);
|
IIdType retVal = myIdHelperService.translatePidIdToForcedId(myFhirContext, myResourceName, pid);
|
||||||
if (!retVal.hasVersionIdPart()) {
|
if (!retVal.hasVersionIdPart()) {
|
||||||
Long version = myMemoryCacheService.getIfPresent(MemoryCacheService.CacheEnum.RESOURCE_CONDITIONAL_CREATE_VERSION, pid.getId());
|
Long version = myMemoryCacheService.getIfPresent(MemoryCacheService.CacheEnum.RESOURCE_CONDITIONAL_CREATE_VERSION, pid.getId());
|
||||||
|
@ -376,7 +410,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
}
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
DaoMethodOutcome outcome = toMethodOutcomeLazy(theRequest, pid, entitySupplier, idSupplier).setCreated(false).setNop(true);
|
DaoMethodOutcome outcome = toMethodOutcomeLazy(theRequest, pid, entitySupplier, idSupplier).setCreated(false).setNop(true);
|
||||||
StorageResponseCodeEnum responseCode = StorageResponseCodeEnum.SUCCESSFUL_CREATE_WITH_CONDITIONAL_MATCH;
|
StorageResponseCodeEnum responseCode = StorageResponseCodeEnum.SUCCESSFUL_CREATE_WITH_CONDITIONAL_MATCH;
|
||||||
|
@ -385,6 +418,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
return outcome;
|
return outcome;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String resourceIdBeforeStorage = theResource.getIdElement().getIdPart();
|
String resourceIdBeforeStorage = theResource.getIdElement().getIdPart();
|
||||||
boolean resourceHadIdBeforeStorage = isNotBlank(resourceIdBeforeStorage);
|
boolean resourceHadIdBeforeStorage = isNotBlank(resourceIdBeforeStorage);
|
||||||
|
@ -617,12 +651,15 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
throw new ResourceVersionConflictException(Msg.code(961) + "Trying to delete " + theId + " but this is not the current version");
|
throw new ResourceVersionConflictException(Msg.code(961) + "Trying to delete " + theId + " but this is not the current version");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JpaPid persistentId = JpaPid.fromId(entity.getResourceId());
|
||||||
|
theTransactionDetails.addDeletedResourceId(persistentId);
|
||||||
|
|
||||||
// Don't delete again if it's already deleted
|
// Don't delete again if it's already deleted
|
||||||
if (isDeleted(entity)) {
|
if (isDeleted(entity)) {
|
||||||
DaoMethodOutcome outcome = createMethodOutcomeForResourceId(entity.getIdDt().getValue(), MESSAGE_KEY_DELETE_RESOURCE_ALREADY_DELETED, StorageResponseCodeEnum.SUCCESSFUL_DELETE_ALREADY_DELETED);
|
DaoMethodOutcome outcome = createMethodOutcomeForResourceId(entity.getIdDt().getValue(), MESSAGE_KEY_DELETE_RESOURCE_ALREADY_DELETED, StorageResponseCodeEnum.SUCCESSFUL_DELETE_ALREADY_DELETED);
|
||||||
|
|
||||||
// used to exist, so we'll set the persistent id
|
// used to exist, so we'll set the persistent id
|
||||||
outcome.setPersistentId(JpaPid.fromId(entity.getResourceId()));
|
outcome.setPersistentId(persistentId);
|
||||||
outcome.setEntity(entity);
|
outcome.setEntity(entity);
|
||||||
|
|
||||||
return outcome;
|
return outcome;
|
||||||
|
@ -681,7 +718,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
|
|
||||||
return myTransactionService.execute(theRequest, transactionDetails, tx -> {
|
return myTransactionService.execute(theRequest, transactionDetails, tx -> {
|
||||||
DeleteConflictList deleteConflicts = new DeleteConflictList();
|
DeleteConflictList deleteConflicts = new DeleteConflictList();
|
||||||
DeleteMethodOutcome outcome = deleteByUrl(theUrl, deleteConflicts, theRequest);
|
DeleteMethodOutcome outcome = deleteByUrl(theUrl, deleteConflicts, theRequest, transactionDetails);
|
||||||
DeleteConflictUtil.validateDeleteConflictsEmptyOrThrowException(getContext(), deleteConflicts);
|
DeleteConflictUtil.validateDeleteConflictsEmptyOrThrowException(getContext(), deleteConflicts);
|
||||||
return outcome;
|
return outcome;
|
||||||
});
|
});
|
||||||
|
@ -692,20 +729,19 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
* transaction processors
|
* transaction processors
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public DeleteMethodOutcome deleteByUrl(String theUrl, DeleteConflictList deleteConflicts, RequestDetails theRequestDetails) {
|
public DeleteMethodOutcome deleteByUrl(String theUrl, DeleteConflictList deleteConflicts, RequestDetails theRequestDetails, @Nonnull TransactionDetails theTransactionDetails) {
|
||||||
validateDeleteEnabled();
|
validateDeleteEnabled();
|
||||||
TransactionDetails transactionDetails = new TransactionDetails();
|
|
||||||
|
|
||||||
return myTransactionService.execute(theRequestDetails, transactionDetails, tx -> doDeleteByUrl(theUrl, deleteConflicts, theRequestDetails));
|
return myTransactionService.execute(theRequestDetails, theTransactionDetails, tx -> doDeleteByUrl(theUrl, deleteConflicts, theTransactionDetails, theRequestDetails));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private DeleteMethodOutcome doDeleteByUrl(String theUrl, DeleteConflictList deleteConflicts, RequestDetails theRequest) {
|
private DeleteMethodOutcome doDeleteByUrl(String theUrl, DeleteConflictList deleteConflicts, TransactionDetails theTransactionDetails, RequestDetails theRequestDetails) {
|
||||||
ResourceSearch resourceSearch = myMatchUrlService.getResourceSearch(theUrl);
|
ResourceSearch resourceSearch = myMatchUrlService.getResourceSearch(theUrl);
|
||||||
SearchParameterMap paramMap = resourceSearch.getSearchParameterMap();
|
SearchParameterMap paramMap = resourceSearch.getSearchParameterMap();
|
||||||
paramMap.setLoadSynchronous(true);
|
paramMap.setLoadSynchronous(true);
|
||||||
|
|
||||||
Set<JpaPid> resourceIds = myMatchResourceUrlService.search(paramMap, myResourceType, theRequest, null);
|
Set<JpaPid> resourceIds = myMatchResourceUrlService.search(paramMap, myResourceType, theRequestDetails, null);
|
||||||
|
|
||||||
if (resourceIds.size() > 1) {
|
if (resourceIds.size() > 1) {
|
||||||
if (!getStorageSettings().isAllowMultipleDelete()) {
|
if (!getStorageSettings().isAllowMultipleDelete()) {
|
||||||
|
@ -713,7 +749,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return deletePidList(theUrl, resourceIds, deleteConflicts, theRequest);
|
return deletePidList(theUrl, resourceIds, deleteConflicts, theRequestDetails, theTransactionDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -733,15 +769,23 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public <P extends IResourcePersistentId> DeleteMethodOutcome deletePidList(String theUrl, Collection<P> theResourceIds, DeleteConflictList theDeleteConflicts, RequestDetails theRequest) {
|
public <P extends IResourcePersistentId> DeleteMethodOutcome deletePidList(String theUrl, Collection<P> theResourceIds, DeleteConflictList theDeleteConflicts, RequestDetails theRequestDetails, TransactionDetails theTransactionDetails) {
|
||||||
StopWatch w = new StopWatch();
|
StopWatch w = new StopWatch();
|
||||||
TransactionDetails transactionDetails = new TransactionDetails();
|
TransactionDetails transactionDetails = new TransactionDetails();
|
||||||
List<ResourceTable> deletedResources = new ArrayList<>();
|
List<ResourceTable> deletedResources = new ArrayList<>();
|
||||||
|
|
||||||
|
List<IResourcePersistentId<?>> resolvedIds = theResourceIds
|
||||||
|
.stream()
|
||||||
|
.map(t -> (IResourcePersistentId<?>) t)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
mySystemDao.preFetchResources(resolvedIds, false);
|
||||||
|
|
||||||
for (P pid : theResourceIds) {
|
for (P pid : theResourceIds) {
|
||||||
JpaPid jpaPid = (JpaPid) pid;
|
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.getId());
|
||||||
deletedResources.add(entity);
|
deletedResources.add(entity);
|
||||||
|
|
||||||
|
@ -750,18 +794,18 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
// Notify IServerOperationInterceptors about pre-action call
|
// Notify IServerOperationInterceptors about pre-action call
|
||||||
HookParams hooks = new HookParams()
|
HookParams hooks = new HookParams()
|
||||||
.add(IBaseResource.class, resourceToDelete)
|
.add(IBaseResource.class, resourceToDelete)
|
||||||
.add(RequestDetails.class, theRequest)
|
.add(RequestDetails.class, theRequestDetails)
|
||||||
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails)
|
||||||
.add(TransactionDetails.class, transactionDetails);
|
.add(TransactionDetails.class, transactionDetails);
|
||||||
doCallHooks(transactionDetails, theRequest, Pointcut.STORAGE_PRESTORAGE_RESOURCE_DELETED, hooks);
|
doCallHooks(transactionDetails, theRequestDetails, Pointcut.STORAGE_PRESTORAGE_RESOURCE_DELETED, hooks);
|
||||||
|
|
||||||
myDeleteConflictService.validateOkToDelete(theDeleteConflicts, entity, false, theRequest, transactionDetails);
|
myDeleteConflictService.validateOkToDelete(theDeleteConflicts, entity, false, theRequestDetails, transactionDetails);
|
||||||
|
|
||||||
// Perform delete
|
// Perform delete
|
||||||
|
|
||||||
preDelete(resourceToDelete, entity, theRequest);
|
preDelete(resourceToDelete, entity, theRequestDetails);
|
||||||
|
|
||||||
updateEntityForDelete(theRequest, transactionDetails, entity);
|
updateEntityForDelete(theRequestDetails, transactionDetails, entity);
|
||||||
resourceToDelete.setId(entity.getIdDt());
|
resourceToDelete.setId(entity.getIdDt());
|
||||||
|
|
||||||
// Notify JPA interceptors
|
// Notify JPA interceptors
|
||||||
|
@ -770,11 +814,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
public void beforeCommit(boolean readOnly) {
|
public void beforeCommit(boolean readOnly) {
|
||||||
HookParams hookParams = new HookParams()
|
HookParams hookParams = new HookParams()
|
||||||
.add(IBaseResource.class, resourceToDelete)
|
.add(IBaseResource.class, resourceToDelete)
|
||||||
.add(RequestDetails.class, theRequest)
|
.add(RequestDetails.class, theRequestDetails)
|
||||||
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails)
|
||||||
.add(TransactionDetails.class, transactionDetails)
|
.add(TransactionDetails.class, transactionDetails)
|
||||||
.add(InterceptorInvocationTimingEnum.class, transactionDetails.getInvocationTiming(Pointcut.STORAGE_PRECOMMIT_RESOURCE_DELETED));
|
.add(InterceptorInvocationTimingEnum.class, transactionDetails.getInvocationTiming(Pointcut.STORAGE_PRECOMMIT_RESOURCE_DELETED));
|
||||||
doCallHooks(transactionDetails, theRequest, Pointcut.STORAGE_PRECOMMIT_RESOURCE_DELETED, hookParams);
|
doCallHooks(transactionDetails, theRequestDetails, Pointcut.STORAGE_PRECOMMIT_RESOURCE_DELETED, hookParams);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -791,6 +835,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
|
|
||||||
ourLog.debug("Processed delete on {} (matched {} resource(s)) in {}ms", theUrl, deletedResources.size(), w.getMillis());
|
ourLog.debug("Processed delete on {} (matched {} resource(s)) in {}ms", theUrl, deletedResources.size(), w.getMillis());
|
||||||
|
|
||||||
|
theTransactionDetails.addDeletedResourceIds(theResourceIds);
|
||||||
|
|
||||||
DeleteMethodOutcome retVal = new DeleteMethodOutcome();
|
DeleteMethodOutcome retVal = new DeleteMethodOutcome();
|
||||||
retVal.setDeletedEntities(deletedResources);
|
retVal.setDeletedEntities(deletedResources);
|
||||||
retVal.setOperationOutcome(oo);
|
retVal.setOperationOutcome(oo);
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
package ca.uhn.fhir.jpa.dao;
|
package ca.uhn.fhir.jpa.dao;
|
||||||
|
|
||||||
import ca.uhn.fhir.i18n.Msg;
|
import ca.uhn.fhir.i18n.Msg;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ public class PersistObservationIndexedSearchParamLastNR4IT {
|
||||||
ResourceTable entity = new ResourceTable();
|
ResourceTable entity = new ResourceTable();
|
||||||
entity.setId(55L);
|
entity.setId(55L);
|
||||||
entity.setResourceType("Observation");
|
entity.setResourceType("Observation");
|
||||||
entity.setVersion(0L);
|
entity.setVersionForUnitTest(0L);
|
||||||
|
|
||||||
testObservationPersist.deleteObservationIndex(entity);
|
testObservationPersist.deleteObservationIndex(entity);
|
||||||
elasticsearchSvc.refreshIndex(ElasticsearchSvcImpl.OBSERVATION_INDEX);
|
elasticsearchSvc.refreshIndex(ElasticsearchSvcImpl.OBSERVATION_INDEX);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -153,10 +153,6 @@ public abstract class BaseHasResource extends BasePartitionable implements IBase
|
||||||
myUpdated = theUpdated;
|
myUpdated = theUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUpdated(InstantDt theUpdated) {
|
|
||||||
myUpdated = theUpdated.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract long getVersion();
|
public abstract long getVersion();
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ import ca.uhn.fhir.jpa.model.search.ResourceTableRoutingBinder;
|
||||||
import ca.uhn.fhir.jpa.model.search.SearchParamTextPropertyBinder;
|
import ca.uhn.fhir.jpa.model.search.SearchParamTextPropertyBinder;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
|
@ -59,6 +60,7 @@ import javax.persistence.Index;
|
||||||
import javax.persistence.NamedEntityGraph;
|
import javax.persistence.NamedEntityGraph;
|
||||||
import javax.persistence.OneToMany;
|
import javax.persistence.OneToMany;
|
||||||
import javax.persistence.OneToOne;
|
import javax.persistence.OneToOne;
|
||||||
|
import javax.persistence.PostPersist;
|
||||||
import javax.persistence.PrePersist;
|
import javax.persistence.PrePersist;
|
||||||
import javax.persistence.PreUpdate;
|
import javax.persistence.PreUpdate;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
|
@ -67,6 +69,7 @@ import javax.persistence.Version;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -83,16 +86,15 @@ import java.util.stream.Collectors;
|
||||||
@NamedEntityGraph(name = "Resource.noJoins")
|
@NamedEntityGraph(name = "Resource.noJoins")
|
||||||
public class ResourceTable extends BaseHasResource implements Serializable, IBasePersistedResource<JpaPid> {
|
public class ResourceTable extends BaseHasResource implements Serializable, IBasePersistedResource<JpaPid> {
|
||||||
public static final int RESTYPE_LEN = 40;
|
public static final int RESTYPE_LEN = 40;
|
||||||
private static final int MAX_LANGUAGE_LENGTH = 20;
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
public static final String HFJ_RESOURCE = "HFJ_RESOURCE";
|
public static final String HFJ_RESOURCE = "HFJ_RESOURCE";
|
||||||
public static final String RES_TYPE = "RES_TYPE";
|
public static final String RES_TYPE = "RES_TYPE";
|
||||||
|
private static final int MAX_LANGUAGE_LENGTH = 20;
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
/**
|
/**
|
||||||
* Holds the narrative text only - Used for Fulltext searching but not directly stored in the DB
|
* Holds the narrative text only - Used for Fulltext searching but not directly stored in the DB
|
||||||
* Note the extra config needed in HS6 for indexing transient props:
|
* Note the extra config needed in HS6 for indexing transient props:
|
||||||
* https://docs.jboss.org/hibernate/search/6.0/migration/html_single/#indexed-transient-requires-configuration
|
* https://docs.jboss.org/hibernate/search/6.0/migration/html_single/#indexed-transient-requires-configuration
|
||||||
*
|
* <p>
|
||||||
* Note that we depend on `myVersion` updated for this field to be indexed.
|
* Note that we depend on `myVersion` updated for this field to be indexed.
|
||||||
*/
|
*/
|
||||||
@Transient
|
@Transient
|
||||||
|
@ -278,18 +280,17 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
@Transient
|
@Transient
|
||||||
private transient boolean myUnchangedInCurrentOperation;
|
private transient boolean myUnchangedInCurrentOperation;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The id of the Resource.
|
* The id of the Resource.
|
||||||
* Will contain either the client-assigned id, or the sequence value.
|
* Will contain either the client-assigned id, or the sequence value.
|
||||||
* Will be null during insert time until the first read.
|
* Will be null during insert time until the first read.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Column(name = "FHIR_ID",
|
@Column(name = "FHIR_ID",
|
||||||
// [A-Za-z0-9\-\.]{1,64} - https://www.hl7.org/fhir/datatypes.html#id
|
// [A-Za-z0-9\-\.]{1,64} - https://www.hl7.org/fhir/datatypes.html#id
|
||||||
length = 64,
|
length = 64,
|
||||||
// we never update this after insert, and the Generator will otherwise "dirty" the object.
|
// we never update this after insert, and the Generator will otherwise "dirty" the object.
|
||||||
updatable = false)
|
updatable = false)
|
||||||
|
|
||||||
// inject the pk for server-assigned sequence ids.
|
// inject the pk for server-assigned sequence ids.
|
||||||
@GeneratorType(when = GenerationTime.INSERT, type = FhirIdGenerator.class)
|
@GeneratorType(when = GenerationTime.INSERT, type = FhirIdGenerator.class)
|
||||||
// Make sure the generator doesn't bump the history version.
|
// Make sure the generator doesn't bump the history version.
|
||||||
|
@ -305,30 +306,21 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
@Column(name = "SEARCH_URL_PRESENT", nullable = true)
|
@Column(name = "SEARCH_URL_PRESENT", nullable = true)
|
||||||
private Boolean mySearchUrlPresent = false;
|
private Boolean mySearchUrlPresent = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* Populate myFhirId with server-assigned sequence id when no client-id provided.
|
|
||||||
* We eat this complexity during insert to simplify query time with a uniform column.
|
|
||||||
* Server-assigned sequence ids aren't available until just before insertion.
|
|
||||||
* Hibernate calls insert Generators after the pk has been assigned, so we can use myId safely here.
|
|
||||||
*/
|
|
||||||
public static final class FhirIdGenerator implements ValueGenerator<String> {
|
|
||||||
@Override
|
|
||||||
public String generateValue(Session session, Object owner) {
|
|
||||||
ResourceTable that = (ResourceTable) owner;
|
|
||||||
return that.myFhirId != null ? that.myFhirId : that.myId.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Version
|
@Version
|
||||||
@Column(name = "RES_VER")
|
@Column(name = "RES_VER")
|
||||||
private long myVersion;
|
private long myVersion;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "myResourceTable", fetch = FetchType.LAZY)
|
@OneToMany(mappedBy = "myResourceTable", fetch = FetchType.LAZY)
|
||||||
private Collection<ResourceHistoryProvenanceEntity> myProvenance;
|
private Collection<ResourceHistoryProvenanceEntity> myProvenance;
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
private transient ResourceHistoryTable myCurrentVersionEntity;
|
private transient ResourceHistoryTable myCurrentVersionEntity;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private transient ResourceHistoryTable myNewVersionEntity;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private transient boolean myVersionUpdatedInCurrentTransaction;
|
||||||
|
|
||||||
@OneToOne(optional = true, fetch = FetchType.EAGER, cascade = {}, orphanRemoval = false, mappedBy = "myResource")
|
@OneToOne(optional = true, fetch = FetchType.EAGER, cascade = {}, orphanRemoval = false, mappedBy = "myResource")
|
||||||
@OptimisticLock(excluded = true)
|
@OptimisticLock(excluded = true)
|
||||||
private ForcedId myForcedId;
|
private ForcedId myForcedId;
|
||||||
|
@ -343,6 +335,39 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setting this flag is an indication that we're making changes and the version number will
|
||||||
|
* be incremented in the current transaction. When this is set, calls to {@link #getVersion()}
|
||||||
|
* will be incremented by one.
|
||||||
|
* This flag is cleared in {@link #postPersist()} since at that time the new version number
|
||||||
|
* should be reflected.
|
||||||
|
*/
|
||||||
|
public void markVersionUpdatedInCurrentTransaction() {
|
||||||
|
if (!myVersionUpdatedInCurrentTransaction) {
|
||||||
|
/*
|
||||||
|
* Note that modifying this number doesn't actually directly affect what
|
||||||
|
* gets stored in the database since this is a @Version field and the
|
||||||
|
* value is therefore managed by Hibernate. So in other words, if the
|
||||||
|
* row in the database is updated, it doesn't matter what we set
|
||||||
|
* this field to, hibernate will increment it by one. However, we still
|
||||||
|
* increment it for two reasons:
|
||||||
|
* 1. The value gets used for the version attribute in the ResourceHistoryTable
|
||||||
|
* entity we create for each new version.
|
||||||
|
* 2. For updates to existing resources, there may actually not be any other
|
||||||
|
* changes to this entity so incrementing this is a signal to
|
||||||
|
* Hibernate that something changed and we need to force an entity
|
||||||
|
* update.
|
||||||
|
*/
|
||||||
|
myVersion++;
|
||||||
|
this.myVersionUpdatedInCurrentTransaction = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostPersist
|
||||||
|
public void postPersist() {
|
||||||
|
myVersionUpdatedInCurrentTransaction = false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResourceTag addTag(TagDefinition theTag) {
|
public ResourceTag addTag(TagDefinition theTag) {
|
||||||
for (ResourceTag next : getTags()) {
|
for (ResourceTag next : getTags()) {
|
||||||
|
@ -355,7 +380,6 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getHashSha256() {
|
public String getHashSha256() {
|
||||||
return myHashSha256;
|
return myHashSha256;
|
||||||
}
|
}
|
||||||
|
@ -558,6 +582,26 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
return myVersion;
|
return myVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the version on this entity to {@literal 1}. This should only be called
|
||||||
|
* on resources that are not yet persisted. After that time the version number
|
||||||
|
* is managed by hibernate.
|
||||||
|
*/
|
||||||
|
public void initializeVersion() {
|
||||||
|
assert myId == null;
|
||||||
|
myVersion = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Don't call this in any JPA environments, the version will be ignored
|
||||||
|
* since this field is managed by hibernate
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
public void setVersionForUnitTest(long theVersion) {
|
||||||
|
myVersion = theVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDeleted() {
|
public boolean isDeleted() {
|
||||||
return getDeleted() != null;
|
return getDeleted() != null;
|
||||||
|
@ -568,10 +612,6 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
setDeleted(null);
|
setDeleted(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVersion(long theVersion) {
|
|
||||||
myVersion = theVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isHasLinks() {
|
public boolean isHasLinks() {
|
||||||
return myHasLinks;
|
return myHasLinks;
|
||||||
}
|
}
|
||||||
|
@ -689,14 +729,14 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
myUnchangedInCurrentOperation = theUnchangedInCurrentOperation;
|
myUnchangedInCurrentOperation = theUnchangedInCurrentOperation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setContentText(String theContentText) {
|
|
||||||
myContentText = theContentText;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getContentText() {
|
public String getContentText() {
|
||||||
return myContentText;
|
return myContentText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setContentText(String theContentText) {
|
||||||
|
myContentText = theContentText;
|
||||||
|
}
|
||||||
|
|
||||||
public void setNarrativeText(String theNarrativeText) {
|
public void setNarrativeText(String theNarrativeText) {
|
||||||
myNarrativeText = theNarrativeText;
|
myNarrativeText = theNarrativeText;
|
||||||
}
|
}
|
||||||
|
@ -709,12 +749,27 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
mySearchUrlPresent = theSearchUrlPresent;
|
mySearchUrlPresent = theSearchUrlPresent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method creates a new history entity, or might reuse the current one if we've
|
||||||
|
* already created one in the current transaction. This is because we can only increment
|
||||||
|
* the version once in a DB transaction (since hibernate manages that number) so creating
|
||||||
|
* multiple {@link ResourceHistoryTable} entities will result in a constraint error.
|
||||||
|
*/
|
||||||
public ResourceHistoryTable toHistory(boolean theCreateVersionTags) {
|
public ResourceHistoryTable toHistory(boolean theCreateVersionTags) {
|
||||||
ResourceHistoryTable retVal = new ResourceHistoryTable();
|
boolean createVersionTags = theCreateVersionTags;
|
||||||
|
|
||||||
|
ResourceHistoryTable retVal = myNewVersionEntity;
|
||||||
|
if (retVal == null) {
|
||||||
|
retVal = new ResourceHistoryTable();
|
||||||
|
myNewVersionEntity = retVal;
|
||||||
|
} else {
|
||||||
|
// Tags should already be set
|
||||||
|
createVersionTags = false;
|
||||||
|
}
|
||||||
|
|
||||||
retVal.setResourceId(myId);
|
retVal.setResourceId(myId);
|
||||||
retVal.setResourceType(myResourceType);
|
retVal.setResourceType(myResourceType);
|
||||||
retVal.setVersion(myVersion);
|
retVal.setVersion(getVersion());
|
||||||
retVal.setTransientForcedId(getTransientForcedId());
|
retVal.setTransientForcedId(getTransientForcedId());
|
||||||
|
|
||||||
retVal.setPublished(getPublishedDate());
|
retVal.setPublished(getPublishedDate());
|
||||||
|
@ -725,10 +780,8 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
retVal.setForcedId(getForcedId());
|
retVal.setForcedId(getForcedId());
|
||||||
retVal.setPartitionId(getPartitionId());
|
retVal.setPartitionId(getPartitionId());
|
||||||
|
|
||||||
retVal.getTags().clear();
|
|
||||||
|
|
||||||
retVal.setHasTags(isHasTags());
|
retVal.setHasTags(isHasTags());
|
||||||
if (isHasTags() && theCreateVersionTags) {
|
if (isHasTags() && createVersionTags) {
|
||||||
for (ResourceTag next : getTags()) {
|
for (ResourceTag next : getTags()) {
|
||||||
retVal.addTag(next);
|
retVal.addTag(next);
|
||||||
}
|
}
|
||||||
|
@ -772,16 +825,16 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
* This is a convenience to avoid loading the version a second time within a single transaction. It is
|
* This is a convenience to avoid loading the version a second time within a single transaction. It is
|
||||||
* not persisted.
|
* not persisted.
|
||||||
*/
|
*/
|
||||||
public void setCurrentVersionEntity(ResourceHistoryTable theCurrentVersionEntity) {
|
public ResourceHistoryTable getCurrentVersionEntity() {
|
||||||
myCurrentVersionEntity = theCurrentVersionEntity;
|
return myCurrentVersionEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a convenience to avoid loading the version a second time within a single transaction. It is
|
* This is a convenience to avoid loading the version a second time within a single transaction. It is
|
||||||
* not persisted.
|
* not persisted.
|
||||||
*/
|
*/
|
||||||
public ResourceHistoryTable getCurrentVersionEntity() {
|
public void setCurrentVersionEntity(ResourceHistoryTable theCurrentVersionEntity) {
|
||||||
return myCurrentVersionEntity;
|
myCurrentVersionEntity = theCurrentVersionEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -799,8 +852,6 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
myForcedId = theForcedId;
|
myForcedId = theForcedId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IdDt getIdDt() {
|
public IdDt getIdDt() {
|
||||||
IdDt retVal = new IdDt();
|
IdDt retVal = new IdDt();
|
||||||
|
@ -808,7 +859,6 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public IIdType getIdType(FhirContext theContext) {
|
public IIdType getIdType(FhirContext theContext) {
|
||||||
IIdType retVal = theContext.getVersion().newIdType();
|
IIdType retVal = theContext.getVersion().newIdType();
|
||||||
populateId(retVal);
|
populateId(retVal);
|
||||||
|
@ -830,14 +880,14 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCreatedByMatchUrl(String theCreatedByMatchUrl) {
|
|
||||||
myCreatedByMatchUrl = theCreatedByMatchUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCreatedByMatchUrl() {
|
public String getCreatedByMatchUrl() {
|
||||||
return myCreatedByMatchUrl;
|
return myCreatedByMatchUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCreatedByMatchUrl(String theCreatedByMatchUrl) {
|
||||||
|
myCreatedByMatchUrl = theCreatedByMatchUrl;
|
||||||
|
}
|
||||||
|
|
||||||
public void setLuceneIndexData(ExtendedHSearchIndexData theLuceneIndexData) {
|
public void setLuceneIndexData(ExtendedHSearchIndexData theLuceneIndexData) {
|
||||||
myLuceneIndexData = theLuceneIndexData;
|
myLuceneIndexData = theLuceneIndexData;
|
||||||
}
|
}
|
||||||
|
@ -862,4 +912,18 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
public void setFhirId(String theFhirId) {
|
public void setFhirId(String theFhirId) {
|
||||||
myFhirId = theFhirId;
|
myFhirId = theFhirId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate myFhirId with server-assigned sequence id when no client-id provided.
|
||||||
|
* We eat this complexity during insert to simplify query time with a uniform column.
|
||||||
|
* Server-assigned sequence ids aren't available until just before insertion.
|
||||||
|
* Hibernate calls insert Generators after the pk has been assigned, so we can use myId safely here.
|
||||||
|
*/
|
||||||
|
public static final class FhirIdGenerator implements ValueGenerator<String> {
|
||||||
|
@Override
|
||||||
|
public String generateValue(Session session, Object owner) {
|
||||||
|
ResourceTable that = (ResourceTable) owner;
|
||||||
|
return that.myFhirId != null ? that.myFhirId : that.myId.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -94,7 +94,7 @@ public class SearchParamRegistryImplTest {
|
||||||
ResourceTable searchParamEntity = new ResourceTable();
|
ResourceTable searchParamEntity = new ResourceTable();
|
||||||
searchParamEntity.setResourceType("SearchParameter");
|
searchParamEntity.setResourceType("SearchParameter");
|
||||||
searchParamEntity.setId(theId);
|
searchParamEntity.setId(theId);
|
||||||
searchParamEntity.setVersion(theVersion);
|
searchParamEntity.setVersionForUnitTest(theVersion);
|
||||||
return searchParamEntity;
|
return searchParamEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ public class SearchParamRegistryImplTest {
|
||||||
|
|
||||||
// Update the resource without changing anything that would affect our cache
|
// Update the resource without changing anything that would affect our cache
|
||||||
ResourceTable lastEntity = newEntities.get(newEntities.size() - 1);
|
ResourceTable lastEntity = newEntities.get(newEntities.size() - 1);
|
||||||
lastEntity.setVersion(2);
|
lastEntity.setVersionForUnitTest(2);
|
||||||
resetMock(Enumerations.PublicationStatus.ACTIVE, newEntities);
|
resetMock(Enumerations.PublicationStatus.ACTIVE, newEntities);
|
||||||
mySearchParamRegistry.requestRefresh();
|
mySearchParamRegistry.requestRefresh();
|
||||||
assertResult(mySearchParamRegistry.refreshCacheIfNecessary(), 0, 1, 0);
|
assertResult(mySearchParamRegistry.refreshCacheIfNecessary(), 0, 1, 0);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -2,7 +2,10 @@ package ca.uhn.fhir.jpa.dao.r4;
|
||||||
|
|
||||||
import ca.uhn.fhir.batch2.api.IJobDataSink;
|
import ca.uhn.fhir.batch2.api.IJobDataSink;
|
||||||
import ca.uhn.fhir.batch2.api.RunOutcome;
|
import ca.uhn.fhir.batch2.api.RunOutcome;
|
||||||
|
import ca.uhn.fhir.batch2.api.VoidModel;
|
||||||
import ca.uhn.fhir.batch2.jobs.chunk.ResourceIdListWorkChunkJson;
|
import ca.uhn.fhir.batch2.jobs.chunk.ResourceIdListWorkChunkJson;
|
||||||
|
import ca.uhn.fhir.batch2.jobs.chunk.TypedPidJson;
|
||||||
|
import ca.uhn.fhir.batch2.jobs.expunge.DeleteExpungeStep;
|
||||||
import ca.uhn.fhir.batch2.jobs.reindex.ReindexJobParameters;
|
import ca.uhn.fhir.batch2.jobs.reindex.ReindexJobParameters;
|
||||||
import ca.uhn.fhir.batch2.jobs.reindex.ReindexStep;
|
import ca.uhn.fhir.batch2.jobs.reindex.ReindexStep;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
@ -10,12 +13,12 @@ import ca.uhn.fhir.context.support.ValidationSupportContext;
|
||||||
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
|
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
|
||||||
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
||||||
import ca.uhn.fhir.jpa.api.dao.ReindexParameters;
|
import ca.uhn.fhir.jpa.api.dao.ReindexParameters;
|
||||||
|
import ca.uhn.fhir.jpa.api.model.DeleteMethodOutcome;
|
||||||
import ca.uhn.fhir.jpa.api.model.HistoryCountModeEnum;
|
import ca.uhn.fhir.jpa.api.model.HistoryCountModeEnum;
|
||||||
import ca.uhn.fhir.jpa.dao.data.ISearchParamPresentDao;
|
import ca.uhn.fhir.jpa.dao.data.ISearchParamPresentDao;
|
||||||
import ca.uhn.fhir.jpa.entity.TermValueSet;
|
import ca.uhn.fhir.jpa.entity.TermValueSet;
|
||||||
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
|
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ForcedId;
|
import ca.uhn.fhir.jpa.model.entity.ForcedId;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
|
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||||
import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test;
|
import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test;
|
||||||
|
@ -98,8 +101,6 @@ import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.empty;
|
import static org.hamcrest.Matchers.empty;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
@ -137,26 +138,28 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
|
||||||
private SubscriptionMatcherInterceptor mySubscriptionMatcherInterceptor;
|
private SubscriptionMatcherInterceptor mySubscriptionMatcherInterceptor;
|
||||||
@Autowired
|
@Autowired
|
||||||
private ReindexStep myReindexStep;
|
private ReindexStep myReindexStep;
|
||||||
|
@Autowired
|
||||||
|
private DeleteExpungeStep myDeleteExpungeStep;
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void afterResetDao() {
|
public void afterResetDao() {
|
||||||
myStorageSettings.setResourceMetaCountHardLimit(new JpaStorageSettings().getResourceMetaCountHardLimit());
|
myStorageSettings.clearSupportedSubscriptionTypesForUnitTest();
|
||||||
myStorageSettings.setIndexMissingFields(new JpaStorageSettings().getIndexMissingFields());
|
myStorageSettings.setAllowMultipleDelete(new JpaStorageSettings().isAllowMultipleDelete());
|
||||||
myStorageSettings.setDeleteEnabled(new JpaStorageSettings().isDeleteEnabled());
|
|
||||||
myStorageSettings.setMatchUrlCacheEnabled(new JpaStorageSettings().isMatchUrlCacheEnabled());
|
|
||||||
myStorageSettings.setHistoryCountMode(JpaStorageSettings.DEFAULT_HISTORY_COUNT_MODE);
|
|
||||||
myStorageSettings.setMassIngestionMode(new JpaStorageSettings().isMassIngestionMode());
|
|
||||||
myStorageSettings.setAutoVersionReferenceAtPaths(new JpaStorageSettings().getAutoVersionReferenceAtPaths());
|
|
||||||
myStorageSettings.setRespectVersionsForSearchIncludes(new JpaStorageSettings().isRespectVersionsForSearchIncludes());
|
|
||||||
myFhirContext.getParserOptions().setStripVersionsFromReferences(true);
|
|
||||||
myStorageSettings.setTagStorageMode(new JpaStorageSettings().getTagStorageMode());
|
|
||||||
myStorageSettings.setAutoCreatePlaceholderReferenceTargets(new JpaStorageSettings().isAutoCreatePlaceholderReferenceTargets());
|
myStorageSettings.setAutoCreatePlaceholderReferenceTargets(new JpaStorageSettings().isAutoCreatePlaceholderReferenceTargets());
|
||||||
|
myStorageSettings.setAutoVersionReferenceAtPaths(new JpaStorageSettings().getAutoVersionReferenceAtPaths());
|
||||||
|
myStorageSettings.setDeleteEnabled(new JpaStorageSettings().isDeleteEnabled());
|
||||||
|
myStorageSettings.setHistoryCountMode(JpaStorageSettings.DEFAULT_HISTORY_COUNT_MODE);
|
||||||
|
myStorageSettings.setIndexMissingFields(new JpaStorageSettings().getIndexMissingFields());
|
||||||
|
myStorageSettings.setInlineResourceTextBelowSize(new JpaStorageSettings().getInlineResourceTextBelowSize());
|
||||||
|
myStorageSettings.setMassIngestionMode(new JpaStorageSettings().isMassIngestionMode());
|
||||||
|
myStorageSettings.setMatchUrlCacheEnabled(new JpaStorageSettings().isMatchUrlCacheEnabled());
|
||||||
myStorageSettings.setPopulateIdentifierInAutoCreatedPlaceholderReferenceTargets(new JpaStorageSettings().isPopulateIdentifierInAutoCreatedPlaceholderReferenceTargets());
|
myStorageSettings.setPopulateIdentifierInAutoCreatedPlaceholderReferenceTargets(new JpaStorageSettings().isPopulateIdentifierInAutoCreatedPlaceholderReferenceTargets());
|
||||||
myStorageSettings.setResourceClientIdStrategy(new JpaStorageSettings().getResourceClientIdStrategy());
|
myStorageSettings.setResourceClientIdStrategy(new JpaStorageSettings().getResourceClientIdStrategy());
|
||||||
|
myStorageSettings.setResourceMetaCountHardLimit(new JpaStorageSettings().getResourceMetaCountHardLimit());
|
||||||
|
myStorageSettings.setRespectVersionsForSearchIncludes(new JpaStorageSettings().isRespectVersionsForSearchIncludes());
|
||||||
myStorageSettings.setTagStorageMode(new JpaStorageSettings().getTagStorageMode());
|
myStorageSettings.setTagStorageMode(new JpaStorageSettings().getTagStorageMode());
|
||||||
myStorageSettings.setInlineResourceTextBelowSize(new JpaStorageSettings().getInlineResourceTextBelowSize());
|
|
||||||
myStorageSettings.clearSupportedSubscriptionTypesForUnitTest();
|
|
||||||
|
|
||||||
|
myFhirContext.getParserOptions().setStripVersionsFromReferences(true);
|
||||||
TermReadSvcImpl.setForceDisableHibernateSearchForUnitTest(false);
|
TermReadSvcImpl.setForceDisableHibernateSearchForUnitTest(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,7 +421,6 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See the class javadoc before changing the counts in this test!
|
* See the class javadoc before changing the counts in this test!
|
||||||
*/
|
*/
|
||||||
|
@ -452,7 +454,6 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See the class javadoc before changing the counts in this test!
|
* See the class javadoc before changing the counts in this test!
|
||||||
*/
|
*/
|
||||||
|
@ -478,7 +479,6 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
|
||||||
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
|
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See the class javadoc before changing the counts in this test!
|
* See the class javadoc before changing the counts in this test!
|
||||||
*/
|
*/
|
||||||
|
@ -533,7 +533,6 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
|
||||||
assertEquals(0, myCaptureQueriesListener.getCommitCount());
|
assertEquals(0, myCaptureQueriesListener.getCommitCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See the class javadoc before changing the counts in this test!
|
* See the class javadoc before changing the counts in this test!
|
||||||
*/
|
*/
|
||||||
|
@ -559,7 +558,6 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
|
||||||
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
|
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See the class javadoc before changing the counts in this test!
|
* See the class javadoc before changing the counts in this test!
|
||||||
*/
|
*/
|
||||||
|
@ -650,7 +648,6 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See the class javadoc before changing the counts in this test!
|
* See the class javadoc before changing the counts in this test!
|
||||||
*/
|
*/
|
||||||
|
@ -740,6 +737,62 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
|
||||||
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
|
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteMultiple() {
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
createPatient(withId("PT" + i), withActiveTrue(), withIdentifier("http://foo", "id" + i), withFamily("Family" + i));
|
||||||
|
}
|
||||||
|
|
||||||
|
myStorageSettings.setAllowMultipleDelete(true);
|
||||||
|
|
||||||
|
// Test
|
||||||
|
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
DeleteMethodOutcome outcome = myPatientDao.deleteByUrl("Patient?active=true", new SystemRequestDetails());
|
||||||
|
|
||||||
|
// Validate
|
||||||
|
assertEquals(13, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
|
assertEquals(10, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
||||||
|
assertEquals(10, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
||||||
|
assertEquals(30, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||||
|
assertEquals(10, outcome.getDeletedEntities().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteExpungeStep() {
|
||||||
|
// Setup
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
createPatient(
|
||||||
|
withId("PT" + i),
|
||||||
|
withActiveTrue(),
|
||||||
|
withIdentifier("http://foo", "id" + i),
|
||||||
|
withFamily("Family" + i),
|
||||||
|
withTag("http://foo", "blah"));
|
||||||
|
}
|
||||||
|
List<TypedPidJson> pids = runInTransaction(() -> myForcedIdDao
|
||||||
|
.findAll()
|
||||||
|
.stream()
|
||||||
|
.map(t -> new TypedPidJson(t.getResourceType(), Long.toString(t.getResourceId())))
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
|
||||||
|
runInTransaction(()-> assertEquals(10, myResourceTableDao.count()));
|
||||||
|
|
||||||
|
IJobDataSink<VoidModel> sink = mock(IJobDataSink.class);
|
||||||
|
|
||||||
|
// Test
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
RunOutcome outcome = myDeleteExpungeStep.doDeleteExpunge(new ResourceIdListWorkChunkJson(pids), sink, "instance-id", "chunk-id");
|
||||||
|
|
||||||
|
// Verify
|
||||||
|
assertEquals(1, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
||||||
|
assertEquals(29, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||||
|
assertEquals(10, outcome.getRecordsProcessed());
|
||||||
|
runInTransaction(()-> assertEquals(0, myResourceTableDao.count()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See the class javadoc before changing the counts in this test!
|
* See the class javadoc before changing the counts in this test!
|
||||||
*/
|
*/
|
||||||
|
@ -3185,6 +3238,8 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
|
||||||
return (Bundle) bb.getBundle();
|
return (Bundle) bb.getBundle();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Pass 1
|
||||||
|
|
||||||
myCaptureQueriesListener.clear();
|
myCaptureQueriesListener.clear();
|
||||||
mySystemDao.transaction(new SystemRequestDetails(), supplier.get());
|
mySystemDao.transaction(new SystemRequestDetails(), supplier.get());
|
||||||
assertEquals(2, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
assertEquals(2, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
|
@ -3192,13 +3247,55 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
|
||||||
assertEquals(1, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
assertEquals(1, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
||||||
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||||
|
|
||||||
|
// Pass 2
|
||||||
|
|
||||||
myCaptureQueriesListener.clear();
|
myCaptureQueriesListener.clear();
|
||||||
mySystemDao.transaction(new SystemRequestDetails(), supplier.get());
|
Bundle outcome = mySystemDao.transaction(new SystemRequestDetails(), supplier.get());
|
||||||
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
|
|
||||||
assertEquals(8, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
assertEquals(8, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
|
myCaptureQueriesListener.logInsertQueries();
|
||||||
assertEquals(4, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
assertEquals(4, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
||||||
assertEquals(7, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
assertEquals(7, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
||||||
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||||
|
|
||||||
|
ourLog.info(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
|
||||||
|
IdType patientId = new IdType(outcome.getEntry().get(1).getResponse().getLocation());
|
||||||
|
assertEquals("2", patientId.getVersionIdPart());
|
||||||
|
|
||||||
|
Patient patient = myPatientDao.read(patientId, mySrd);
|
||||||
|
assertEquals(1, patient.getMeta().getProfile().size());
|
||||||
|
assertEquals("http://foo", patient.getMeta().getProfile().get(0).getValue());
|
||||||
|
assertEquals("SMITH", patient.getNameFirstRep().getFamily());
|
||||||
|
patient = myPatientDao.read(patientId.withVersion("1"), mySrd);
|
||||||
|
assertEquals(1, patient.getMeta().getProfile().size());
|
||||||
|
assertEquals("http://foo", patient.getMeta().getProfile().get(0).getValue());
|
||||||
|
assertEquals("SMITH", patient.getNameFirstRep().getFamily());
|
||||||
|
|
||||||
|
// Pass 3
|
||||||
|
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
outcome = mySystemDao.transaction(new SystemRequestDetails(), supplier.get());
|
||||||
|
assertEquals(8, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||||
|
myCaptureQueriesListener.logInsertQueries();
|
||||||
|
assertEquals(4, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
|
||||||
|
assertEquals(6, myCaptureQueriesListener.countUpdateQueriesForCurrentThread());
|
||||||
|
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||||
|
|
||||||
|
ourLog.info(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
|
||||||
|
patientId = new IdType(outcome.getEntry().get(1).getResponse().getLocation());
|
||||||
|
assertEquals("3", patientId.getVersionIdPart());
|
||||||
|
|
||||||
|
patient = myPatientDao.read(patientId, mySrd);
|
||||||
|
assertEquals(1, patient.getMeta().getProfile().size());
|
||||||
|
assertEquals("http://foo", patient.getMeta().getProfile().get(0).getValue());
|
||||||
|
assertEquals("SMITH", patient.getNameFirstRep().getFamily());
|
||||||
|
patient = myPatientDao.read(patientId.withVersion("2"), mySrd);
|
||||||
|
assertEquals(1, patient.getMeta().getProfile().size());
|
||||||
|
assertEquals("http://foo", patient.getMeta().getProfile().get(0).getValue());
|
||||||
|
assertEquals("SMITH", patient.getNameFirstRep().getFamily());
|
||||||
|
patient = myPatientDao.read(patientId.withVersion("1"), mySrd);
|
||||||
|
assertEquals(1, patient.getMeta().getProfile().size());
|
||||||
|
assertEquals("http://foo", patient.getMeta().getProfile().get(0).getValue());
|
||||||
|
assertEquals("SMITH", patient.getNameFirstRep().getFamily());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3206,7 +3303,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
|
||||||
* See the class javadoc before changing the counts in this test!
|
* See the class javadoc before changing the counts in this test!
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testMassIngestionMode_TransactionWithChanges_2() throws IOException {
|
public void testMassIngestionMode_TransactionWithChanges_NonVersionedTags() throws IOException {
|
||||||
myStorageSettings.setDeleteEnabled(false);
|
myStorageSettings.setDeleteEnabled(false);
|
||||||
myStorageSettings.setMatchUrlCacheEnabled(true);
|
myStorageSettings.setMatchUrlCacheEnabled(true);
|
||||||
myStorageSettings.setMassIngestionMode(true);
|
myStorageSettings.setMassIngestionMode(true);
|
||||||
|
|
|
@ -100,6 +100,9 @@ public class FhirResourceDaoR4TagsInlineTest extends BaseResourceProviderR4Test
|
||||||
mySearchParameterDao.update(searchParameter, mySrd);
|
mySearchParameterDao.update(searchParameter, mySrd);
|
||||||
mySearchParamRegistry.forceRefresh();
|
mySearchParamRegistry.forceRefresh();
|
||||||
|
|
||||||
|
logAllResources();
|
||||||
|
logAllResourceVersions();
|
||||||
|
|
||||||
createPatientsForInlineSearchTests();
|
createPatientsForInlineSearchTests();
|
||||||
|
|
||||||
logAllTokenIndexes();
|
logAllTokenIndexes();
|
||||||
|
|
|
@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.delete.job;
|
||||||
import ca.uhn.fhir.batch2.api.IJobCoordinator;
|
import ca.uhn.fhir.batch2.api.IJobCoordinator;
|
||||||
import ca.uhn.fhir.batch2.jobs.expunge.DeleteExpungeAppCtx;
|
import ca.uhn.fhir.batch2.jobs.expunge.DeleteExpungeAppCtx;
|
||||||
import ca.uhn.fhir.batch2.jobs.expunge.DeleteExpungeJobParameters;
|
import ca.uhn.fhir.batch2.jobs.expunge.DeleteExpungeJobParameters;
|
||||||
|
import ca.uhn.fhir.batch2.model.JobInstance;
|
||||||
import ca.uhn.fhir.batch2.model.JobInstanceStartRequest;
|
import ca.uhn.fhir.batch2.model.JobInstanceStartRequest;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.batch.models.Batch2JobStartResponse;
|
import ca.uhn.fhir.jpa.batch.models.Batch2JobStartResponse;
|
||||||
|
|
|
@ -254,7 +254,7 @@ public class ReindexJobTest extends BaseJpaR4Test {
|
||||||
resource.setDeleted(currentDate);
|
resource.setDeleted(currentDate);
|
||||||
resource.setUpdated(currentDate);
|
resource.setUpdated(currentDate);
|
||||||
resource.setHashSha256(null);
|
resource.setHashSha256(null);
|
||||||
resource.setVersion(2L);
|
resource.setVersionForUnitTest(2L);
|
||||||
myResourceTableDao.save(resource);
|
myResourceTableDao.save(resource);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package ca.uhn.fhir.jpa.dao.r5;
|
package ca.uhn.fhir.jpa.dao.r5;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||||
import ca.uhn.fhir.util.BundleBuilder;
|
import ca.uhn.fhir.util.BundleBuilder;
|
||||||
import org.hl7.fhir.r5.model.BooleanType;
|
import org.hl7.fhir.r5.model.BooleanType;
|
||||||
import org.hl7.fhir.r5.model.Bundle;
|
import org.hl7.fhir.r5.model.Bundle;
|
||||||
|
@ -12,15 +14,22 @@ import org.hl7.fhir.r5.model.Patient;
|
||||||
import org.hl7.fhir.r5.model.Quantity;
|
import org.hl7.fhir.r5.model.Quantity;
|
||||||
import org.hl7.fhir.r5.model.Reference;
|
import org.hl7.fhir.r5.model.Reference;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.CsvSource;
|
import org.junit.jupiter.params.provider.CsvSource;
|
||||||
import org.junit.jupiter.params.provider.ValueSource;
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.countMatches;
|
import static org.apache.commons.lang3.StringUtils.countMatches;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.endsWith;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
public class FhirSystemDaoTransactionR5Test extends BaseJpaR5Test {
|
public class FhirSystemDaoTransactionR5Test extends BaseJpaR5Test {
|
||||||
|
|
||||||
|
@ -30,6 +39,7 @@ public class FhirSystemDaoTransactionR5Test extends BaseJpaR5Test {
|
||||||
myStorageSettings.setIndexMissingFields(defaults.getIndexMissingFields());
|
myStorageSettings.setIndexMissingFields(defaults.getIndexMissingFields());
|
||||||
myStorageSettings.setMatchUrlCacheEnabled(defaults.isMatchUrlCacheEnabled());
|
myStorageSettings.setMatchUrlCacheEnabled(defaults.isMatchUrlCacheEnabled());
|
||||||
myStorageSettings.setDeleteEnabled(defaults.isDeleteEnabled());
|
myStorageSettings.setDeleteEnabled(defaults.isDeleteEnabled());
|
||||||
|
myStorageSettings.setInlineResourceTextBelowSize(defaults.getInlineResourceTextBelowSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -435,6 +445,248 @@ public class FhirSystemDaoTransactionR5Test extends BaseJpaR5Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a conditional delete and conditional update are both used on the same condition,
|
||||||
|
* the update should win.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testConditionalDeleteAndConditionalUpdateOnSameResource() {
|
||||||
|
Bundle outcome;
|
||||||
|
Patient actual;
|
||||||
|
|
||||||
|
// First pass (resource doesn't already exist)
|
||||||
|
|
||||||
|
outcome = mySystemDao.transaction(mySrd, createBundleWithConditionalDeleteAndConditionalUpdateOnSameResource(myFhirContext));
|
||||||
|
assertEquals(null, outcome.getEntry().get(0).getResponse().getLocation());
|
||||||
|
assertEquals("204 No Content", outcome.getEntry().get(0).getResponse().getStatus());
|
||||||
|
assertThat(outcome.getEntry().get(1).getResponse().getLocation(), endsWith("_history/1"));
|
||||||
|
assertEquals("201 Created", outcome.getEntry().get(1).getResponse().getStatus());
|
||||||
|
|
||||||
|
IdType resourceId = new IdType(outcome.getEntry().get(1).getResponse().getLocation()).toUnqualifiedVersionless();
|
||||||
|
actual = myPatientDao.read(resourceId, mySrd);
|
||||||
|
assertEquals("1", actual.getIdElement().getVersionIdPart());
|
||||||
|
assertEquals("http://foo", actual.getIdentifierFirstRep().getSystem());
|
||||||
|
assertEquals("http://tag", actual.getMeta().getTagFirstRep().getSystem());
|
||||||
|
|
||||||
|
// Second pass (resource already exists)
|
||||||
|
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
outcome = mySystemDao.transaction(mySrd, createBundleWithConditionalDeleteAndConditionalUpdateOnSameResource(myFhirContext));
|
||||||
|
myCaptureQueriesListener.logUpdateQueries();
|
||||||
|
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
|
||||||
|
assertEquals(null, outcome.getEntry().get(0).getResponse().getLocation());
|
||||||
|
assertEquals("204 No Content", outcome.getEntry().get(0).getResponse().getStatus());
|
||||||
|
assertThat(outcome.getEntry().get(1).getResponse().getLocation(), endsWith("_history/2"));
|
||||||
|
assertEquals("201 Created", outcome.getEntry().get(1).getResponse().getStatus());
|
||||||
|
|
||||||
|
logAllResources();
|
||||||
|
logAllResourceVersions();
|
||||||
|
|
||||||
|
actual = myPatientDao.read(resourceId, mySrd);
|
||||||
|
assertEquals("2", actual.getIdElement().getVersionIdPart());
|
||||||
|
assertEquals("http://foo", actual.getIdentifierFirstRep().getSystem());
|
||||||
|
assertEquals("http://tag", actual.getMeta().getTagFirstRep().getSystem());
|
||||||
|
|
||||||
|
// Third pass (resource already exists)
|
||||||
|
|
||||||
|
outcome = mySystemDao.transaction(mySrd, createBundleWithConditionalDeleteAndConditionalUpdateOnSameResource(myFhirContext));
|
||||||
|
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
|
||||||
|
assertEquals(null, outcome.getEntry().get(0).getResponse().getLocation());
|
||||||
|
assertEquals("204 No Content", outcome.getEntry().get(0).getResponse().getStatus());
|
||||||
|
assertThat(outcome.getEntry().get(1).getResponse().getLocation(), endsWith("_history/3"));
|
||||||
|
assertEquals("201 Created", outcome.getEntry().get(1).getResponse().getStatus());
|
||||||
|
|
||||||
|
actual = myPatientDao.read(resourceId, mySrd);
|
||||||
|
assertEquals("3", actual.getIdElement().getVersionIdPart());
|
||||||
|
assertEquals("http://foo", actual.getIdentifierFirstRep().getSystem());
|
||||||
|
assertEquals("http://tag", actual.getMeta().getTagFirstRep().getSystem());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConditionalDeleteAndConditionalUpdateOnSameResource_MultipleMatchesAlreadyExist() {
|
||||||
|
|
||||||
|
// Setup
|
||||||
|
|
||||||
|
myPatientDao.create(createPatientWithIdentifierAndTag(), mySrd);
|
||||||
|
myPatientDao.create(createPatientWithIdentifierAndTag(), mySrd);
|
||||||
|
|
||||||
|
// Test
|
||||||
|
|
||||||
|
try {
|
||||||
|
mySystemDao.transaction(mySrd, createBundleWithConditionalDeleteAndConditionalUpdateOnSameResource(myFhirContext));
|
||||||
|
fail();
|
||||||
|
} catch (PreconditionFailedException e) {
|
||||||
|
|
||||||
|
// Verify
|
||||||
|
assertThat(e.getMessage(), containsString("Multiple resources match this search"));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a conditional delete and conditional update are both used on the same condition,
|
||||||
|
* the update should win.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testConditionalDeleteAndConditionalCreateOnSameResource() {
|
||||||
|
Bundle outcome;
|
||||||
|
Patient actual;
|
||||||
|
|
||||||
|
// First pass (resource doesn't already exist)
|
||||||
|
|
||||||
|
outcome = mySystemDao.transaction(mySrd, createBundleWithConditionalDeleteAndConditionalCreateOnSameResource(myFhirContext));
|
||||||
|
assertEquals(null, outcome.getEntry().get(0).getResponse().getLocation());
|
||||||
|
assertEquals("204 No Content", outcome.getEntry().get(0).getResponse().getStatus());
|
||||||
|
assertThat(outcome.getEntry().get(1).getResponse().getLocation(), endsWith("_history/1"));
|
||||||
|
assertEquals("201 Created", outcome.getEntry().get(1).getResponse().getStatus());
|
||||||
|
|
||||||
|
IdType resourceId = new IdType(outcome.getEntry().get(1).getResponse().getLocation()).toUnqualifiedVersionless();
|
||||||
|
actual = myPatientDao.read(resourceId, mySrd);
|
||||||
|
assertEquals("1", actual.getIdElement().getVersionIdPart());
|
||||||
|
assertEquals("http://foo", actual.getIdentifierFirstRep().getSystem());
|
||||||
|
assertEquals("http://tag", actual.getMeta().getTagFirstRep().getSystem());
|
||||||
|
|
||||||
|
// Second pass (resource already exists)
|
||||||
|
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
outcome = mySystemDao.transaction(mySrd, createBundleWithConditionalDeleteAndConditionalCreateOnSameResource(myFhirContext));
|
||||||
|
myCaptureQueriesListener.logUpdateQueries();
|
||||||
|
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
|
||||||
|
assertEquals(null, outcome.getEntry().get(0).getResponse().getLocation());
|
||||||
|
assertEquals("204 No Content", outcome.getEntry().get(0).getResponse().getStatus());
|
||||||
|
assertThat(outcome.getEntry().get(1).getResponse().getLocation(), endsWith("_history/1"));
|
||||||
|
assertEquals("201 Created", outcome.getEntry().get(1).getResponse().getStatus());
|
||||||
|
|
||||||
|
logAllResources();
|
||||||
|
logAllResourceVersions();
|
||||||
|
|
||||||
|
IdType resourceId2 = new IdType(outcome.getEntry().get(1).getResponse().getLocation()).toUnqualifiedVersionless();
|
||||||
|
assertNotEquals(resourceId.getIdPart(), resourceId2.getIdPart());
|
||||||
|
actual = myPatientDao.read(resourceId2, mySrd);
|
||||||
|
assertEquals("1", actual.getIdElement().getVersionIdPart());
|
||||||
|
assertEquals("http://foo", actual.getIdentifierFirstRep().getSystem());
|
||||||
|
assertEquals("http://tag", actual.getMeta().getTagFirstRep().getSystem());
|
||||||
|
|
||||||
|
// Third pass (resource already exists)
|
||||||
|
|
||||||
|
outcome = mySystemDao.transaction(mySrd, createBundleWithConditionalDeleteAndConditionalCreateOnSameResource(myFhirContext));
|
||||||
|
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
|
||||||
|
assertEquals(null, outcome.getEntry().get(0).getResponse().getLocation());
|
||||||
|
assertEquals("204 No Content", outcome.getEntry().get(0).getResponse().getStatus());
|
||||||
|
assertThat(outcome.getEntry().get(1).getResponse().getLocation(), endsWith("_history/1"));
|
||||||
|
assertEquals("201 Created", outcome.getEntry().get(1).getResponse().getStatus());
|
||||||
|
|
||||||
|
IdType resourceId3 = new IdType(outcome.getEntry().get(1).getResponse().getLocation()).toUnqualifiedVersionless();
|
||||||
|
assertNotEquals(resourceId2.getIdPart(), resourceId3.getIdPart());
|
||||||
|
actual = myPatientDao.read(resourceId3, mySrd);
|
||||||
|
assertEquals("1", actual.getIdElement().getVersionIdPart());
|
||||||
|
assertEquals("http://foo", actual.getIdentifierFirstRep().getSystem());
|
||||||
|
assertEquals("http://tag", actual.getMeta().getTagFirstRep().getSystem());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* There's not much point to deleting and updating the same resource in a
|
||||||
|
* transaction, but let's make sure we at least don't end up in a bad state
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testDeleteAndUpdateOnSameResource() {
|
||||||
|
|
||||||
|
Bundle outcome;
|
||||||
|
Patient actual;
|
||||||
|
|
||||||
|
// First pass (resource doesn't already exist)
|
||||||
|
|
||||||
|
outcome = mySystemDao.transaction(mySrd, createBundleWithDeleteAndUpdateOnSameResource(myFhirContext));
|
||||||
|
assertEquals(null, outcome.getEntry().get(0).getResponse().getLocation());
|
||||||
|
assertEquals("204 No Content", outcome.getEntry().get(0).getResponse().getStatus());
|
||||||
|
assertEquals("Patient/P/_history/1", outcome.getEntry().get(1).getResponse().getLocation());
|
||||||
|
assertEquals("201 Created", outcome.getEntry().get(1).getResponse().getStatus());
|
||||||
|
|
||||||
|
IdType resourceId = new IdType(outcome.getEntry().get(1).getResponse().getLocation()).toUnqualifiedVersionless();
|
||||||
|
actual = myPatientDao.read(resourceId, mySrd);
|
||||||
|
assertEquals("1", actual.getIdElement().getVersionIdPart());
|
||||||
|
assertEquals("http://foo", actual.getIdentifierFirstRep().getSystem());
|
||||||
|
assertEquals("http://tag", actual.getMeta().getTagFirstRep().getSystem());
|
||||||
|
|
||||||
|
// Second pass (resource already exists)
|
||||||
|
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
outcome = mySystemDao.transaction(mySrd, createBundleWithDeleteAndUpdateOnSameResource(myFhirContext));
|
||||||
|
myCaptureQueriesListener.logUpdateQueries();
|
||||||
|
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
|
||||||
|
assertEquals("Patient/P/_history/2", outcome.getEntry().get(0).getResponse().getLocation());
|
||||||
|
assertEquals("204 No Content", outcome.getEntry().get(0).getResponse().getStatus());
|
||||||
|
assertEquals("Patient/P/_history/2", outcome.getEntry().get(1).getResponse().getLocation());
|
||||||
|
assertEquals("201 Created", outcome.getEntry().get(1).getResponse().getStatus());
|
||||||
|
|
||||||
|
logAllResources();
|
||||||
|
logAllResourceVersions();
|
||||||
|
|
||||||
|
actual = myPatientDao.read(resourceId, mySrd);
|
||||||
|
assertEquals("2", actual.getIdElement().getVersionIdPart());
|
||||||
|
assertEquals("http://foo", actual.getIdentifierFirstRep().getSystem());
|
||||||
|
assertEquals("http://tag", actual.getMeta().getTagFirstRep().getSystem());
|
||||||
|
|
||||||
|
// Third pass (resource already exists)
|
||||||
|
|
||||||
|
outcome = mySystemDao.transaction(mySrd, createBundleWithDeleteAndUpdateOnSameResource(myFhirContext));
|
||||||
|
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
|
||||||
|
assertEquals("Patient/P/_history/3", outcome.getEntry().get(0).getResponse().getLocation());
|
||||||
|
assertEquals("204 No Content", outcome.getEntry().get(0).getResponse().getStatus());
|
||||||
|
assertEquals("Patient/P/_history/3", outcome.getEntry().get(1).getResponse().getLocation());
|
||||||
|
assertEquals("201 Created", outcome.getEntry().get(1).getResponse().getStatus());
|
||||||
|
|
||||||
|
actual = myPatientDao.read(resourceId, mySrd);
|
||||||
|
assertEquals("3", actual.getIdElement().getVersionIdPart());
|
||||||
|
assertEquals("http://foo", actual.getIdentifierFirstRep().getSystem());
|
||||||
|
assertEquals("http://tag", actual.getMeta().getTagFirstRep().getSystem());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private static Bundle createBundleWithConditionalDeleteAndConditionalUpdateOnSameResource(FhirContext theFhirContext) {
|
||||||
|
// Build a new bundle each time we need it
|
||||||
|
BundleBuilder bb = new BundleBuilder(theFhirContext);
|
||||||
|
bb.addTransactionDeleteConditionalEntry("Patient?identifier=http://foo|bar");
|
||||||
|
|
||||||
|
Patient patient = createPatientWithIdentifierAndTag();
|
||||||
|
bb.addTransactionUpdateEntry(patient).conditional("Patient?identifier=http://foo|bar");
|
||||||
|
return bb.getBundleTyped();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private static Bundle createBundleWithConditionalDeleteAndConditionalCreateOnSameResource(FhirContext theFhirContext) {
|
||||||
|
// Build a new bundle each time we need it
|
||||||
|
BundleBuilder bb = new BundleBuilder(theFhirContext);
|
||||||
|
bb.addTransactionDeleteConditionalEntry("Patient?identifier=http://foo|bar");
|
||||||
|
|
||||||
|
Patient patient = createPatientWithIdentifierAndTag();
|
||||||
|
patient.setId((String)null);
|
||||||
|
bb.addTransactionCreateEntry(patient).conditional("Patient?identifier=http://foo|bar");
|
||||||
|
return bb.getBundleTyped();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private static Bundle createBundleWithDeleteAndUpdateOnSameResource(FhirContext theFhirContext) {
|
||||||
|
// Build a new bundle each time we need it
|
||||||
|
BundleBuilder bb = new BundleBuilder(theFhirContext);
|
||||||
|
bb.addTransactionDeleteEntry(new IdType("Patient/P"));
|
||||||
|
bb.addTransactionUpdateEntry(createPatientWithIdentifierAndTag());
|
||||||
|
return bb.getBundleTyped();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private static Patient createPatientWithIdentifierAndTag() {
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.setId("Patient/P");
|
||||||
|
patient.getMeta().addTag("http://tag", "tag-code", "tag-display");
|
||||||
|
patient.addIdentifier().setSystem("http://foo").setValue("bar");
|
||||||
|
return patient;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -33,13 +33,7 @@ import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,6 +56,7 @@ public class TransactionDetails {
|
||||||
private Map<String, IResourcePersistentId> myResolvedResourceIds = Collections.emptyMap();
|
private Map<String, IResourcePersistentId> myResolvedResourceIds = Collections.emptyMap();
|
||||||
private Map<String, IResourcePersistentId> myResolvedMatchUrls = Collections.emptyMap();
|
private Map<String, IResourcePersistentId> myResolvedMatchUrls = Collections.emptyMap();
|
||||||
private Map<String, Supplier<IBaseResource>> myResolvedResources = Collections.emptyMap();
|
private Map<String, Supplier<IBaseResource>> myResolvedResources = Collections.emptyMap();
|
||||||
|
private Set<IResourcePersistentId> myDeletedResourceIds = Collections.emptySet();
|
||||||
private Map<String, Object> myUserData;
|
private Map<String, Object> myUserData;
|
||||||
private ListMultimap<Pointcut, HookParams> myDeferredInterceptorBroadcasts;
|
private ListMultimap<Pointcut, HookParams> myDeferredInterceptorBroadcasts;
|
||||||
private EnumSet<Pointcut> myDeferredInterceptorBroadcastPointcuts;
|
private EnumSet<Pointcut> myDeferredInterceptorBroadcastPointcuts;
|
||||||
|
@ -114,6 +109,34 @@ public class TransactionDetails {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 6.8.0
|
||||||
|
*/
|
||||||
|
public void addDeletedResourceId(@Nonnull IResourcePersistentId theResourceId) {
|
||||||
|
Validate.notNull(theResourceId, "theResourceId must not be null");
|
||||||
|
if (myDeletedResourceIds.isEmpty()) {
|
||||||
|
myDeletedResourceIds = new HashSet<>();
|
||||||
|
}
|
||||||
|
myDeletedResourceIds.add(theResourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 6.8.0
|
||||||
|
*/
|
||||||
|
public void addDeletedResourceIds(Collection<? extends IResourcePersistentId> theResourceIds) {
|
||||||
|
for (IResourcePersistentId<?> next : theResourceIds) {
|
||||||
|
addDeletedResourceId(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 6.8.0
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public Set<IResourcePersistentId> getDeletedResourceIds() {
|
||||||
|
return Collections.unmodifiableSet(myDeletedResourceIds);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A <b>Resolved Resource ID</b> is a mapping between a resource ID (e.g. "<code>Patient/ABC</code>" or
|
* A <b>Resolved Resource ID</b> is a mapping between a resource ID (e.g. "<code>Patient/ABC</code>" or
|
||||||
* "<code>Observation/123</code>") and a storage ID for that resource. Resources should only be placed within
|
* "<code>Observation/123</code>") and a storage ID for that resource. Resources should only be placed within
|
||||||
|
@ -223,6 +246,15 @@ public class TransactionDetails {
|
||||||
myResolvedMatchUrls.put(theConditionalUrl, thePersistentId);
|
myResolvedMatchUrls.put(theConditionalUrl, thePersistentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 6.8.0
|
||||||
|
* @see #addResolvedMatchUrl(FhirContext, String, IResourcePersistentId)
|
||||||
|
*/
|
||||||
|
public void removeResolvedMatchUrl(String theMatchUrl) {
|
||||||
|
myResolvedMatchUrls.remove(theMatchUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private boolean matchUrlWithDiffIdExists(String theConditionalUrl, @Nonnull IResourcePersistentId thePersistentId) {
|
private boolean matchUrlWithDiffIdExists(String theConditionalUrl, @Nonnull IResourcePersistentId thePersistentId) {
|
||||||
if (myResolvedMatchUrls.containsKey(theConditionalUrl) && myResolvedMatchUrls.get(theConditionalUrl) != NOT_FOUND) {
|
if (myResolvedMatchUrls.containsKey(theConditionalUrl) && myResolvedMatchUrls.get(theConditionalUrl) != NOT_FOUND) {
|
||||||
return myResolvedMatchUrls.get(theConditionalUrl).getId() != thePersistentId.getId();
|
return myResolvedMatchUrls.get(theConditionalUrl).getId() != thePersistentId.getId();
|
||||||
|
@ -359,13 +391,13 @@ public class TransactionDetails {
|
||||||
return !myResolvedResourceIds.isEmpty();
|
return !myResolvedResourceIds.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFhirTransaction(boolean theFhirTransaction) {
|
|
||||||
myFhirTransaction = theFhirTransaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFhirTransaction() {
|
public boolean isFhirTransaction() {
|
||||||
return myFhirTransaction;
|
return myFhirTransaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFhirTransaction(boolean theFhirTransaction) {
|
||||||
|
myFhirTransaction = theFhirTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-caching-api</artifactId>
|
<artifactId>hapi-fhir-caching-api</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>hapi-fhir-spring-boot-sample-client-apache</artifactId>
|
<artifactId>hapi-fhir-spring-boot-sample-client-apache</artifactId>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-spring-boot</artifactId>
|
<artifactId>hapi-fhir-spring-boot</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -96,7 +96,7 @@ public class DeleteExpungeStep implements IJobStepWorker<ReindexJobParameters, R
|
||||||
List<JpaPid> persistentIds = myData.getResourcePersistentIds(myIdHelperService);
|
List<JpaPid> persistentIds = myData.getResourcePersistentIds(myIdHelperService);
|
||||||
|
|
||||||
if (persistentIds.isEmpty()) {
|
if (persistentIds.isEmpty()) {
|
||||||
ourLog.info("Starting delete expunge work chunk. Ther are no resources to delete expunge - Instance[{}] Chunk[{}]", myInstanceId, myChunkId);
|
ourLog.info("Starting delete expunge work chunk. There are no resources to delete expunge - Instance[{}] Chunk[{}]", myInstanceId, myChunkId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -85,7 +85,7 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
|
||||||
* won't be indexed and searches won't work.
|
* won't be indexed and searches won't work.
|
||||||
* @param theRequestDetails The request details including permissions and partitioning information
|
* @param theRequestDetails The request details including permissions and partitioning information
|
||||||
*/
|
*/
|
||||||
DaoMethodOutcome create(T theResource, String theIfNoneExist, boolean thePerformIndexing, @Nonnull TransactionDetails theTransactionDetails, RequestDetails theRequestDetails);
|
DaoMethodOutcome create(T theResource, String theIfNoneExist, boolean thePerformIndexing, RequestDetails theRequestDetails, @Nonnull TransactionDetails theTransactionDetails);
|
||||||
|
|
||||||
DaoMethodOutcome create(T theResource, String theIfNoneExist, RequestDetails theRequestDetails);
|
DaoMethodOutcome create(T theResource, String theIfNoneExist, RequestDetails theRequestDetails);
|
||||||
|
|
||||||
|
@ -111,14 +111,40 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
|
||||||
/**
|
/**
|
||||||
* This method does not throw an exception if there are delete conflicts, but populates them
|
* This method does not throw an exception if there are delete conflicts, but populates them
|
||||||
* in the provided list
|
* in the provided list
|
||||||
|
*
|
||||||
|
* @since 6.8.0
|
||||||
*/
|
*/
|
||||||
DeleteMethodOutcome deleteByUrl(String theUrl, DeleteConflictList theDeleteConflictsListToPopulate, RequestDetails theRequestDetails);
|
DeleteMethodOutcome deleteByUrl(String theUrl, DeleteConflictList theDeleteConflictsListToPopulate, RequestDetails theRequestDetails, @Nonnull TransactionDetails theTransactionDetails);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method throws an exception if there are delete conflicts
|
* This method throws an exception if there are delete conflicts
|
||||||
*/
|
*/
|
||||||
DeleteMethodOutcome deleteByUrl(String theString, RequestDetails theRequestDetails);
|
DeleteMethodOutcome deleteByUrl(String theString, RequestDetails theRequestDetails);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Deprecated in 6.8.0 - Use and implement {@link #deletePidList(String, Collection, DeleteConflictList, RequestDetails, TransactionDetails)}
|
||||||
|
*/
|
||||||
|
default <P extends IResourcePersistentId> DeleteMethodOutcome deletePidList(String theUrl, Collection<P> theResourceIds, DeleteConflictList theDeleteConflicts, RequestDetails theRequest) {
|
||||||
|
return deletePidList(theUrl, theResourceIds, theDeleteConflicts, theRequest, new TransactionDetails());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a list of resource Pids
|
||||||
|
* <p>
|
||||||
|
* CAUTION: This list does not throw an exception if there are delete conflicts. It should always be followed by
|
||||||
|
* a call to DeleteConflictUtil.validateDeleteConflictsEmptyOrThrowException(fhirContext, conflicts);
|
||||||
|
* to actually throw the exception. The reason this method doesn't do that itself is that it is expected to be
|
||||||
|
* called repeatedly where an earlier conflict can be removed in a subsequent pass.
|
||||||
|
*
|
||||||
|
* @param theUrl the original URL that triggered the deletion
|
||||||
|
* @param theResourceIds the ids of the resources to be deleted
|
||||||
|
* @param theDeleteConflicts out parameter of conflicts preventing deletion
|
||||||
|
* @param theRequestDetails the request that initiated the request
|
||||||
|
* @return response back to the client
|
||||||
|
* @since 6.8.0
|
||||||
|
*/
|
||||||
|
<P extends IResourcePersistentId> DeleteMethodOutcome deletePidList(String theUrl, Collection<P> theResourceIds, DeleteConflictList theDeleteConflicts, RequestDetails theRequestDetails, TransactionDetails theTransactionDetails);
|
||||||
|
|
||||||
ExpungeOutcome expunge(ExpungeOptions theExpungeOptions, RequestDetails theRequestDetails);
|
ExpungeOutcome expunge(ExpungeOptions theExpungeOptions, RequestDetails theRequestDetails);
|
||||||
|
|
||||||
ExpungeOutcome expunge(IIdType theIIdType, ExpungeOptions theExpungeOptions, RequestDetails theRequest);
|
ExpungeOutcome expunge(IIdType theIIdType, ExpungeOptions theExpungeOptions, RequestDetails theRequest);
|
||||||
|
@ -331,22 +357,6 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
|
||||||
|
|
||||||
RuntimeResourceDefinition validateCriteriaAndReturnResourceDefinition(String criteria);
|
RuntimeResourceDefinition validateCriteriaAndReturnResourceDefinition(String criteria);
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a list of resource Pids
|
|
||||||
* <p>
|
|
||||||
* CAUTION: This list does not throw an exception if there are delete conflicts. It should always be followed by
|
|
||||||
* a call to DeleteConflictUtil.validateDeleteConflictsEmptyOrThrowException(fhirContext, conflicts);
|
|
||||||
* to actually throw the exception. The reason this method doesn't do that itself is that it is expected to be
|
|
||||||
* called repeatedly where an earlier conflict can be removed in a subsequent pass.
|
|
||||||
*
|
|
||||||
* @param theUrl the original URL that triggered the delete
|
|
||||||
* @param theResourceIds the ids of the resources to be deleted
|
|
||||||
* @param theDeleteConflicts out parameter of conflicts preventing deletion
|
|
||||||
* @param theRequest the request that initiated the request
|
|
||||||
* @return response back to the client
|
|
||||||
*/
|
|
||||||
<P extends IResourcePersistentId> DeleteMethodOutcome deletePidList(String theUrl, Collection<P> theResourceIds, DeleteConflictList theDeleteConflicts, RequestDetails theRequest);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated use #read(IIdType, RequestDetails) instead
|
* @deprecated use #read(IIdType, RequestDetails) instead
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -961,7 +961,7 @@ public abstract class BaseTransactionProcessor {
|
||||||
String matchUrl = myVersionAdapter.getEntryRequestIfNoneExist(nextReqEntry);
|
String matchUrl = myVersionAdapter.getEntryRequestIfNoneExist(nextReqEntry);
|
||||||
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
||||||
// create individual resource
|
// create individual resource
|
||||||
outcome = resourceDao.create(res, matchUrl, false, theTransactionDetails, theRequest);
|
outcome = resourceDao.create(res, matchUrl, false, theRequest, theTransactionDetails);
|
||||||
setConditionalUrlToBeValidatedLater(conditionalUrlToIdMap, matchUrl, outcome.getId());
|
setConditionalUrlToBeValidatedLater(conditionalUrlToIdMap, matchUrl, outcome.getId());
|
||||||
res.setId(outcome.getId());
|
res.setId(outcome.getId());
|
||||||
|
|
||||||
|
@ -999,7 +999,7 @@ public abstract class BaseTransactionProcessor {
|
||||||
} else {
|
} else {
|
||||||
String matchUrl = parts.getResourceType() + '?' + parts.getParams();
|
String matchUrl = parts.getResourceType() + '?' + parts.getParams();
|
||||||
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
||||||
DeleteMethodOutcome deleteOutcome = dao.deleteByUrl(matchUrl, deleteConflicts, theRequest);
|
DeleteMethodOutcome deleteOutcome = dao.deleteByUrl(matchUrl, deleteConflicts, theRequest, theTransactionDetails);
|
||||||
setConditionalUrlToBeValidatedLater(conditionalUrlToIdMap, matchUrl, deleteOutcome.getId());
|
setConditionalUrlToBeValidatedLater(conditionalUrlToIdMap, matchUrl, deleteOutcome.getId());
|
||||||
List<? extends IBasePersistedResource> allDeleted = deleteOutcome.getDeletedEntities();
|
List<? extends IBasePersistedResource> allDeleted = deleteOutcome.getDeletedEntities();
|
||||||
for (IBasePersistedResource deleted : allDeleted) {
|
for (IBasePersistedResource deleted : allDeleted) {
|
||||||
|
|
|
@ -222,4 +222,9 @@ public class MatchResourceUrlService<T extends IResourcePersistentId> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void unresolveMatchUrl(TransactionDetails theTransactionDetails, String theResourceType, String theMatchUrl) {
|
||||||
|
Validate.notBlank(theMatchUrl);
|
||||||
|
String matchUrl = massageForStorage(theResourceType, theMatchUrl);
|
||||||
|
theTransactionDetails.removeResolvedMatchUrl(matchUrl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR Storage api
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
package ca.uhn.fhir.storage.interceptor.balp;
|
package ca.uhn.fhir.storage.interceptor.balp;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR Storage api
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
package ca.uhn.fhir.storage.interceptor.balp;
|
package ca.uhn.fhir.storage.interceptor.balp;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR Storage api
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
package ca.uhn.fhir.storage.interceptor.balp;
|
package ca.uhn.fhir.storage.interceptor.balp;
|
||||||
|
|
||||||
import org.hl7.fhir.r4.model.AuditEvent;
|
import org.hl7.fhir.r4.model.AuditEvent;
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR Storage api
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
package ca.uhn.fhir.storage.interceptor.balp;
|
package ca.uhn.fhir.storage.interceptor.balp;
|
||||||
|
|
||||||
import org.hl7.fhir.r4.model.AuditEvent;
|
import org.hl7.fhir.r4.model.AuditEvent;
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR Storage api
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
package ca.uhn.fhir.storage.interceptor.balp;
|
package ca.uhn.fhir.storage.interceptor.balp;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR Storage api
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
package ca.uhn.fhir.storage.interceptor.balp;
|
package ca.uhn.fhir.storage.interceptor.balp;
|
||||||
|
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR Storage api
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
package ca.uhn.fhir.storage.interceptor.balp;
|
package ca.uhn.fhir.storage.interceptor.balp;
|
||||||
|
|
||||||
import org.hl7.fhir.r4.model.AuditEvent;
|
import org.hl7.fhir.r4.model.AuditEvent;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR Test Utilities
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
package ca.uhn.fhir.parser;
|
package ca.uhn.fhir.parser;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR Test Utilities
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
package ca.uhn.fhir.parser;
|
package ca.uhn.fhir.parser;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR Test Utilities
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
package ca.uhn.fhir.parser;
|
package ca.uhn.fhir.parser;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR Test Utilities
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
package ca.uhn.test.concurrency;
|
package ca.uhn.test.concurrency;
|
||||||
|
|
||||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR Test Utilities
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
package ca.uhn.test.concurrency;
|
package ca.uhn.test.concurrency;
|
||||||
|
|
||||||
import ca.uhn.fhir.i18n.Msg;
|
import ca.uhn.fhir.i18n.Msg;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.7.0-SNAPSHOT</version>
|
<version>6.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue