diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_4_0/4426-add-sort-capability-to-mdm-query-links-operation.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_4_0/4426-add-sort-capability-to-mdm-query-links-operation.yaml
new file mode 100644
index 00000000000..741f914e7d6
--- /dev/null
+++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_4_0/4426-add-sort-capability-to-mdm-query-links-operation.yaml
@@ -0,0 +1,4 @@
+---
+type: add
+issue: 4426
+title: "Added sorting capability to $mdm-query-links operation."
diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_mdm/mdm_operations.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_mdm/mdm_operations.md
index 76b55a1d97e..bcfc3853788 100644
--- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_mdm/mdm_operations.md
+++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_mdm/mdm_operations.md
@@ -113,6 +113,14 @@ Use the `$mdm-query-links` operation to view MDM links. The results returned are
The number of links to be returned in a page.
+
+ _sort
+ String
+ 0..1
+
+ The sort specification (see sort note below).
+
+
resourceType
String
@@ -124,6 +132,12 @@ Use the `$mdm-query-links` operation to view MDM links. The results returned are
+Sort note: sort is specified by adding one or more comma-separated MdmLink property names prefixed by '-' (minus sign) to indicate descending order.
+
+#### Sort specification example
+```url
+http://example.com/$mdm-query-links?_sort=-myScore,myCreated
+```
### Example
Use an HTTP GET like `http://example.com/$mdm-query-links?matchResult=POSSIBLE_MATCH` or an HTTP POST to the following URL to invoke this operation:
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/mdm/MdmLinkDaoJpaImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/mdm/MdmLinkDaoJpaImpl.java
index 335809dcd7c..0e122b87981 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/mdm/MdmLinkDaoJpaImpl.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/mdm/MdmLinkDaoJpaImpl.java
@@ -33,6 +33,7 @@ import ca.uhn.fhir.mdm.api.MdmQuerySearchParameters;
import ca.uhn.fhir.mdm.api.paging.MdmPageRequest;
import ca.uhn.fhir.mdm.dao.IMdmLinkDao;
import ca.uhn.fhir.mdm.model.MdmPidTuple;
+import ca.uhn.fhir.rest.api.SortOrderEnum;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
@@ -49,14 +50,26 @@ import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
+import javax.persistence.criteria.Order;
+import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
+import javax.validation.constraints.NotNull;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
+import static ca.uhn.fhir.mdm.api.MdmQuerySearchParameters.GOLDEN_RESOURCE_NAME;
+import static ca.uhn.fhir.mdm.api.MdmQuerySearchParameters.GOLDEN_RESOURCE_PID_NAME;
+import static ca.uhn.fhir.mdm.api.MdmQuerySearchParameters.LINK_SOURCE_NAME;
+import static ca.uhn.fhir.mdm.api.MdmQuerySearchParameters.MATCH_RESULT_NAME;
+import static ca.uhn.fhir.mdm.api.MdmQuerySearchParameters.PARTITION_ID_NAME;
+import static ca.uhn.fhir.mdm.api.MdmQuerySearchParameters.RESOURCE_TYPE_NAME;
+import static ca.uhn.fhir.mdm.api.MdmQuerySearchParameters.SOURCE_PID_NAME;
+
public class MdmLinkDaoJpaImpl implements IMdmLinkDao {
@Autowired
IMdmLinkJpaRepository myMdmLinkDao;
@@ -107,7 +120,7 @@ public class MdmLinkDaoJpaImpl implements IMdmLinkDao {
public List findPidByResourceNameAndThreshold(String theResourceName, Date theHighThreshold, Pageable thePageable) {
return myMdmLinkDao.findPidByResourceNameAndThreshold(theResourceName,theHighThreshold, thePageable)
.stream()
- .map( theResourcePids -> JpaPid.fromId(theResourcePids))
+ .map(JpaPid::fromId)
.collect(Collectors.toList());
}
@@ -115,7 +128,7 @@ public class MdmLinkDaoJpaImpl implements IMdmLinkDao {
public List findPidByResourceNameAndThresholdAndPartitionId(String theResourceName, Date theHighThreshold, List thePartitionIds, Pageable thePageable) {
return myMdmLinkDao.findPidByResourceNameAndThresholdAndPartitionId(theResourceName,theHighThreshold, thePartitionIds, thePageable)
.stream()
- .map( theResourcePids -> JpaPid.fromId(theResourcePids))
+ .map(JpaPid::fromId)
.collect(Collectors.toList());
}
@@ -183,8 +196,14 @@ public class MdmLinkDaoJpaImpl implements IMdmLinkDao {
@Override
@Deprecated
- public Page search(IIdType theGoldenResourceId, IIdType theSourceId, MdmMatchResultEnum theMatchResult, MdmLinkSourceEnum theLinkSource, MdmPageRequest thePageRequest, List thePartitionId) {
- MdmQuerySearchParameters mdmQuerySearchParameters = new MdmQuerySearchParameters(theGoldenResourceId, theSourceId, theMatchResult, theLinkSource, thePageRequest, thePartitionId, null);
+ public Page search(IIdType theGoldenResourceId, IIdType theSourceId, MdmMatchResultEnum theMatchResult,
+ MdmLinkSourceEnum theLinkSource, MdmPageRequest thePageRequest, List thePartitionIds) {
+ MdmQuerySearchParameters mdmQuerySearchParameters = new MdmQuerySearchParameters(thePageRequest)
+ .setGoldenResourceId(theGoldenResourceId)
+ .setSourceId(theSourceId)
+ .setMatchResult(theMatchResult)
+ .setLinkSource(theLinkSource)
+ .setPartitionIds(thePartitionIds);
return search(mdmQuerySearchParameters);
}
@@ -193,37 +212,14 @@ public class MdmLinkDaoJpaImpl implements IMdmLinkDao {
CriteriaBuilder criteriaBuilder = myEntityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(MdmLink.class);
Root from = criteriaQuery.from(MdmLink.class);
+ List orderList = getOrderList(theParams, criteriaBuilder, from);
- List andPredicates = new ArrayList<>();
-
- if (theParams.getGoldenResourceId() != null) {
- Predicate goldenResourcePredicate = criteriaBuilder.equal(from.get("myGoldenResourcePid").as(Long.class), (myIdHelperService.getPidOrThrowException(RequestPartitionId.allPartitions(), theParams.getGoldenResourceId())).getId());
- andPredicates.add(goldenResourcePredicate);
- }
- if (theParams.getSourceId() != null) {
- Predicate sourceIdPredicate = criteriaBuilder.equal(from.get("mySourcePid").as(Long.class), (myIdHelperService.getPidOrThrowException(RequestPartitionId.allPartitions(), theParams.getSourceId())).getId());
- andPredicates.add(sourceIdPredicate);
- }
- if (theParams.getMatchResult() != null) {
- Predicate matchResultPredicate = criteriaBuilder.equal(from.get("myMatchResult").as(MdmMatchResultEnum.class), theParams.getMatchResult());
- andPredicates.add(matchResultPredicate);
- }
- if (theParams.getLinkSource() != null) {
- Predicate linkSourcePredicate = criteriaBuilder.equal(from.get("myLinkSource").as(MdmLinkSourceEnum.class), theParams.getLinkSource());
- andPredicates.add(linkSourcePredicate);
- }
- if (!CollectionUtils.isEmpty(theParams.getPartitionIds())) {
- Expression exp = from.get("myPartitionId").get("myPartitionId").as(Integer.class);
- Predicate linkSourcePredicate = exp.in(theParams.getPartitionIds());
- andPredicates.add(linkSourcePredicate);
- }
-
- if (theParams.getResourceType() != null) {
- Predicate resourceTypePredicate = criteriaBuilder.equal(from.get("myGoldenResource").get("myResourceType").as(String.class), theParams.getResourceType());
- andPredicates.add(resourceTypePredicate);
- }
+ List andPredicates = buildPredicates(theParams, criteriaBuilder, from);
Predicate finalQuery = criteriaBuilder.and(andPredicates.toArray(new Predicate[0]));
+ if ( ! orderList.isEmpty()) {
+ criteriaQuery.orderBy(orderList);
+ }
TypedQuery typedQuery = myEntityManager.createQuery(criteriaQuery.where(finalQuery));
CriteriaQuery countQuery = criteriaBuilder.createQuery(Long.class);
@@ -232,11 +228,63 @@ public class MdmLinkDaoJpaImpl implements IMdmLinkDao {
Long totalResults = myEntityManager.createQuery(countQuery).getSingleResult();
MdmPageRequest pageRequest = theParams.getPageRequest();
- return new PageImpl<>(typedQuery.setFirstResult(pageRequest.getOffset()).setMaxResults(pageRequest.getCount()).getResultList(),
+
+ List result = typedQuery
+ .setFirstResult(pageRequest.getOffset())
+ .setMaxResults(pageRequest.getCount())
+ .getResultList();
+
+ return new PageImpl<>(result,
PageRequest.of(pageRequest.getPage(), pageRequest.getCount()),
totalResults);
}
+ @NotNull
+ private List buildPredicates(MdmQuerySearchParameters theParams, CriteriaBuilder criteriaBuilder, Root from) {
+ List andPredicates = new ArrayList<>();
+ if (theParams.getGoldenResourceId() != null) {
+ Predicate goldenResourcePredicate = criteriaBuilder.equal(from.get(GOLDEN_RESOURCE_PID_NAME).as(Long.class), (myIdHelperService.getPidOrThrowException(RequestPartitionId.allPartitions(), theParams.getGoldenResourceId())).getId());
+ andPredicates.add(goldenResourcePredicate);
+ }
+ if (theParams.getSourceId() != null) {
+ Predicate sourceIdPredicate = criteriaBuilder.equal(from.get(SOURCE_PID_NAME).as(Long.class), (myIdHelperService.getPidOrThrowException(RequestPartitionId.allPartitions(), theParams.getSourceId())).getId());
+ andPredicates.add(sourceIdPredicate);
+ }
+ if (theParams.getMatchResult() != null) {
+ Predicate matchResultPredicate = criteriaBuilder.equal(from.get(MATCH_RESULT_NAME).as(MdmMatchResultEnum.class), theParams.getMatchResult());
+ andPredicates.add(matchResultPredicate);
+ }
+ if (theParams.getLinkSource() != null) {
+ Predicate linkSourcePredicate = criteriaBuilder.equal(from.get(LINK_SOURCE_NAME).as(MdmLinkSourceEnum.class), theParams.getLinkSource());
+ andPredicates.add(linkSourcePredicate);
+ }
+ if (!CollectionUtils.isEmpty(theParams.getPartitionIds())) {
+ Expression exp = from.get(PARTITION_ID_NAME).get(PARTITION_ID_NAME).as(Integer.class);
+ Predicate linkSourcePredicate = exp.in(theParams.getPartitionIds());
+ andPredicates.add(linkSourcePredicate);
+ }
+
+ if (theParams.getResourceType() != null) {
+ Predicate resourceTypePredicate = criteriaBuilder.equal(from.get(GOLDEN_RESOURCE_NAME).get(RESOURCE_TYPE_NAME).as(String.class), theParams.getResourceType());
+ andPredicates.add(resourceTypePredicate);
+ }
+
+ return andPredicates;
+ }
+
+
+ private List getOrderList(MdmQuerySearchParameters theParams, CriteriaBuilder criteriaBuilder, Root from) {
+ if (CollectionUtils.isEmpty(theParams.getSort())) {
+ return Collections.emptyList();
+ }
+
+ return theParams.getSort().stream().map(sortSpec -> {
+ Path path = from.get(sortSpec.getParamName());
+ return sortSpec.getOrder() == SortOrderEnum.DESC ? criteriaBuilder.desc(path) : criteriaBuilder.asc(path);
+ })
+ .collect(Collectors.toList());
+ }
+
@Override
public Optional findBySourcePidAndMatchResult(JpaPid theSourcePid, MdmMatchResultEnum theMatch) {
return myMdmLinkDao.findBySourcePidAndMatchResult((theSourcePid).getId(), theMatch);
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmControllerSvcImpl.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmControllerSvcImpl.java
index 0fec83d773a..57093c633d3 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmControllerSvcImpl.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmControllerSvcImpl.java
@@ -103,14 +103,24 @@ public class MdmControllerSvcImpl implements IMdmControllerSvc {
@Override
@Deprecated
public Page queryLinks(@Nullable String theGoldenResourceId, @Nullable String theSourceResourceId, @Nullable String theMatchResult, @Nullable String theLinkSource, MdmTransactionContext theMdmTransactionContext, MdmPageRequest thePageRequest) {
- MdmQuerySearchParameters mdmQuerySearchParameters = new MdmQuerySearchParameters(theGoldenResourceId, theSourceResourceId, theMatchResult, theLinkSource, thePageRequest, null, null);
+ MdmQuerySearchParameters mdmQuerySearchParameters = new MdmQuerySearchParameters(thePageRequest)
+ .setGoldenResourceId(theGoldenResourceId)
+ .setSourceId(theSourceResourceId)
+ .setMatchResult(theMatchResult)
+ .setLinkSource(theLinkSource);
return queryLinksFromPartitionList(mdmQuerySearchParameters, theMdmTransactionContext);
}
@Override
@Deprecated
- public Page queryLinks(@Nullable String theGoldenResourceId, @Nullable String theSourceResourceId, @Nullable String theMatchResult, @Nullable String theLinkSource, MdmTransactionContext theMdmTransactionContext, MdmPageRequest thePageRequest, @Nullable RequestDetails theRequestDetails) {
- MdmQuerySearchParameters mdmQuerySearchParameters = new MdmQuerySearchParameters(theGoldenResourceId, theSourceResourceId, theMatchResult, theLinkSource, thePageRequest, null, null);
+ public Page queryLinks(@Nullable String theGoldenResourceId, @Nullable String theSourceResourceId,
+ @Nullable String theMatchResult, @Nullable String theLinkSource, MdmTransactionContext theMdmTransactionContext,
+ MdmPageRequest thePageRequest, @Nullable RequestDetails theRequestDetails) {
+ MdmQuerySearchParameters mdmQuerySearchParameters = new MdmQuerySearchParameters(thePageRequest)
+ .setGoldenResourceId(theGoldenResourceId)
+ .setSourceId(theSourceResourceId)
+ .setMatchResult(theMatchResult)
+ .setLinkSource(theLinkSource);
return queryLinks(mdmQuerySearchParameters, theMdmTransactionContext, theRequestDetails);
}
@@ -130,8 +140,16 @@ public class MdmControllerSvcImpl implements IMdmControllerSvc {
@Override
@Deprecated
- public Page queryLinksFromPartitionList(@Nullable String theGoldenResourceId, @Nullable String theSourceResourceId, @Nullable String theMatchResult, @Nullable String theLinkSource, MdmTransactionContext theMdmTransactionContext, MdmPageRequest thePageRequest, @Nullable List thePartitionIds) {
- MdmQuerySearchParameters mdmQuerySearchParameters = new MdmQuerySearchParameters(theGoldenResourceId, theSourceResourceId, theMatchResult, theLinkSource, thePageRequest, thePartitionIds, null);
+ public Page queryLinksFromPartitionList(@Nullable String theGoldenResourceId, @Nullable String theSourceResourceId,
+ @Nullable String theMatchResult, @Nullable String theLinkSource,
+ MdmTransactionContext theMdmTransactionContext, MdmPageRequest thePageRequest,
+ @Nullable List thePartitionIds) {
+ MdmQuerySearchParameters mdmQuerySearchParameters = new MdmQuerySearchParameters(thePageRequest)
+ .setGoldenResourceId(theGoldenResourceId)
+ .setSourceId(theSourceResourceId)
+ .setMatchResult(theMatchResult)
+ .setLinkSource(theLinkSource)
+ .setPartitionIds(thePartitionIds);
return queryLinksFromPartitionList(mdmQuerySearchParameters, theMdmTransactionContext);
}
@@ -214,7 +232,6 @@ public class MdmControllerSvcImpl implements IMdmControllerSvc {
if (theBatchSize != null && theBatchSize.getValue() !=null && theBatchSize.getValue().longValue() > 0) {
params.setBatchSize(theBatchSize.getValue().intValue());
}
- ReadPartitionIdRequestDetails details= new ReadPartitionIdRequestDetails(null, RestOperationTypeEnum.EXTENDED_OPERATION_SERVER, null, null, null);
params.setRequestPartitionId(RequestPartitionId.allPartitions());
theUrls.forEach(params::addUrl);
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkQuerySvcImplSvc.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkQuerySvcImplSvc.java
index 20783cfed73..144a43c3953 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkQuerySvcImplSvc.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkQuerySvcImplSvc.java
@@ -52,21 +52,33 @@ public class MdmLinkQuerySvcImplSvc implements IMdmLinkQuerySvc {
@Deprecated
@Transactional
public Page queryLinks(IIdType theGoldenResourceId, IIdType theSourceResourceId, MdmMatchResultEnum theMatchResult, MdmLinkSourceEnum theLinkSource, MdmTransactionContext theMdmContext, MdmPageRequest thePageRequest) {
- MdmQuerySearchParameters mdmQuerySearchParameters = new MdmQuerySearchParameters(theGoldenResourceId, theSourceResourceId, theMatchResult, theLinkSource, thePageRequest, null, null);
+ MdmQuerySearchParameters mdmQuerySearchParameters = new MdmQuerySearchParameters(thePageRequest)
+ .setGoldenResourceId(theGoldenResourceId)
+ .setSourceId(theSourceResourceId)
+ .setMatchResult(theMatchResult)
+ .setLinkSource(theLinkSource);
+
return queryLinks(mdmQuerySearchParameters, theMdmContext);
}
@Override
@Deprecated
@Transactional
- public Page queryLinks(IIdType theGoldenResourceId, IIdType theSourceResourceId, MdmMatchResultEnum theMatchResult, MdmLinkSourceEnum theLinkSource, MdmTransactionContext theMdmContext, MdmPageRequest thePageRequest, List thePartitionId) {
- MdmQuerySearchParameters mdmQuerySearchParameters = new MdmQuerySearchParameters(theGoldenResourceId, theSourceResourceId, theMatchResult, theLinkSource, thePageRequest, thePartitionId, null);
+ public Page queryLinks(IIdType theGoldenResourceId, IIdType theSourceResourceId, MdmMatchResultEnum theMatchResult, MdmLinkSourceEnum theLinkSource, MdmTransactionContext theMdmContext, MdmPageRequest thePageRequest, List thePartitionIds) {
+ MdmQuerySearchParameters mdmQuerySearchParameters = new MdmQuerySearchParameters(thePageRequest)
+ .setGoldenResourceId(theGoldenResourceId)
+ .setSourceId(theSourceResourceId)
+ .setMatchResult(theMatchResult)
+ .setLinkSource(theLinkSource)
+ .setPartitionIds(thePartitionIds);
+
return queryLinks(mdmQuerySearchParameters, theMdmContext);
}
@Override
@Transactional
public Page queryLinks(MdmQuerySearchParameters theMdmQuerySearchParameters, MdmTransactionContext theMdmContext) {
+ @SuppressWarnings("unchecked")
Page extends IMdmLink> mdmLinks = myMdmLinkDaoSvc.executeTypedQuery(theMdmQuerySearchParameters);
return mdmLinks.map(myMdmModelConverterSvc::toJson);
}
@@ -80,9 +92,14 @@ public class MdmLinkQuerySvcImplSvc implements IMdmLinkQuerySvc {
@Override
@Transactional
- public Page getDuplicateGoldenResources(MdmTransactionContext theMdmContext, MdmPageRequest thePageRequest, List thePartitionId, String theRequestResourceType) {
- MdmQuerySearchParameters mdmQuerySearchParameters =
- new MdmQuerySearchParameters(null, null, MdmMatchResultEnum.POSSIBLE_DUPLICATE, null, thePageRequest, thePartitionId, theRequestResourceType);
+ public Page getDuplicateGoldenResources(MdmTransactionContext theMdmContext, MdmPageRequest thePageRequest,
+ List thePartitionIds, String theRequestResourceType) {
+ MdmQuerySearchParameters mdmQuerySearchParameters = new MdmQuerySearchParameters(thePageRequest)
+ .setMatchResult(MdmMatchResultEnum.POSSIBLE_DUPLICATE)
+ .setPartitionIds(thePartitionIds)
+ .setResourceType(theRequestResourceType);
+
+ @SuppressWarnings("unchecked")
Page extends IMdmLink> mdmLinkPage = myMdmLinkDaoSvc.executeTypedQuery(mdmQuerySearchParameters);
return mdmLinkPage.map(myMdmModelConverterSvc::toJson);
}
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderQueryLinkR4Test.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderQueryLinkR4Test.java
index ecb3ac04695..a8afac6393c 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderQueryLinkR4Test.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderQueryLinkR4Test.java
@@ -10,23 +10,30 @@ import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
+import ca.uhn.fhir.util.ParametersUtil;
import ca.uhn.fhir.util.StopWatch;
import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
import org.hl7.fhir.dstu3.model.UnsignedIntType;
import org.hl7.fhir.instance.model.api.IAnyResource;
+import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.BooleanType;
+import org.hl7.fhir.r4.model.DecimalType;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.StringType;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import java.util.Comparator;
import java.util.List;
+import java.util.Optional;
import java.util.stream.Collectors;
import static org.hamcrest.MatcherAssert.assertThat;
@@ -35,13 +42,16 @@ import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.lessThanOrEqualTo;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
public class MdmProviderQueryLinkR4Test extends BaseLinkR4Test {
private static final Logger ourLog = LoggerFactory.getLogger(MdmProviderQueryLinkR4Test.class);
+ private static final int MDM_LINK_PROPERTY_COUNT = 9;
private static final StringType RESOURCE_TYPE_PATIENT = new StringType("Patient");
private static final StringType RESOURCE_TYPE_OBSERVATION = new StringType("Observation");
+
private StringType myLinkSource;
private StringType myGoldenResource1Id;
private StringType myGoldenResource2Id;
@@ -74,27 +84,180 @@ public class MdmProviderQueryLinkR4Test extends BaseLinkR4Test {
@Test
public void testQueryLinkOneMatch() {
- Parameters result = (Parameters) myMdmProvider.queryLinks(mySourcePatientId, myPatientId, null, null, new UnsignedIntType(0), new UnsignedIntType(10), myRequestDetails, null);
+ Parameters result = (Parameters) myMdmProvider.queryLinks(mySourcePatientId, myPatientId, null, null, new UnsignedIntType(0), new UnsignedIntType(10), new StringType(), myRequestDetails, null);
ourLog.debug(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(result));
List list = getParametersByName(result, "link");
assertThat(list, hasSize(1));
List part = list.get(0).getPart();
- assertMdmLink(7, part, mySourcePatientId.getValue(), myPatientId.getValue(), MdmMatchResultEnum.POSSIBLE_MATCH, "false", "true", null);
+ assertMdmLink(MDM_LINK_PROPERTY_COUNT, part, mySourcePatientId.getValue(), myPatientId.getValue(), MdmMatchResultEnum.POSSIBLE_MATCH, "false", "true", null);
}
@Test
public void testQueryLinkWithResourceType() {
- Parameters result = (Parameters) myMdmProvider.queryLinks(null, null, null, null, new UnsignedIntType(0), new UnsignedIntType(10), myRequestDetails, RESOURCE_TYPE_PATIENT);
+ Parameters result = (Parameters) myMdmProvider.queryLinks(null, null, null, null, new UnsignedIntType(0), new UnsignedIntType(10), new StringType(), myRequestDetails, RESOURCE_TYPE_PATIENT);
ourLog.debug(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(result));
List list = getParametersByName(result, "link");
assertThat("All resources with Patient type found", list, hasSize(3));
List part = list.get(0).getPart();
- assertMdmLink(7, part, mySourcePatientId.getValue(), myPatientId.getValue(), MdmMatchResultEnum.POSSIBLE_MATCH, "false", "true", null);
+ assertMdmLink(MDM_LINK_PROPERTY_COUNT, part, mySourcePatientId.getValue(), myPatientId.getValue(), MdmMatchResultEnum.POSSIBLE_MATCH, "false", "true", null);
}
+
+ @Nested
+ public class QueryLinkWithSort {
+ @Test
+ public void byCreatedDescending() {
+ Parameters result = (Parameters) myMdmProvider.queryLinks(null, null, null, null,
+ new UnsignedIntType(0), new UnsignedIntType(10), new StringType("-myCreated"),
+ myRequestDetails, new StringType("Patient"));
+
+ List linkList = getParametersByName(result, "link");
+ assertThat(linkList, hasSize(3));
+
+ List createdDates = linkList.stream().map(this::extractCreated).collect(Collectors.toList());
+
+ // by created descending
+ Comparator comp = Comparator.comparingLong( (Long e) -> e).reversed();
+ List expected = createdDates.stream().sorted(comp).collect(Collectors.toList());
+
+ assertEquals(expected, createdDates);
+ }
+
+ @Test
+ public void byScoreDescending() {
+ addScoresToLinksInCreationOrder(List.of(.5d, .1d, .3d));
+
+ Parameters result = (Parameters) myMdmProvider.queryLinks(null, null, null, null,
+ new UnsignedIntType(0), new UnsignedIntType(10), new StringType("-myScore"),
+ myRequestDetails, new StringType("Patient"));
+
+ List linkList = getParametersByName(result, "link");
+ assertThat(linkList, hasSize(3));
+
+ List scores = linkList.stream().map(this::extractScore).collect(Collectors.toList());
+
+ // by score descending
+ Comparator comp = Comparator.comparingDouble( (Double e) -> e).reversed();
+ List expected = scores.stream().sorted(comp).collect(Collectors.toList());
+
+ assertEquals(expected, scores);
+ }
+
+
+ @Test
+ public void byScoreDescendingAndThenCreated() {
+ addScoresToLinksInCreationOrder(List.of(.4d, .4d, .3d));
+
+ Parameters result = (Parameters) myMdmProvider.queryLinks(null, null, null, null,
+ new UnsignedIntType(0), new UnsignedIntType(10), new StringType("-myScore,-myCreated"),
+ myRequestDetails, new StringType("Patient"));
+
+ List linkList = getParametersByName(result, "link");
+ assertThat(linkList, hasSize(3));
+
+ List> resultUpdatedScorePairs = linkList.stream()
+ .map(l -> Pair.of(extractCreated(l), extractScore(l))).collect(Collectors.toList());
+
+ // by desc score then desc created
+ Comparator> comp = Comparator
+ .comparing( (Pair p) -> p.getRight(), Comparator.reverseOrder() )
+ .thenComparing(Pair::getLeft, Comparator.reverseOrder() );
+
+ List> expected = resultUpdatedScorePairs.stream().sorted(comp).collect(Collectors.toList());
+
+ assertEquals(expected, resultUpdatedScorePairs);
+ }
+
+ @Test
+ public void testPaginationWhenSorting() {
+ addTwoMoreMdmLinks();
+ addScoresToLinksInCreationOrder(List.of(.5d, .1d, .3d, .8d, .6d));
+ List expectedScoresPage1 = List.of(.8d, .6d, .5d);
+ List expectedScoresPage2 = List.of(.3d, .1d);
+
+ int pageSize = 3;
+
+ // first page
+
+ Parameters page1 = (Parameters) myMdmProvider.queryLinks(null, null, null, null,
+ new UnsignedIntType(0), new UnsignedIntType(pageSize), new StringType("-myScore"),
+ myRequestDetails, new StringType("Patient"));
+
+ List linkListPage1 = getParametersByName(page1, "link");
+ assertThat(linkListPage1, hasSize(pageSize));
+
+ List scoresPage1 = linkListPage1.stream().map(this::extractScore).collect(Collectors.toList());
+ assertEquals(expectedScoresPage1, scoresPage1);
+
+ // second page
+
+ Parameters page2 = (Parameters) myMdmProvider.queryLinks(null, null, null, null,
+ new UnsignedIntType(pageSize), new UnsignedIntType(pageSize), new StringType("-myScore"),
+ myRequestDetails, new StringType("Patient"));
+
+ List linkListPage2 = getParametersByName(page2, "link");
+ assertThat(linkListPage2, hasSize(2));
+
+ List scoresPage2 = linkListPage2.stream().map(this::extractScore).collect(Collectors.toList());
+ assertEquals(expectedScoresPage2, scoresPage2);
+ }
+
+
+ private Long extractCreated(Parameters.ParametersParameterComponent theParamComponent) {
+ Optional opt = ParametersUtil.getParameterPartValue(myFhirContext, theParamComponent, "linkUpdated");
+ assertTrue(opt.isPresent());
+ DecimalType createdDateDt = (DecimalType) opt.get();
+ return createdDateDt.getValue().longValue();
+ }
+
+
+ private Double extractScore(Parameters.ParametersParameterComponent theParamComponent) {
+ Optional opt = ParametersUtil.getParameterPartValue(myFhirContext, theParamComponent, "score");
+ assertTrue(opt.isPresent());
+ DecimalType scoreIntegerDt = (DecimalType) opt.get();
+ assertNotNull(scoreIntegerDt.getValue());
+ return scoreIntegerDt.getValue().doubleValue();
+ }
+
+ }
+
+ private void addTwoMoreMdmLinks() {
+ createPatientAndUpdateLinks(buildFrankPatient());
+
+ // Add a possible duplicate
+ myLinkSource = new StringType(MdmLinkSourceEnum.AUTO.name());
+ Patient sourcePatient1 = createGoldenPatient();
+ myGoldenResource1Id = new StringType(sourcePatient1.getIdElement().toVersionless().getValue());
+ JpaPid sourcePatient1Pid = runInTransaction(()->myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), sourcePatient1));
+ Patient sourcePatient2 = createGoldenPatient();
+ myGoldenResource2Id = new StringType(sourcePatient2.getIdElement().toVersionless().getValue());
+ JpaPid sourcePatient2Pid = runInTransaction(()->myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), sourcePatient2));
+
+ MdmLink possibleDuplicateMdmLink = (MdmLink) myMdmLinkDaoSvc.newMdmLink();
+ possibleDuplicateMdmLink.setGoldenResourcePersistenceId(sourcePatient1Pid);
+ possibleDuplicateMdmLink.setSourcePersistenceId(sourcePatient2Pid);
+ possibleDuplicateMdmLink.setMatchResult(MdmMatchResultEnum.POSSIBLE_DUPLICATE).setLinkSource(MdmLinkSourceEnum.AUTO);
+ saveLink(possibleDuplicateMdmLink);
+ }
+
+
+ private void addScoresToLinksInCreationOrder(List theScores) {
+ List links = myMdmLinkDao.findAll();
+ assertThat(links, hasSize(theScores.size()));
+
+ links.sort( Comparator.comparing(MdmLink::getCreated) );
+
+ for (int i = 0; i < links.size(); i++) {
+ MdmLink link = links.get(i);
+ link.setScore( theScores.get(i) );
+ myMdmLinkDao.save(link);
+ }
+ }
+
+
@Test
public void testQueryLinkWithResourceTypeNoMatch() {
- Parameters result = (Parameters) myMdmProvider.queryLinks(null, null, null, null, new UnsignedIntType(0), new UnsignedIntType(10), myRequestDetails, RESOURCE_TYPE_OBSERVATION);
+ Parameters result = (Parameters) myMdmProvider.queryLinks(null, null, null, null, new UnsignedIntType(0), new UnsignedIntType(10), new StringType(), myRequestDetails, RESOURCE_TYPE_OBSERVATION);
ourLog.debug(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(result));
List list = getParametersByName(result, "link");
assertThat(list, hasSize(0));
@@ -110,7 +273,7 @@ public class MdmProviderQueryLinkR4Test extends BaseLinkR4Test {
int count = 2;
StopWatch sw = new StopWatch();
while (true) {
- Parameters result = (Parameters) myMdmProvider.queryLinks(null, null, null, myLinkSource, new UnsignedIntType(offset), new UnsignedIntType(count), myRequestDetails, null);
+ Parameters result = (Parameters) myMdmProvider.queryLinks(null, null, null, myLinkSource, new UnsignedIntType(offset), new UnsignedIntType(count), new StringType(), myRequestDetails, null);
List parameter = result.getParameter();
@@ -156,7 +319,8 @@ public class MdmProviderQueryLinkR4Test extends BaseLinkR4Test {
null, myLinkSource,
new UnsignedIntType(offset),
new UnsignedIntType(count),
- myRequestDetails,
+ new StringType(),
+ myRequestDetails,
null);
} catch (InvalidRequestException e) {
//Then
@@ -173,6 +337,7 @@ public class MdmProviderQueryLinkR4Test extends BaseLinkR4Test {
null, myLinkSource,
new UnsignedIntType(offset),
new UnsignedIntType(count),
+ new StringType(),
myRequestDetails,
null);
} catch (InvalidRequestException e) {
@@ -190,6 +355,7 @@ public class MdmProviderQueryLinkR4Test extends BaseLinkR4Test {
null, myLinkSource,
new UnsignedIntType(offset),
new UnsignedIntType(count),
+ new StringType(),
myRequestDetails,
null);
} catch (InvalidRequestException e) {
@@ -206,12 +372,12 @@ public class MdmProviderQueryLinkR4Test extends BaseLinkR4Test {
IAnyResource goldenResource = getGoldenResourceFromTargetResource(patient);
IIdType goldenResourceId = goldenResource.getIdElement().toVersionless();
- Parameters result = (Parameters) myMdmProvider.queryLinks(null, null, null, myLinkSource, new UnsignedIntType(0), new UnsignedIntType(10), myRequestDetails, null);
+ Parameters result = (Parameters) myMdmProvider.queryLinks(null, null, null, myLinkSource, new UnsignedIntType(0), new UnsignedIntType(10), new StringType(), myRequestDetails, null);
ourLog.debug(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(result));
List list = getParametersByName(result, "link");
assertThat(list, hasSize(4));
List part = list.get(3).getPart();
- assertMdmLink(7, part, goldenResourceId.getValue(), patientId.getValue(), MdmMatchResultEnum.MATCH, "false", "false", "2");
+ assertMdmLink(MDM_LINK_PROPERTY_COUNT, part, goldenResourceId.getValue(), patientId.getValue(), MdmMatchResultEnum.MATCH, "false", "false", "2");
}
@Test
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmControllerSvcImplTest.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmControllerSvcImplTest.java
index 2c0f722b11f..52f5a216fe6 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmControllerSvcImplTest.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmControllerSvcImplTest.java
@@ -106,8 +106,9 @@ public class MdmControllerSvcImplTest extends BaseLinkR4Test {
assertEquals(MdmLinkSourceEnum.AUTO, link.getLinkSource());
assertLinkCount(2);
- MdmQuerySearchParameters params = new MdmQuerySearchParameters(null, myPatientId.getIdElement().getValue(), null, null,
- new MdmPageRequest((Integer) null, null, DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE), null, null);
+ MdmPageRequest pageRequest = new MdmPageRequest((Integer) null, null, DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE);
+ MdmQuerySearchParameters params = new MdmQuerySearchParameters(pageRequest)
+ .setSourceId(myPatientId.getIdElement().getValue());
Page resultPage = myMdmControllerSvc.queryLinks(params,
new MdmTransactionContext(MdmTransactionContext.OperationType.QUERY_LINKS),
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/MdmQuerySearchParameters.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/MdmQuerySearchParameters.java
index 0cf1601d588..ec747c84979 100644
--- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/MdmQuerySearchParameters.java
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/MdmQuerySearchParameters.java
@@ -20,16 +20,41 @@ package ca.uhn.fhir.mdm.api;
* #L%
*/
+import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.mdm.api.paging.MdmPageRequest;
import ca.uhn.fhir.mdm.provider.MdmControllerUtil;
+import ca.uhn.fhir.rest.api.SortOrderEnum;
+import ca.uhn.fhir.rest.api.SortSpec;
+import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.hl7.fhir.instance.model.api.IIdType;
import javax.annotation.Nullable;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
+
+import static org.hibernate.internal.util.StringHelper.isBlank;
public class MdmQuerySearchParameters {
+
+ public static final String GOLDEN_RESOURCE_PID_NAME = "myGoldenResourcePid";
+ public static final String SOURCE_PID_NAME = "mySourcePid";
+ public static final String MATCH_RESULT_NAME = "myMatchResult";
+ public static final String LINK_SOURCE_NAME = "myLinkSource";
+ public static final String PARTITION_ID_NAME = "myPartitionId";
+ public static final String GOLDEN_RESOURCE_NAME = "myGoldenResource";
+ public static final String RESOURCE_TYPE_NAME = "myResourceType";
+ public static final String CREATED_NAME = "myCreated";
+ public static final String UPDATED_NAME = "myUpdated";
+ public static final String SCORE_NAME = "myScore";
+
+ public static final Set ourValidSortParameters = Set.of(
+ GOLDEN_RESOURCE_PID_NAME, SOURCE_PID_NAME, MATCH_RESULT_NAME, LINK_SOURCE_NAME, PARTITION_ID_NAME, GOLDEN_RESOURCE_NAME,
+ RESOURCE_TYPE_NAME, CREATED_NAME, UPDATED_NAME, SCORE_NAME
+ );
+
private IIdType myGoldenResourceId;
private IIdType mySourceId;
private MdmMatchResultEnum myMatchResult;
@@ -37,9 +62,16 @@ public class MdmQuerySearchParameters {
private MdmPageRequest myPageRequest;
private List myPartitionIds;
private String myResourceType;
+ private final List mySort = new ArrayList<>();
+ @Deprecated(since = "2023.02.R01", forRemoval = true)
public MdmQuerySearchParameters() {}
+ public MdmQuerySearchParameters(MdmPageRequest thePageRequest) {
+ setPageRequest(thePageRequest);
+ }
+
+ @Deprecated(since = "2023.02.R01", forRemoval = true)
public MdmQuerySearchParameters(@Nullable String theGoldenResourceId, @Nullable String theSourceId, @Nullable String theMatchResult, @Nullable String theLinkSource, MdmPageRequest thePageRequest, @Nullable List thePartitionIds, @Nullable String theResourceType) {
setGoldenResourceId(theGoldenResourceId);
setSourceId(theSourceId);
@@ -50,6 +82,7 @@ public class MdmQuerySearchParameters {
setResourceType(theResourceType);
}
+ @Deprecated(since = "2023.02.R01", forRemoval = true)
public MdmQuerySearchParameters(@Nullable IIdType theGoldenResourceId, @Nullable IIdType theSourceId, @Nullable MdmMatchResultEnum theMatchResult, @Nullable MdmLinkSourceEnum theLinkSource, MdmPageRequest thePageRequest, @Nullable List thePartitionIds, @Nullable String theResourceType) {
setGoldenResourceId(theGoldenResourceId);
setSourceId(theSourceId);
@@ -64,52 +97,56 @@ public class MdmQuerySearchParameters {
return myGoldenResourceId;
}
- public void setGoldenResourceId(IIdType theGoldenResourceId) {
+ public MdmQuerySearchParameters setGoldenResourceId(IIdType theGoldenResourceId) {
myGoldenResourceId = theGoldenResourceId;
+ return this;
}
- public void setGoldenResourceId(String theGoldenResourceId) {
- IIdType goldenResourceId = MdmControllerUtil.extractGoldenResourceIdDtOrNull(ProviderConstants.MDM_QUERY_LINKS_GOLDEN_RESOURCE_ID, theGoldenResourceId);
- myGoldenResourceId = goldenResourceId;
+ public MdmQuerySearchParameters setGoldenResourceId(String theGoldenResourceId) {
+ myGoldenResourceId = MdmControllerUtil.extractGoldenResourceIdDtOrNull(ProviderConstants.MDM_QUERY_LINKS_GOLDEN_RESOURCE_ID, theGoldenResourceId);
+ return this;
}
public IIdType getSourceId() {
return mySourceId;
}
- public void setSourceId(IIdType theSourceId) {
+ public MdmQuerySearchParameters setSourceId(IIdType theSourceId) {
mySourceId = theSourceId;
+ return this;
}
- public void setSourceId(String theSourceId) {
- IIdType sourceId = MdmControllerUtil.extractSourceIdDtOrNull(ProviderConstants.MDM_QUERY_LINKS_RESOURCE_ID, theSourceId);
- mySourceId = sourceId;
+ public MdmQuerySearchParameters setSourceId(String theSourceId) {
+ mySourceId = MdmControllerUtil.extractSourceIdDtOrNull(ProviderConstants.MDM_QUERY_LINKS_RESOURCE_ID, theSourceId);
+ return this;
}
public MdmMatchResultEnum getMatchResult() {
return myMatchResult;
}
- public void setMatchResult(MdmMatchResultEnum theMatchResult) {
+ public MdmQuerySearchParameters setMatchResult(MdmMatchResultEnum theMatchResult) {
myMatchResult = theMatchResult;
+ return this;
}
- public void setMatchResult(String theMatchResult) {
- MdmMatchResultEnum matchResult = MdmControllerUtil.extractMatchResultOrNull(theMatchResult);
- myMatchResult = matchResult;
+ public MdmQuerySearchParameters setMatchResult(String theMatchResult) {
+ myMatchResult = MdmControllerUtil.extractMatchResultOrNull(theMatchResult);
+ return this;
}
public MdmLinkSourceEnum getLinkSource() {
return myLinkSource;
}
- public void setLinkSource(MdmLinkSourceEnum theLinkSource) {
+ public MdmQuerySearchParameters setLinkSource(MdmLinkSourceEnum theLinkSource) {
myLinkSource = theLinkSource;
+ return this;
}
- public void setLinkSource(String theLinkSource) {
- MdmLinkSourceEnum linkSource = MdmControllerUtil.extractLinkSourceOrNull(theLinkSource);
- myLinkSource = linkSource;
+ public MdmQuerySearchParameters setLinkSource(String theLinkSource) {
+ myLinkSource = MdmControllerUtil.extractLinkSourceOrNull(theLinkSource);
+ return this;
}
public MdmPageRequest getPageRequest() {
@@ -124,28 +161,51 @@ public class MdmQuerySearchParameters {
return myPartitionIds;
}
- public void setPartitionIds(List thePartitionIds) {
+ public MdmQuerySearchParameters setPartitionIds(List thePartitionIds) {
myPartitionIds = thePartitionIds;
+ return this;
}
public String getResourceType() {
return myResourceType;
}
- public void setResourceType(String theResourceType) {
+ public MdmQuerySearchParameters setResourceType(String theResourceType) {
myResourceType = theResourceType;
+ return this;
+ }
+
+ public List getSort() {
+ return mySort;
+ }
+
+ public MdmQuerySearchParameters setSort(String theSortString) {
+ if (isBlank(theSortString)) {
+ return this;
+ }
+
+ for (String param : theSortString.split(",")) {
+ String p = (param.startsWith("-") ? param.substring(1) : param).trim();
+ if ( ! MdmQuerySearchParameters.ourValidSortParameters.contains(p)) {
+ throw new InvalidRequestException(Msg.code(2233) + "Unrecognized sort parameter: " + p + ". Valid parameters are: " +
+ String.join(", ", MdmQuerySearchParameters.ourValidSortParameters));
+ }
+ SortOrderEnum order = param.startsWith("-") ? SortOrderEnum.DESC : SortOrderEnum.ASC;
+ mySort.add( new SortSpec(p, order) );
+ }
+ return this;
}
@Override
public String toString() {
return new ToStringBuilder(this)
- .append("myGoldenResourceId", myGoldenResourceId)
- .append("mySourceId", mySourceId)
- .append("myMatchResult", myMatchResult)
- .append("myLinkSource", myLinkSource)
- .append("myPartitionId", myPartitionIds)
+ .append(GOLDEN_RESOURCE_PID_NAME, myGoldenResourceId)
+ .append(SOURCE_PID_NAME, mySourceId)
+ .append(MATCH_RESULT_NAME, myMatchResult)
+ .append(LINK_SOURCE_NAME, myLinkSource)
+ .append(PARTITION_ID_NAME, myPartitionIds)
+ .append(RESOURCE_TYPE_NAME, myResourceType)
.append("myPageRequest", myPageRequest)
- .append("myResourceType", myResourceType)
.toString();
}
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/BaseMdmProvider.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/BaseMdmProvider.java
index 51c2eb6b44c..926ebbd5773 100644
--- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/BaseMdmProvider.java
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/BaseMdmProvider.java
@@ -20,8 +20,8 @@ package ca.uhn.fhir.mdm.provider;
* #L%
*/
-import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.mdm.api.MdmLinkJson;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.api.paging.MdmPageLinkBuilder;
@@ -115,7 +115,8 @@ public abstract class BaseMdmProvider {
return theString.getValue();
}
- protected IBaseParameters parametersFromMdmLinks(Page theMdmLinkStream, boolean includeResultAndSource, ServletRequestDetails theServletRequestDetails, MdmPageRequest thePageRequest) {
+ protected IBaseParameters parametersFromMdmLinks(Page theMdmLinkStream, boolean includeResultAndSource,
+ ServletRequestDetails theServletRequestDetails, MdmPageRequest thePageRequest) {
IBaseParameters retval = ParametersUtil.newInstance(myFhirContext);
addPagingParameters(retval, theMdmLinkStream, theServletRequestDetails, thePageRequest);
theMdmLinkStream.getContent().forEach(mdmLink -> {
@@ -129,6 +130,8 @@ public abstract class BaseMdmProvider {
ParametersUtil.addPartBoolean(myFhirContext, resultPart, "eidMatch", mdmLink.getEidMatch());
ParametersUtil.addPartBoolean(myFhirContext, resultPart, "hadToCreateNewResource", mdmLink.getLinkCreatedNewResource());
ParametersUtil.addPartDecimal(myFhirContext, resultPart, "score", mdmLink.getScore());
+ ParametersUtil.addPartDecimal(myFhirContext, resultPart, "linkCreated", (double) mdmLink.getCreated().getTime());
+ ParametersUtil.addPartDecimal(myFhirContext, resultPart, "linkUpdated", (double) mdmLink.getUpdated().getTime());
}
});
return retval;
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/MdmProviderDstu3Plus.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/MdmProviderDstu3Plus.java
index 44fa42db52f..eb4a5e70a1d 100644
--- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/MdmProviderDstu3Plus.java
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/MdmProviderDstu3Plus.java
@@ -182,25 +182,30 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
@OperationParam(name = ProviderConstants.MDM_QUERY_LINKS_LINK_SOURCE, min = 0, max = 1, typeName = "string")
IPrimitiveType theLinkSource,
- @Description(formalDefinition = "Results from this method are returned across multiple pages. This parameter controls the offset when fetching a page.")
+ @Description(value = "Results from this method are returned across multiple pages. This parameter controls the offset when fetching a page.")
@OperationParam(name = PARAM_OFFSET, min = 0, max = 1, typeName = "integer")
IPrimitiveType theOffset,
- @Description(formalDefinition = "Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
+
+ @Description(value = "Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
@OperationParam(name = Constants.PARAM_COUNT, min = 0, max = 1, typeName = "integer")
IPrimitiveType theCount,
+
+ @OperationParam(name = Constants.PARAM_SORT, min = 0, max = 1, typeName = "string")
+ IPrimitiveType theSort,
+
ServletRequestDetails theRequestDetails,
@OperationParam(name = ProviderConstants.MDM_RESOURCE_TYPE, min = 0, max = 1, typeName = "string") IPrimitiveType theResourceType
) {
MdmPageRequest mdmPageRequest = new MdmPageRequest(theOffset, theCount, DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE);
MdmTransactionContext mdmContext = createMdmContext(theRequestDetails, MdmTransactionContext.OperationType.QUERY_LINKS,
getResourceType(ProviderConstants.MDM_QUERY_LINKS_GOLDEN_RESOURCE_ID, theGoldenResourceId, theResourceType));
- MdmQuerySearchParameters mdmQuerySearchParameters = new MdmQuerySearchParameters();
- mdmQuerySearchParameters.setGoldenResourceId(extractStringOrNull(theGoldenResourceId));
- mdmQuerySearchParameters.setSourceId(extractStringOrNull(theResourceId));
- mdmQuerySearchParameters.setLinkSource(extractStringOrNull(theLinkSource));
- mdmQuerySearchParameters.setMatchResult(extractStringOrNull(theMatchResult));
- mdmQuerySearchParameters.setPageRequest(mdmPageRequest);
- mdmQuerySearchParameters.setResourceType(extractStringOrNull(theResourceType));
+ MdmQuerySearchParameters mdmQuerySearchParameters = new MdmQuerySearchParameters(mdmPageRequest)
+ .setGoldenResourceId(extractStringOrNull(theGoldenResourceId))
+ .setSourceId(extractStringOrNull(theResourceId))
+ .setLinkSource(extractStringOrNull(theLinkSource))
+ .setMatchResult(extractStringOrNull(theMatchResult))
+ .setResourceType(extractStringOrNull(theResourceType))
+ .setSort(extractStringOrNull(theSort));
Page mdmLinkJson = myMdmControllerSvc.queryLinks(mdmQuerySearchParameters, mdmContext, theRequestDetails);
return parametersFromMdmLinks(mdmLinkJson, true, theRequestDetails, mdmPageRequest);
diff --git a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/api/MdmQuerySearchParametersTest.java b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/api/MdmQuerySearchParametersTest.java
index 6260c262927..cd9083a96f5 100644
--- a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/api/MdmQuerySearchParametersTest.java
+++ b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/api/MdmQuerySearchParametersTest.java
@@ -20,13 +20,12 @@ class MdmQuerySearchParametersTest {
@Test
public void testMdmQuerySearchParameters() {
- MdmQuerySearchParameters params = new MdmQuerySearchParameters();
+ MdmQuerySearchParameters params = new MdmQuerySearchParameters(PAGE_REQUEST);
params.setGoldenResourceId(GOLDEN_RESOURCE_ID);
params.setSourceId(SOURCE_ID);
params.setMatchResult(MATCH_RESULT);
params.setLinkSource(LINK_SOURCE);
params.setPartitionIds(PARTITION_ID);
- params.setPageRequest(PAGE_REQUEST);
params.setResourceType(RESOURCE_TYPE);
assertEquals(GOLDEN_RESOURCE_ID, params.getGoldenResourceId().getValueAsString());
assertEquals(SOURCE_ID, params.getSourceId().getValueAsString());