mirror of
https://github.com/hapifhir/hapi-fhir.git
synced 2025-03-09 14:33:32 +00:00
Add support for including qualified star syntax (#2672)
* Add support for including qualified star syntax * Add changelog * Add docs * Build fix
This commit is contained in:
parent
e359b6d823
commit
2c722e64c2
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 2672
|
||||||
|
title: "A concurrency error was fixed when using client assigned IDs on a highly concurrent server
|
||||||
|
with resource deletion disabled."
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 2672
|
||||||
|
title: "Support has been added to the JPA server for `_include` and `_revinclude` where the
|
||||||
|
value is a qualified star, e.g. `_include=Observation:*`."
|
@ -144,6 +144,13 @@
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution><id>validate</id><phase>none</phase></execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</project>
|
</project>
|
||||||
|
@ -42,6 +42,8 @@ import org.apache.commons.lang3.Validate;
|
|||||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@ -82,7 +84,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||||||
@Service
|
@Service
|
||||||
public class IdHelperService {
|
public class IdHelperService {
|
||||||
private static final String RESOURCE_PID = "RESOURCE_PID";
|
private static final String RESOURCE_PID = "RESOURCE_PID";
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(IdHelperService.class);
|
||||||
@Autowired
|
@Autowired
|
||||||
protected IForcedIdDao myForcedIdDao;
|
protected IForcedIdDao myForcedIdDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
@ -142,7 +144,7 @@ public class IdHelperService {
|
|||||||
retVal = new ResourcePersistentId(resolveResourceIdentity(theRequestPartitionId, theResourceType, theId).getResourceId());
|
retVal = new ResourcePersistentId(resolveResourceIdentity(theRequestPartitionId, theResourceType, theId).getResourceId());
|
||||||
} else {
|
} else {
|
||||||
String key = toForcedIdToPidKey(theRequestPartitionId, theResourceType, theId);
|
String key = toForcedIdToPidKey(theRequestPartitionId, theResourceType, theId);
|
||||||
retVal = myMemoryCacheService.get(MemoryCacheService.CacheEnum.FORCED_ID_TO_PID, key, t -> new ResourcePersistentId(resolveResourceIdentity(theRequestPartitionId, theResourceType, theId).getResourceId()));
|
retVal = myMemoryCacheService.getThenPutAfterCommit(MemoryCacheService.CacheEnum.FORCED_ID_TO_PID, key, t -> new ResourcePersistentId(resolveResourceIdentity(theRequestPartitionId, theResourceType, theId).getResourceId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -252,7 +254,6 @@ public class IdHelperService {
|
|||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Optional<String> translatePidIdToForcedIdWithCache(ResourcePersistentId theId) {
|
public Optional<String> translatePidIdToForcedIdWithCache(ResourcePersistentId theId) {
|
||||||
return myMemoryCacheService.get(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, theId.getIdAsLong(), pid -> myForcedIdDao.findByResourcePid(pid).map(t -> t.getForcedId()));
|
return myMemoryCacheService.get(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, theId.getIdAsLong(), pid -> myForcedIdDao.findByResourcePid(pid).map(t -> t.getForcedId()));
|
||||||
}
|
}
|
||||||
@ -334,7 +335,7 @@ public class IdHelperService {
|
|||||||
|
|
||||||
if (!myDaoConfig.isDeleteEnabled()) {
|
if (!myDaoConfig.isDeleteEnabled()) {
|
||||||
String key = resourceType + "/" + forcedId;
|
String key = resourceType + "/" + forcedId;
|
||||||
myMemoryCacheService.put(MemoryCacheService.CacheEnum.RESOURCE_LOOKUP, key, lookup);
|
myMemoryCacheService.putAfterCommit(MemoryCacheService.CacheEnum.RESOURCE_LOOKUP, key, lookup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -378,7 +379,7 @@ public class IdHelperService {
|
|||||||
theTarget.add(t);
|
theTarget.add(t);
|
||||||
if (!myDaoConfig.isDeleteEnabled()) {
|
if (!myDaoConfig.isDeleteEnabled()) {
|
||||||
String nextKey = Long.toString(t.getResourceId());
|
String nextKey = Long.toString(t.getResourceId());
|
||||||
myMemoryCacheService.put(MemoryCacheService.CacheEnum.RESOURCE_LOOKUP, nextKey, t);
|
myMemoryCacheService.putAfterCommit(MemoryCacheService.CacheEnum.RESOURCE_LOOKUP, nextKey, t);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -386,12 +387,11 @@ public class IdHelperService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* Given a set of PIDs, return a set of public FHIR Resource IDs.
|
* Given a set of PIDs, return a set of public FHIR Resource IDs.
|
||||||
* This function will resolve a forced ID if it resolves, and if it fails to resolve to a forced it, will just return the pid
|
* This function will resolve a forced ID if it resolves, and if it fails to resolve to a forced it, will just return the pid
|
||||||
* Example:
|
* Example:
|
||||||
* Let's say we have Patient/1(pid == 1), Patient/pat1 (pid == 2), Patient/3 (pid == 3), their pids would resolve as follows:
|
* Let's say we have Patient/1(pid == 1), Patient/pat1 (pid == 2), Patient/3 (pid == 3), their pids would resolve as follows:
|
||||||
*
|
* <p>
|
||||||
* [1,2,3] -> ["1","pat1","3"]
|
* [1,2,3] -> ["1","pat1","3"]
|
||||||
*
|
*
|
||||||
* @param thePids The Set of pids you would like to resolve to external FHIR Resource IDs.
|
* @param thePids The Set of pids you would like to resolve to external FHIR Resource IDs.
|
||||||
@ -408,6 +408,7 @@ public class IdHelperService {
|
|||||||
return resolvedResourceIds;
|
return resolvedResourceIds;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Long, Optional<String>> translatePidsToForcedIds(Set<Long> thePids) {
|
public Map<Long, Optional<String>> translatePidsToForcedIds(Set<Long> thePids) {
|
||||||
Map<Long, Optional<String>> retVal = new HashMap<>(myMemoryCacheService.getAllPresent(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, thePids));
|
Map<Long, Optional<String>> retVal = new HashMap<>(myMemoryCacheService.getAllPresent(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, thePids));
|
||||||
|
|
||||||
@ -423,7 +424,7 @@ public class IdHelperService {
|
|||||||
Long nextResourcePid = forcedId.getResourceId();
|
Long nextResourcePid = forcedId.getResourceId();
|
||||||
Optional<String> nextForcedId = Optional.of(forcedId.getForcedId());
|
Optional<String> nextForcedId = Optional.of(forcedId.getForcedId());
|
||||||
retVal.put(nextResourcePid, nextForcedId);
|
retVal.put(nextResourcePid, nextForcedId);
|
||||||
myMemoryCacheService.put(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, nextResourcePid, nextForcedId);
|
myMemoryCacheService.putAfterCommit(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, nextResourcePid, nextForcedId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -433,7 +434,7 @@ public class IdHelperService {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
for (Long nextResourcePid : remainingPids) {
|
for (Long nextResourcePid : remainingPids) {
|
||||||
retVal.put(nextResourcePid, Optional.empty());
|
retVal.put(nextResourcePid, Optional.empty());
|
||||||
myMemoryCacheService.put(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, nextResourcePid, Optional.empty());
|
myMemoryCacheService.putAfterCommit(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, nextResourcePid, Optional.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
@ -491,11 +492,11 @@ public class IdHelperService {
|
|||||||
*/
|
*/
|
||||||
public void addResolvedPidToForcedId(ResourcePersistentId theResourcePersistentId, @Nonnull RequestPartitionId theRequestPartitionId, String theResourceType, @Nullable String theForcedId) {
|
public void addResolvedPidToForcedId(ResourcePersistentId theResourcePersistentId, @Nonnull RequestPartitionId theRequestPartitionId, String theResourceType, @Nullable String theForcedId) {
|
||||||
if (theForcedId != null) {
|
if (theForcedId != null) {
|
||||||
myMemoryCacheService.put(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, theResourcePersistentId.getIdAsLong(), Optional.of(theForcedId));
|
myMemoryCacheService.putAfterCommit(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, theResourcePersistentId.getIdAsLong(), Optional.of(theForcedId));
|
||||||
String key = toForcedIdToPidKey(theRequestPartitionId, theResourceType, theForcedId);
|
String key = toForcedIdToPidKey(theRequestPartitionId, theResourceType, theForcedId);
|
||||||
myMemoryCacheService.put(MemoryCacheService.CacheEnum.FORCED_ID_TO_PID, key, theResourcePersistentId);
|
myMemoryCacheService.putAfterCommit(MemoryCacheService.CacheEnum.FORCED_ID_TO_PID, key, theResourcePersistentId);
|
||||||
}else {
|
} else {
|
||||||
myMemoryCacheService.put(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, theResourcePersistentId.getIdAsLong(), Optional.empty());
|
myMemoryCacheService.putAfterCommit(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, theResourcePersistentId.getIdAsLong(), Optional.empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1250,9 +1250,12 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||||||
theSearch.setStatus(SearchStatusEnum.LOADING);
|
theSearch.setStatus(SearchStatusEnum.LOADING);
|
||||||
theSearch.setSearchQueryString(theQueryString, theRequestPartitionId);
|
theSearch.setSearchQueryString(theQueryString, theRequestPartitionId);
|
||||||
|
|
||||||
for (Include next : theParams.getIncludes()) {
|
if (theParams.hasIncludes()) {
|
||||||
theSearch.addInclude(new SearchInclude(theSearch, next.getValue(), false, next.isRecurse()));
|
for (Include next : theParams.getIncludes()) {
|
||||||
|
theSearch.addInclude(new SearchInclude(theSearch, next.getValue(), false, next.isRecurse()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Include next : theParams.getRevIncludes()) {
|
for (Include next : theParams.getRevIncludes()) {
|
||||||
theSearch.addInclude(new SearchInclude(theSearch, next.getValue(), true, next.isRecurse()));
|
theSearch.addInclude(new SearchInclude(theSearch, next.getValue(), true, next.isRecurse()));
|
||||||
}
|
}
|
||||||
|
@ -787,7 +787,18 @@ public class SearchBuilder implements ISearchBuilder {
|
|||||||
iter.remove();
|
iter.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Account for _include=*
|
||||||
boolean matchAll = "*".equals(nextInclude.getValue());
|
boolean matchAll = "*".equals(nextInclude.getValue());
|
||||||
|
|
||||||
|
// Account for _include=[resourceType]:*
|
||||||
|
String wantResourceType = null;
|
||||||
|
if (!matchAll) {
|
||||||
|
if (nextInclude.getParamName().equals("*")) {
|
||||||
|
wantResourceType = nextInclude.getParamType();
|
||||||
|
matchAll = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (matchAll) {
|
if (matchAll) {
|
||||||
StringBuilder sqlBuilder = new StringBuilder();
|
StringBuilder sqlBuilder = new StringBuilder();
|
||||||
sqlBuilder.append("SELECT r.").append(findPidFieldName);
|
sqlBuilder.append("SELECT r.").append(findPidFieldName);
|
||||||
@ -797,11 +808,27 @@ public class SearchBuilder implements ISearchBuilder {
|
|||||||
sqlBuilder.append(" FROM ResourceLink r WHERE r.");
|
sqlBuilder.append(" FROM ResourceLink r WHERE r.");
|
||||||
sqlBuilder.append(searchPidFieldName);
|
sqlBuilder.append(searchPidFieldName);
|
||||||
sqlBuilder.append(" IN (:target_pids)");
|
sqlBuilder.append(" IN (:target_pids)");
|
||||||
|
|
||||||
|
// Technically if the request is a qualified star (e.g. _include=Observation:*) we
|
||||||
|
// should always be checking the source resource type on the resource link. We don't
|
||||||
|
// actually index that column though by default, so in order to try and be efficient
|
||||||
|
// we don't actually include it for includes (but we do for revincludes). This is
|
||||||
|
// because for an include it doesn't really make sense to include a different
|
||||||
|
// resource type than the one you are searching on.
|
||||||
|
if (wantResourceType != null && theReverseMode) {
|
||||||
|
sqlBuilder.append(" AND r.mySourceResourceType = :want_resource_type");
|
||||||
|
} else {
|
||||||
|
wantResourceType = null;
|
||||||
|
}
|
||||||
|
|
||||||
String sql = sqlBuilder.toString();
|
String sql = sqlBuilder.toString();
|
||||||
List<Collection<ResourcePersistentId>> partitions = partition(nextRoundMatches, getMaximumPageSize());
|
List<Collection<ResourcePersistentId>> partitions = partition(nextRoundMatches, getMaximumPageSize());
|
||||||
for (Collection<ResourcePersistentId> nextPartition : partitions) {
|
for (Collection<ResourcePersistentId> nextPartition : partitions) {
|
||||||
TypedQuery<?> q = theEntityManager.createQuery(sql, Object[].class);
|
TypedQuery<?> q = theEntityManager.createQuery(sql, Object[].class);
|
||||||
q.setParameter("target_pids", ResourcePersistentId.toLongList(nextPartition));
|
q.setParameter("target_pids", ResourcePersistentId.toLongList(nextPartition));
|
||||||
|
if (wantResourceType != null) {
|
||||||
|
q.setParameter("want_resource_type", wantResourceType);
|
||||||
|
}
|
||||||
List<?> results = q.getResultList();
|
List<?> results = q.getResultList();
|
||||||
for (Object nextRow : results) {
|
for (Object nextRow : results) {
|
||||||
if (nextRow == null) {
|
if (nextRow == null) {
|
||||||
|
@ -28,6 +28,7 @@ import com.github.benmanes.caffeine.cache.Cache;
|
|||||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.transaction.support.TransactionSynchronization;
|
import org.springframework.transaction.support.TransactionSynchronization;
|
||||||
@ -94,6 +95,24 @@ public class MemoryCacheService {
|
|||||||
return cache.get(theKey, theSupplier);
|
return cache.get(theKey, theSupplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch an item from the cache if it exists, and use the loading function to
|
||||||
|
* obtain it otherwise.
|
||||||
|
*
|
||||||
|
* This method will put the value into the cache using {@link #putAfterCommit(CacheEnum, Object, Object)}.
|
||||||
|
*/
|
||||||
|
public <K, T> T getThenPutAfterCommit(CacheEnum theCache, K theKey, Function<K, T> theSupplier) {
|
||||||
|
assert theCache.myKeyType.isAssignableFrom(theKey.getClass());
|
||||||
|
|
||||||
|
Cache<K, T> cache = getCache(theCache);
|
||||||
|
T retVal = cache.getIfPresent(theKey);
|
||||||
|
if (retVal == null) {
|
||||||
|
retVal = theSupplier.apply(theKey);
|
||||||
|
putAfterCommit(theCache, theKey, retVal);
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
public <K, V> V getIfPresent(CacheEnum theCache, K theKey) {
|
public <K, V> V getIfPresent(CacheEnum theCache, K theKey) {
|
||||||
assert theCache.myKeyType.isAssignableFrom(theKey.getClass());
|
assert theCache.myKeyType.isAssignableFrom(theKey.getClass());
|
||||||
return (V) getCache(theCache).getIfPresent(theKey);
|
return (V) getCache(theCache).getIfPresent(theKey);
|
||||||
|
@ -25,6 +25,7 @@ import org.hl7.fhir.r4.model.Observation;
|
|||||||
import org.hl7.fhir.r4.model.Parameters;
|
import org.hl7.fhir.r4.model.Parameters;
|
||||||
import org.hl7.fhir.r4.model.Patient;
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
import org.hl7.fhir.r4.model.Practitioner;
|
import org.hl7.fhir.r4.model.Practitioner;
|
||||||
|
import org.hl7.fhir.r4.model.Reference;
|
||||||
import org.hl7.fhir.r4.model.SearchParameter;
|
import org.hl7.fhir.r4.model.SearchParameter;
|
||||||
import org.hl7.fhir.r4.model.StringType;
|
import org.hl7.fhir.r4.model.StringType;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
@ -147,12 +148,12 @@ public class FhirResourceDaoR4ConcurrentWriteTest extends BaseJpaR4Test {
|
|||||||
creator.run();
|
creator.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
runInTransaction(()->{
|
runInTransaction(() -> {
|
||||||
Map<String, Integer> counts = new TreeMap<>();
|
Map<String, Integer> counts = new TreeMap<>();
|
||||||
myResourceTableDao
|
myResourceTableDao
|
||||||
.findAll()
|
.findAll()
|
||||||
.stream()
|
.stream()
|
||||||
.forEach(t->{
|
.forEach(t -> {
|
||||||
counts.putIfAbsent(t.getResourceType(), 0);
|
counts.putIfAbsent(t.getResourceType(), 0);
|
||||||
int value = counts.get(t.getResourceType());
|
int value = counts.get(t.getResourceType());
|
||||||
value++;
|
value++;
|
||||||
@ -166,7 +167,6 @@ public class FhirResourceDaoR4ConcurrentWriteTest extends BaseJpaR4Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateWithClientAssignedId() {
|
public void testCreateWithClientAssignedId() {
|
||||||
myInterceptorRegistry.registerInterceptor(myRetryInterceptor);
|
myInterceptorRegistry.registerInterceptor(myRetryInterceptor);
|
||||||
@ -603,4 +603,63 @@ public class FhirResourceDaoR4ConcurrentWriteTest extends BaseJpaR4Test {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransactionWithCreateClientAssignedIdAndReferenceToThatId() {
|
||||||
|
myInterceptorRegistry.registerInterceptor(myRetryInterceptor);
|
||||||
|
myDaoConfig.setDeleteEnabled(false);
|
||||||
|
|
||||||
|
ServletRequestDetails srd = mock(ServletRequestDetails.class);
|
||||||
|
String value = UserRequestRetryVersionConflictsInterceptor.RETRY + "; " + UserRequestRetryVersionConflictsInterceptor.MAX_RETRIES + "=10";
|
||||||
|
when(srd.getHeaders(eq(UserRequestRetryVersionConflictsInterceptor.HEADER_NAME))).thenReturn(Collections.singletonList(value));
|
||||||
|
when(srd.getUserData()).thenReturn(new HashMap<>());
|
||||||
|
when(srd.getServer()).thenReturn(new RestfulServer(myFhirCtx));
|
||||||
|
when(srd.getInterceptorBroadcaster()).thenReturn(new InterceptorService());
|
||||||
|
|
||||||
|
List<Future<?>> futures = new ArrayList<>();
|
||||||
|
int repetitionCount = 3;
|
||||||
|
for (int i = 0; i < repetitionCount; i++) {
|
||||||
|
String patientId = "PATIENT" + i;
|
||||||
|
|
||||||
|
Runnable task = () -> {
|
||||||
|
BundleBuilder bb = new BundleBuilder(myFhirCtx);
|
||||||
|
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.setId(patientId);
|
||||||
|
p.setActive(true);
|
||||||
|
bb.addTransactionUpdateEntry(p);
|
||||||
|
|
||||||
|
Observation obs = new Observation();
|
||||||
|
obs.setSubject(new Reference("Patient/" + patientId));
|
||||||
|
bb.addTransactionCreateEntry(obs);
|
||||||
|
|
||||||
|
ourLog.info("Submitting transaction");
|
||||||
|
mySystemDao.transaction(srd, (Bundle) bb.getBundle());
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int j = 0; j < 5; j++) {
|
||||||
|
Future<?> future = myExecutor.submit(task);
|
||||||
|
futures.add(future);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for failures
|
||||||
|
for (Future<?> next : futures) {
|
||||||
|
try {
|
||||||
|
next.get();
|
||||||
|
ourLog.info("Future produced success");
|
||||||
|
} catch (Exception e) {
|
||||||
|
ourLog.info("Future produced exception: {}", e.toString());
|
||||||
|
throw new AssertionError("Failed with message: " + e.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we saved the object
|
||||||
|
for (int i = 0; i < repetitionCount; i++) {
|
||||||
|
Patient patient = myPatientDao.read(new IdType("Patient/PATIENT0"));
|
||||||
|
assertEquals(true, patient.getActive());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,40 +1,60 @@
|
|||||||
package ca.uhn.fhir.jpa.dao.r4;
|
package ca.uhn.fhir.jpa.dao.r4;
|
||||||
|
|
||||||
import static ca.uhn.fhir.rest.api.Constants.PARAM_TYPE;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
import static org.apache.commons.lang3.StringUtils.countMatches;
|
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import ca.uhn.fhir.interceptor.api.IAnonymousInterceptor;
|
||||||
import static org.hamcrest.Matchers.contains;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import ca.uhn.fhir.jpa.entity.Search;
|
||||||
import static org.hamcrest.Matchers.empty;
|
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||||
import static org.hamcrest.Matchers.endsWith;
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
import static org.hamcrest.Matchers.hasItem;
|
|
||||||
import static org.hamcrest.Matchers.hasItems;
|
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
|
||||||
import static org.hamcrest.Matchers.not;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
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.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.times;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantityNormalized;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
|
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
||||||
|
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||||
|
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||||
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap.EverythingModeEnum;
|
||||||
|
import ca.uhn.fhir.jpa.util.SqlQuery;
|
||||||
|
import ca.uhn.fhir.jpa.util.TestUtil;
|
||||||
|
import ca.uhn.fhir.model.api.Include;
|
||||||
|
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||||
|
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||||
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
|
import ca.uhn.fhir.rest.param.CompositeParam;
|
||||||
|
import ca.uhn.fhir.rest.param.DateParam;
|
||||||
|
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||||
|
import ca.uhn.fhir.rest.param.HasAndListParam;
|
||||||
|
import ca.uhn.fhir.rest.param.HasOrListParam;
|
||||||
|
import ca.uhn.fhir.rest.param.HasParam;
|
||||||
|
import ca.uhn.fhir.rest.param.NumberParam;
|
||||||
|
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
|
||||||
|
import ca.uhn.fhir.rest.param.QuantityParam;
|
||||||
|
import ca.uhn.fhir.rest.param.ReferenceAndListParam;
|
||||||
|
import ca.uhn.fhir.rest.param.ReferenceOrListParam;
|
||||||
|
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||||
|
import ca.uhn.fhir.rest.param.StringAndListParam;
|
||||||
|
import ca.uhn.fhir.rest.param.StringOrListParam;
|
||||||
|
import ca.uhn.fhir.rest.param.StringParam;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenOrListParam;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenParamModifier;
|
||||||
|
import ca.uhn.fhir.rest.param.UriParam;
|
||||||
|
import ca.uhn.fhir.rest.param.UriParamQualifierEnum;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
@ -116,61 +136,38 @@ import org.springframework.transaction.support.TransactionCallback;
|
|||||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import static ca.uhn.fhir.rest.api.Constants.PARAM_TYPE;
|
||||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
import static org.apache.commons.lang3.StringUtils.countMatches;
|
||||||
import ca.uhn.fhir.interceptor.api.IAnonymousInterceptor;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
import static org.hamcrest.Matchers.contains;
|
||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
import ca.uhn.fhir.jpa.entity.Search;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
import static org.hamcrest.Matchers.empty;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
import static org.hamcrest.Matchers.endsWith;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
import static org.hamcrest.Matchers.hasItem;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
import static org.hamcrest.Matchers.hasItems;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantityNormalized;
|
import static org.hamcrest.Matchers.not;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
import static org.mockito.Mockito.mock;
|
||||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
import static org.mockito.Mockito.times;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import static org.mockito.Mockito.verify;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap.EverythingModeEnum;
|
|
||||||
import ca.uhn.fhir.jpa.util.SqlQuery;
|
|
||||||
import ca.uhn.fhir.jpa.util.TestUtil;
|
|
||||||
import ca.uhn.fhir.model.api.Include;
|
|
||||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
|
||||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
|
||||||
import ca.uhn.fhir.rest.param.CompositeParam;
|
|
||||||
import ca.uhn.fhir.rest.param.DateParam;
|
|
||||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
|
||||||
import ca.uhn.fhir.rest.param.HasAndListParam;
|
|
||||||
import ca.uhn.fhir.rest.param.HasOrListParam;
|
|
||||||
import ca.uhn.fhir.rest.param.HasParam;
|
|
||||||
import ca.uhn.fhir.rest.param.NumberParam;
|
|
||||||
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
|
|
||||||
import ca.uhn.fhir.rest.param.QuantityParam;
|
|
||||||
import ca.uhn.fhir.rest.param.ReferenceAndListParam;
|
|
||||||
import ca.uhn.fhir.rest.param.ReferenceOrListParam;
|
|
||||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
|
||||||
import ca.uhn.fhir.rest.param.StringAndListParam;
|
|
||||||
import ca.uhn.fhir.rest.param.StringOrListParam;
|
|
||||||
import ca.uhn.fhir.rest.param.StringParam;
|
|
||||||
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
|
||||||
import ca.uhn.fhir.rest.param.TokenOrListParam;
|
|
||||||
import ca.uhn.fhir.rest.param.TokenParam;
|
|
||||||
import ca.uhn.fhir.rest.param.TokenParamModifier;
|
|
||||||
import ca.uhn.fhir.rest.param.UriParam;
|
|
||||||
import ca.uhn.fhir.rest.param.UriParamQualifierEnum;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
|
||||||
import ca.uhn.fhir.util.HapiExtensions;
|
|
||||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "Duplicates"})
|
@SuppressWarnings({"unchecked", "Duplicates"})
|
||||||
public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||||
@ -186,8 +183,8 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||||||
myDaoConfig.setAllowContainsSearches(new DaoConfig().isAllowContainsSearches());
|
myDaoConfig.setAllowContainsSearches(new DaoConfig().isAllowContainsSearches());
|
||||||
myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds());
|
myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds());
|
||||||
myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields());
|
myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields());
|
||||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED);
|
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void beforeDisableCacheReuse() {
|
public void beforeDisableCacheReuse() {
|
||||||
@ -573,7 +570,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||||||
ourLog.info("Token indexes:\n * {}", myResourceIndexedSearchParamTokenDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * ")));
|
ourLog.info("Token indexes:\n * {}", myResourceIndexedSearchParamTokenDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * ")));
|
||||||
});
|
});
|
||||||
|
|
||||||
SearchParameterMap map = SearchParameterMap.newSynchronous();
|
SearchParameterMap map = SearchParameterMap.newSynchronous();
|
||||||
map.add(MedicationAdministration.SP_MEDICATION, new ReferenceAndListParam().addAnd(new ReferenceOrListParam().add(new ReferenceParam("code", "04823543"))));
|
map.add(MedicationAdministration.SP_MEDICATION, new ReferenceAndListParam().addAnd(new ReferenceOrListParam().add(new ReferenceParam("code", "04823543"))));
|
||||||
|
|
||||||
myCaptureQueriesListener.clear();
|
myCaptureQueriesListener.clear();
|
||||||
@ -607,8 +604,8 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||||||
String yesterday = new DateType(DateUtils.addDays(new Date(), -1)).getValueAsString();
|
String yesterday = new DateType(DateUtils.addDays(new Date(), -1)).getValueAsString();
|
||||||
String tomorrow = new DateType(DateUtils.addDays(new Date(), 1)).getValueAsString();
|
String tomorrow = new DateType(DateUtils.addDays(new Date(), 1)).getValueAsString();
|
||||||
|
|
||||||
runInTransaction(()->{
|
runInTransaction(() -> {
|
||||||
ourLog.info("Resources:\n * {}", myResourceTableDao.findAll().stream().map(t->t.toString()).collect(Collectors.joining("\n * ")));
|
ourLog.info("Resources:\n * {}", myResourceTableDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * ")));
|
||||||
});
|
});
|
||||||
|
|
||||||
RuntimeResourceDefinition resDef = myFhirCtx.getResourceDefinition("DiagnosticReport");
|
RuntimeResourceDefinition resDef = myFhirCtx.getResourceDefinition("DiagnosticReport");
|
||||||
@ -768,8 +765,8 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||||||
pat2.getManagingOrganization().setReferenceElement(orgId);
|
pat2.getManagingOrganization().setReferenceElement(orgId);
|
||||||
IIdType patId2 = myPatientDao.create(pat2, mySrd).getId().toUnqualifiedVersionless();
|
IIdType patId2 = myPatientDao.create(pat2, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
runInTransaction(()->{
|
runInTransaction(() -> {
|
||||||
ourLog.info("Links:\n * {}", myResourceLinkDao.findAll().stream().map(t->t.toString()).collect(Collectors.joining("\n * ")));
|
ourLog.info("Links:\n * {}", myResourceLinkDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * ")));
|
||||||
});
|
});
|
||||||
|
|
||||||
// All patient IDs
|
// All patient IDs
|
||||||
@ -1229,7 +1226,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||||||
ourLog.info(toStringMultiline(results));
|
ourLog.info(toStringMultiline(results));
|
||||||
assertEquals(0, results.size());
|
assertEquals(0, results.size());
|
||||||
});
|
});
|
||||||
|
|
||||||
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
||||||
mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 123, "http://foo", "UNIT"))));
|
mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 123, "http://foo", "UNIT"))));
|
||||||
assertThat(actual, contains(id));
|
assertThat(actual, contains(id));
|
||||||
@ -1244,45 +1241,45 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||||||
res.addInstance().getQuantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("m").setValue(123);
|
res.addInstance().getQuantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("m").setValue(123);
|
||||||
res.addInstance().getQuantity().setSystem("http://foo2").setCode("UNIT2").setValue(1232);
|
res.addInstance().getQuantity().setSystem("http://foo2").setCode("UNIT2").setValue(1232);
|
||||||
res.addInstance().getQuantity().setSystem("http://foo2").setCode("UNIT2").setValue(1232);
|
res.addInstance().getQuantity().setSystem("http://foo2").setCode("UNIT2").setValue(1232);
|
||||||
|
|
||||||
IIdType id = mySubstanceDao.create(res, mySrd).getId().toUnqualifiedVersionless();
|
IIdType id = mySubstanceDao.create(res, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
||||||
mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 12300, UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm"))));
|
mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 12300, UcumServiceUtil.UCUM_CODESYSTEM_URL, "cm"))));
|
||||||
assertThat(actual, contains(id));
|
assertThat(actual, contains(id));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testQuantityWithNormalizedQuantitySearchSupported_InvalidUCUMCode() {
|
public void testQuantityWithNormalizedQuantitySearchSupported_InvalidUCUMCode() {
|
||||||
|
|
||||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||||
Substance res = new Substance();
|
Substance res = new Substance();
|
||||||
res.addInstance().getQuantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("FOO").setValue(123);
|
res.addInstance().getQuantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("FOO").setValue(123);
|
||||||
|
|
||||||
IIdType id = mySubstanceDao.create(res, mySrd).getId().toUnqualifiedVersionless();
|
IIdType id = mySubstanceDao.create(res, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
||||||
mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 123, UcumServiceUtil.UCUM_CODESYSTEM_URL, "FOO"))));
|
mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 123, UcumServiceUtil.UCUM_CODESYSTEM_URL, "FOO"))));
|
||||||
assertThat(actual, contains(id));
|
assertThat(actual, contains(id));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testQuantityWithNormalizedQuantitySearchSupported_NotUCUM() {
|
public void testQuantityWithNormalizedQuantitySearchSupported_NotUCUM() {
|
||||||
|
|
||||||
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
|
||||||
Substance res = new Substance();
|
Substance res = new Substance();
|
||||||
res.addInstance().getQuantity().setSystem("http://bar").setCode("FOO").setValue(123);
|
res.addInstance().getQuantity().setSystem("http://bar").setCode("FOO").setValue(123);
|
||||||
|
|
||||||
IIdType id = mySubstanceDao.create(res, mySrd).getId().toUnqualifiedVersionless();
|
IIdType id = mySubstanceDao.create(res, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
||||||
mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 123, "http://bar", "FOO"))));
|
mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 123, "http://bar", "FOO"))));
|
||||||
assertThat(actual, contains(id));
|
assertThat(actual, contains(id));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIndexNoDuplicatesQuantityWithNormalizedQuantityStorageSupported() {
|
public void testIndexNoDuplicatesQuantityWithNormalizedQuantityStorageSupported() {
|
||||||
|
|
||||||
@ -1297,9 +1294,9 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||||||
|
|
||||||
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
||||||
mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 123, UcumServiceUtil.UCUM_CODESYSTEM_URL, "m"))));
|
mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 123, UcumServiceUtil.UCUM_CODESYSTEM_URL, "m"))));
|
||||||
assertThat(actual, contains(id));
|
assertThat(actual, contains(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIndexNoDuplicatesReference() {
|
public void testIndexNoDuplicatesReference() {
|
||||||
ServiceRequest pr = new ServiceRequest();
|
ServiceRequest pr = new ServiceRequest();
|
||||||
@ -1509,7 +1506,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||||||
// Should not crash
|
// Should not crash
|
||||||
myServiceRequestDao.create(serviceRequest);
|
myServiceRequestDao.create(serviceRequest);
|
||||||
|
|
||||||
runInTransaction(()->{
|
runInTransaction(() -> {
|
||||||
assertEquals(1, myResourceIndexedSearchParamDateDao.findAll().size());
|
assertEquals(1, myResourceIndexedSearchParamDateDao.findAll().size());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1517,7 +1514,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||||||
@Test
|
@Test
|
||||||
public void testPeriodWithNoEnd() {
|
public void testPeriodWithNoEnd() {
|
||||||
ServiceRequest serviceRequest = new ServiceRequest();
|
ServiceRequest serviceRequest = new ServiceRequest();
|
||||||
|
|
||||||
Period period = new Period();
|
Period period = new Period();
|
||||||
period.setStart(new Date());
|
period.setStart(new Date());
|
||||||
Timing timing = new Timing();
|
Timing timing = new Timing();
|
||||||
@ -1527,11 +1524,11 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||||||
// Should not crash
|
// Should not crash
|
||||||
myServiceRequestDao.create(serviceRequest);
|
myServiceRequestDao.create(serviceRequest);
|
||||||
|
|
||||||
runInTransaction(()->{
|
runInTransaction(() -> {
|
||||||
assertEquals(1, myResourceIndexedSearchParamDateDao.findAll().size());
|
assertEquals(1, myResourceIndexedSearchParamDateDao.findAll().size());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchByIdParamInverse() {
|
public void testSearchByIdParamInverse() {
|
||||||
@ -1840,6 +1837,72 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchWithIncludeStarQualified() {
|
||||||
|
|
||||||
|
Patient pt = new Patient();
|
||||||
|
pt.setActive(true);
|
||||||
|
IIdType ptId = myPatientDao.create(pt, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
Encounter enc = new Encounter();
|
||||||
|
enc.setStatus(Encounter.EncounterStatus.ARRIVED);
|
||||||
|
IIdType encId = myEncounterDao.create(enc, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
Observation obs = new Observation();
|
||||||
|
obs.getSubject().setReference(ptId.getValue());
|
||||||
|
obs.getEncounter().setReference(encId.getValue());
|
||||||
|
IIdType obsId = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
// Async Search
|
||||||
|
SearchParameterMap map = new SearchParameterMap();
|
||||||
|
map.addInclude(new Include("Observation:*"));
|
||||||
|
List<IIdType> ids = toUnqualifiedVersionlessIds(myObservationDao.search(map));
|
||||||
|
assertThat(ids, containsInAnyOrder(obsId, ptId, encId));
|
||||||
|
|
||||||
|
// Sync Search
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.addInclude(new Include("Observation:*"));
|
||||||
|
ids = toUnqualifiedVersionlessIds(myObservationDao.search(map));
|
||||||
|
assertThat(ids, containsInAnyOrder(obsId, ptId, encId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchWithRevIncludeStarQualified() {
|
||||||
|
|
||||||
|
Patient pt = new Patient();
|
||||||
|
pt.setActive(true);
|
||||||
|
IIdType ptId = myPatientDao.create(pt, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
Encounter enc = new Encounter();
|
||||||
|
enc.setStatus(Encounter.EncounterStatus.ARRIVED);
|
||||||
|
IIdType encId = myEncounterDao.create(enc, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
Observation obs = new Observation();
|
||||||
|
obs.getSubject().setReference(ptId.getValue());
|
||||||
|
obs.getEncounter().setReference(encId.getValue());
|
||||||
|
IIdType obsId = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
MedicationRequest mr = new MedicationRequest();
|
||||||
|
mr.getEncounter().setReference(encId.getValue());
|
||||||
|
myMedicationRequestDao.create(mr, mySrd);
|
||||||
|
|
||||||
|
// Async Search
|
||||||
|
SearchParameterMap map = new SearchParameterMap();
|
||||||
|
map.addRevInclude(new Include("Observation:*"));
|
||||||
|
List<IIdType> ids = toUnqualifiedVersionlessIds(myEncounterDao.search(map));
|
||||||
|
assertThat(ids, containsInAnyOrder(obsId, encId));
|
||||||
|
|
||||||
|
// Sync Search
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.addRevInclude(new Include("Observation:*"));
|
||||||
|
ids = toUnqualifiedVersionlessIds(myEncounterDao.search(map));
|
||||||
|
assertThat(ids, containsInAnyOrder(obsId, encId));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testComponentQuantity() {
|
public void testComponentQuantity() {
|
||||||
Observation o1 = new Observation();
|
Observation o1 = new Observation();
|
||||||
@ -2758,7 +2821,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||||||
assertEquals(1, myChargeItemDao.search(map).size().intValue());
|
assertEquals(1, myChargeItemDao.search(map).size().intValue());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchNameParam() {
|
public void testSearchNameParam() {
|
||||||
IIdType id1;
|
IIdType id1;
|
||||||
@ -3122,7 +3185,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||||||
assertEquals(1, found.size().intValue());
|
assertEquals(1, found.size().intValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchResourceLinkOnCanonical() {
|
public void testSearchResourceLinkOnCanonical() {
|
||||||
|
|
||||||
@ -3902,8 +3965,8 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||||||
patient.addName().setFamily("Tester").addGiven("testSearchTokenParam2");
|
patient.addName().setFamily("Tester").addGiven("testSearchTokenParam2");
|
||||||
myPatientDao.create(patient, mySrd);
|
myPatientDao.create(patient, mySrd);
|
||||||
|
|
||||||
runInTransaction(()->{
|
runInTransaction(() -> {
|
||||||
ourLog.info("Token indexes:\n * {}", myResourceIndexedSearchParamTokenDao.findAll().stream().filter(t->t.getParamName().equals("identifier")).map(t->t.toString()).collect(Collectors.joining("\n * ")));
|
ourLog.info("Token indexes:\n * {}", myResourceIndexedSearchParamTokenDao.findAll().stream().filter(t -> t.getParamName().equals("identifier")).map(t -> t.toString()).collect(Collectors.joining("\n * ")));
|
||||||
});
|
});
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -3945,8 +4008,8 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||||||
female = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless().getValue();
|
female = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
runInTransaction(()->{
|
runInTransaction(() -> {
|
||||||
ourLog.info("Tokens:\n * {}", myResourceIndexedSearchParamTokenDao.findAll().stream().map(t->t.toString()).collect(Collectors.joining("\n * ")));
|
ourLog.info("Tokens:\n * {}", myResourceIndexedSearchParamTokenDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * ")));
|
||||||
});
|
});
|
||||||
|
|
||||||
List<String> patients;
|
List<String> patients;
|
||||||
@ -5446,9 +5509,9 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||||||
c3.getEncounter().setReference(e3Id);
|
c3.getEncounter().setReference(e3Id);
|
||||||
myCommunicationDao.create(c3);
|
myCommunicationDao.create(c3);
|
||||||
|
|
||||||
runInTransaction(()->{
|
runInTransaction(() -> {
|
||||||
ourLog.info("Links:\n * {}", myResourceLinkDao.findAll().stream().map(t->t.toString()).collect(Collectors.joining("\n * ")));
|
ourLog.info("Links:\n * {}", myResourceLinkDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * ")));
|
||||||
ourLog.info("Dates:\n * {}", myResourceIndexedSearchParamDateDao.findAll().stream().map(t->t.toString()).collect(Collectors.joining("\n * ")));
|
ourLog.info("Dates:\n * {}", myResourceIndexedSearchParamDateDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * ")));
|
||||||
});
|
});
|
||||||
|
|
||||||
SearchParameterMap map;
|
SearchParameterMap map;
|
||||||
|
@ -58,13 +58,10 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public class SearchParameterMap implements Serializable {
|
public class SearchParameterMap implements Serializable {
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParameterMap.class);
|
|
||||||
public static final Integer INTEGER_0 = 0;
|
public static final Integer INTEGER_0 = 0;
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParameterMap.class);
|
||||||
private final HashMap<String, List<List<IQueryParameterType>>> mySearchParameterMap = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
private final HashMap<String, List<List<IQueryParameterType>>> mySearchParameterMap = new LinkedHashMap<>();
|
||||||
private Integer myCount;
|
private Integer myCount;
|
||||||
private Integer myOffset;
|
private Integer myOffset;
|
||||||
private EverythingModeEnum myEverythingMode = null;
|
private EverythingModeEnum myEverythingMode = null;
|
||||||
@ -81,7 +78,7 @@ public class SearchParameterMap implements Serializable {
|
|||||||
private Integer myLastNMax;
|
private Integer myLastNMax;
|
||||||
private boolean myDeleteExpunge;
|
private boolean myDeleteExpunge;
|
||||||
private SearchContainedModeEnum mySearchContainedMode = SearchContainedModeEnum.FALSE;
|
private SearchContainedModeEnum mySearchContainedMode = SearchContainedModeEnum.FALSE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
@ -467,7 +464,9 @@ public class SearchParameterMap implements Serializable {
|
|||||||
sort = sort.getChain();
|
sort = sort.getChain();
|
||||||
}
|
}
|
||||||
|
|
||||||
addUrlIncludeParams(b, Constants.PARAM_INCLUDE, getIncludes());
|
if (hasIncludes()) {
|
||||||
|
addUrlIncludeParams(b, Constants.PARAM_INCLUDE, getIncludes());
|
||||||
|
}
|
||||||
addUrlIncludeParams(b, Constants.PARAM_REVINCLUDE, getRevIncludes());
|
addUrlIncludeParams(b, Constants.PARAM_REVINCLUDE, getRevIncludes());
|
||||||
|
|
||||||
if (getLastUpdated() != null) {
|
if (getLastUpdated() != null) {
|
||||||
@ -514,6 +513,13 @@ public class SearchParameterMap implements Serializable {
|
|||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 5.5.0
|
||||||
|
*/
|
||||||
|
public boolean hasIncludes() {
|
||||||
|
return myIncludes != null && !myIncludes.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
|
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
|
||||||
@ -555,14 +561,14 @@ public class SearchParameterMap implements Serializable {
|
|||||||
theAndOrParams.removeIf(List::isEmpty);
|
theAndOrParams.removeIf(List::isEmpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNearDistanceParam(QuantityParam theQuantityParam) {
|
|
||||||
myNearDistanceParam = theQuantityParam;
|
|
||||||
}
|
|
||||||
|
|
||||||
public QuantityParam getNearDistanceParam() {
|
public QuantityParam getNearDistanceParam() {
|
||||||
return myNearDistanceParam;
|
return myNearDistanceParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setNearDistanceParam(QuantityParam theQuantityParam) {
|
||||||
|
myNearDistanceParam = theQuantityParam;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isWantOnlyCount() {
|
public boolean isWantOnlyCount() {
|
||||||
return SummaryEnum.COUNT.equals(getSummaryMode()) || INTEGER_0.equals(getCount());
|
return SummaryEnum.COUNT.equals(getSummaryMode()) || INTEGER_0.equals(getCount());
|
||||||
}
|
}
|
||||||
@ -576,6 +582,52 @@ public class SearchParameterMap implements Serializable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<List<IQueryParameterType>> get(String theName) {
|
||||||
|
return mySearchParameterMap.get(theName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(String theName, List<List<IQueryParameterType>> theParams) {
|
||||||
|
mySearchParameterMap.put(theName, theParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsKey(String theName) {
|
||||||
|
return mySearchParameterMap.containsKey(theName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> keySet() {
|
||||||
|
return mySearchParameterMap.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return mySearchParameterMap.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapper methods
|
||||||
|
|
||||||
|
public Set<Map.Entry<String, List<List<IQueryParameterType>>>> entrySet() {
|
||||||
|
return mySearchParameterMap.entrySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<List<IQueryParameterType>> remove(String theName) {
|
||||||
|
return mySearchParameterMap.remove(theName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return mySearchParameterMap.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SearchContainedModeEnum getSearchContainedMode() {
|
||||||
|
return mySearchContainedMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSearchContainedMode(SearchContainedModeEnum theSearchContainedMode) {
|
||||||
|
if (theSearchContainedMode == null) {
|
||||||
|
mySearchContainedMode = SearchContainedModeEnum.FALSE;
|
||||||
|
} else {
|
||||||
|
this.mySearchContainedMode = theSearchContainedMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public enum EverythingModeEnum {
|
public enum EverythingModeEnum {
|
||||||
/*
|
/*
|
||||||
* Don't reorder! We rely on the ordinals
|
* Don't reorder! We rely on the ordinals
|
||||||
@ -689,40 +741,6 @@ public class SearchParameterMap implements Serializable {
|
|||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrapper methods
|
|
||||||
|
|
||||||
public List<List<IQueryParameterType>> get(String theName) {
|
|
||||||
return mySearchParameterMap.get(theName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void put(String theName, List<List<IQueryParameterType>> theParams) {
|
|
||||||
mySearchParameterMap.put(theName, theParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean containsKey(String theName) {
|
|
||||||
return mySearchParameterMap.containsKey(theName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> keySet() {
|
|
||||||
return mySearchParameterMap.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return mySearchParameterMap.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<Map.Entry<String, List<List<IQueryParameterType>>>> entrySet() {
|
|
||||||
return mySearchParameterMap.entrySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<List<IQueryParameterType>> remove(String theName) {
|
|
||||||
return mySearchParameterMap.remove(theName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size() {
|
|
||||||
return mySearchParameterMap.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SearchParameterMap newSynchronous() {
|
public static SearchParameterMap newSynchronous() {
|
||||||
SearchParameterMap retVal = new SearchParameterMap();
|
SearchParameterMap retVal = new SearchParameterMap();
|
||||||
retVal.setLoadSynchronous(true);
|
retVal.setLoadSynchronous(true);
|
||||||
@ -736,17 +754,5 @@ public class SearchParameterMap implements Serializable {
|
|||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SearchContainedModeEnum getSearchContainedMode() {
|
|
||||||
return mySearchContainedMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSearchContainedMode(SearchContainedModeEnum theSearchContainedMode) {
|
|
||||||
if (theSearchContainedMode == null) {
|
|
||||||
mySearchContainedMode = SearchContainedModeEnum.FALSE;
|
|
||||||
} else {
|
|
||||||
this.mySearchContainedMode = theSearchContainedMode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
2
pom.xml
2
pom.xml
@ -2204,7 +2204,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.puppycrawl.tools</groupId>
|
<groupId>com.puppycrawl.tools</groupId>
|
||||||
<artifactId>checkstyle</artifactId>
|
<artifactId>checkstyle</artifactId>
|
||||||
<version>8.41.1</version>
|
<version>8.42</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<configuration>
|
<configuration>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user