From 3f2ef7525accaac1112e3e58847382aa652e311f Mon Sep 17 00:00:00 2001 From: Christopher Welsch <75045836+WelschChristopher@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:39:12 +0100 Subject: [PATCH] Add sort by business key for process and case runtime instances by business key (#3868) --- .../runtime/CaseInstanceQueryProperty.java | 1 + .../caze/BaseCaseInstanceResource.java | 1 + .../CaseInstanceCollectionResourceTest.java | 22 +++++++ .../CaseInstanceQueryResourceTest.java | 65 +++++++++++++++++++ .../impl/ProcessInstanceQueryProperty.java | 1 + .../process/BaseProcessInstanceResource.java | 1 + ...ProcessInstanceCollectionResourceTest.java | 35 ++++++++++ .../ProcessInstanceQueryResourceTest.java | 60 +++++++++++++++++ 8 files changed, 186 insertions(+) diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/CaseInstanceQueryProperty.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/CaseInstanceQueryProperty.java index aa366ea1616..39446295e57 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/CaseInstanceQueryProperty.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/CaseInstanceQueryProperty.java @@ -32,6 +32,7 @@ public class CaseInstanceQueryProperty implements QueryProperty { public static final CaseInstanceQueryProperty CASE_DEFINITION_ID = new CaseInstanceQueryProperty("RES.CASE_DEF_ID_"); public static final CaseInstanceQueryProperty CASE_START_TIME = new CaseInstanceQueryProperty("RES.START_TIME_"); public static final CaseInstanceQueryProperty TENANT_ID = new CaseInstanceQueryProperty("RES.TENANT_ID_"); + public static final CaseInstanceQueryProperty BUSINESS_KEY = new CaseInstanceQueryProperty("RES.BUSINESS_KEY_"); private String name; diff --git a/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/BaseCaseInstanceResource.java b/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/BaseCaseInstanceResource.java index aeb05208f10..f9bae3b8191 100644 --- a/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/BaseCaseInstanceResource.java +++ b/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/BaseCaseInstanceResource.java @@ -50,6 +50,7 @@ public class BaseCaseInstanceResource { allowedSortProperties.put("id", CaseInstanceQueryProperty.CASE_INSTANCE_ID); allowedSortProperties.put("startTime", CaseInstanceQueryProperty.CASE_START_TIME); allowedSortProperties.put("tenantId", CaseInstanceQueryProperty.TENANT_ID); + allowedSortProperties.put("businessKey", CaseInstanceQueryProperty.BUSINESS_KEY); } @Autowired diff --git a/modules/flowable-cmmn-rest/src/test/java/org/flowable/cmmn/rest/service/api/runtime/CaseInstanceCollectionResourceTest.java b/modules/flowable-cmmn-rest/src/test/java/org/flowable/cmmn/rest/service/api/runtime/CaseInstanceCollectionResourceTest.java index 52f17f4cabf..82488ca7c83 100644 --- a/modules/flowable-cmmn-rest/src/test/java/org/flowable/cmmn/rest/service/api/runtime/CaseInstanceCollectionResourceTest.java +++ b/modules/flowable-cmmn-rest/src/test/java/org/flowable/cmmn/rest/service/api/runtime/CaseInstanceCollectionResourceTest.java @@ -264,6 +264,28 @@ public void testGetCaseInstancesTenant() throws Exception { } } + /** + * Test getting a list of case instance, using all tenant filters. + */ + @CmmnDeployment(resources = { "org/flowable/cmmn/rest/service/api/repository/oneHumanTaskCase.cmmn" }) + public void testSortByBusinessKey() throws Exception { + String businessKey3 = runtimeService.createCaseInstanceBuilder().caseDefinitionKey("oneHumanTaskCase").businessKey("businessKey3").start().getId(); + String businessKey1 = runtimeService.createCaseInstanceBuilder().caseDefinitionKey("oneHumanTaskCase").businessKey("businessKey1").start().getId(); + String businessKey2 = runtimeService.createCaseInstanceBuilder().caseDefinitionKey("oneHumanTaskCase").businessKey("businessKey2").start().getId(); + + // Test without any parameters + String url = CmmnRestUrls.createRelativeResourceUrl(CmmnRestUrls.URL_CASE_INSTANCE_COLLECTION); + assertResultsExactlyPresentInDataResponse(url, businessKey3, businessKey1, businessKey2); + + // Sort by businessKey time + url = CmmnRestUrls.createRelativeResourceUrl(CmmnRestUrls.URL_CASE_INSTANCE_COLLECTION) + "?sort=businessKey"; + assertResultsExactlyPresentInDataResponse(url, businessKey1, businessKey2, businessKey3); + + // Sort by businessKey time desc + url = CmmnRestUrls.createRelativeResourceUrl(CmmnRestUrls.URL_CASE_INSTANCE_COLLECTION) + "?sort=businessKey&order=desc"; + assertResultsExactlyPresentInDataResponse(url, businessKey3, businessKey2, businessKey1); + } + /** * Test getting a list of case instance, using the variable selector */ diff --git a/modules/flowable-cmmn-rest/src/test/java/org/flowable/cmmn/rest/service/api/runtime/CaseInstanceQueryResourceTest.java b/modules/flowable-cmmn-rest/src/test/java/org/flowable/cmmn/rest/service/api/runtime/CaseInstanceQueryResourceTest.java index f9bae2b14df..f043cadd194 100644 --- a/modules/flowable-cmmn-rest/src/test/java/org/flowable/cmmn/rest/service/api/runtime/CaseInstanceQueryResourceTest.java +++ b/modules/flowable-cmmn-rest/src/test/java/org/flowable/cmmn/rest/service/api/runtime/CaseInstanceQueryResourceTest.java @@ -475,4 +475,69 @@ public void testQueryCaseInstancesByCaseDefinitionKeys() throws Exception { assertThatJson(dataNode) .isEqualTo("[]"); } + + /** + * Test querying case instance sort by businessKey. POST query/case-instances + */ + @CmmnDeployment(resources = { "org/flowable/cmmn/rest/service/api/repository/oneHumanTaskCase.cmmn" }) + public void testSortByBusinessKey() throws Exception { + Authentication.setAuthenticatedUserId("queryCaseUser"); + runtimeService.createCaseInstanceBuilder().businessKey("businessKey3").caseDefinitionKey("oneHumanTaskCase").start(); + runtimeService.createCaseInstanceBuilder().businessKey("businessKey1").caseDefinitionKey("oneHumanTaskCase").start(); + runtimeService.createCaseInstanceBuilder().businessKey("businessKey2").caseDefinitionKey("oneHumanTaskCase").start(); + + // Create request node + ObjectNode requestNode = objectMapper.createObjectNode(); + requestNode.put("order", "asc"); + requestNode.put("sort", "businessKey"); + + String url = CmmnRestUrls.createRelativeResourceUrl(CmmnRestUrls.URL_CASE_INSTANCE_QUERY); + HttpPost httpPost = new HttpPost(SERVER_URL_PREFIX + url); + httpPost.setEntity(new StringEntity(requestNode.toString())); + CloseableHttpResponse response = executeRequest(httpPost, HttpStatus.SC_OK); + + // Check order + JsonNode rootNode = objectMapper.readTree(response.getEntity().getContent()); + closeResponse(response); + JsonNode dataNode = rootNode.get("data"); + assertThatJson(dataNode) + .when(Option.IGNORING_EXTRA_FIELDS) + .isEqualTo("[" + + " {" + + " businessKey: 'businessKey1'" + + " }," + + " {" + + " businessKey: 'businessKey2'" + + " }," + + " {" + + " businessKey: 'businessKey3'" + + " }" + + "]"); + + requestNode.put("order", "desc"); + + url = CmmnRestUrls.createRelativeResourceUrl(CmmnRestUrls.URL_CASE_INSTANCE_QUERY); + httpPost = new HttpPost(SERVER_URL_PREFIX + url); + httpPost.setEntity(new StringEntity(requestNode.toString())); + response = executeRequest(httpPost, HttpStatus.SC_OK); + + // Check order + rootNode = objectMapper.readTree(response.getEntity().getContent()); + closeResponse(response); + dataNode = rootNode.get("data"); + assertThatJson(dataNode) + .when(Option.IGNORING_EXTRA_FIELDS) + .isEqualTo("[" + + " {" + + " businessKey: 'businessKey3'" + + " }," + + " {" + + " businessKey: 'businessKey2'" + + " }," + + " {" + + " businessKey: 'businessKey1'" + + " }" + + "]"); + + } } diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/ProcessInstanceQueryProperty.java b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/ProcessInstanceQueryProperty.java index afd30f627ab..ffbb9b879a4 100644 --- a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/ProcessInstanceQueryProperty.java +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/ProcessInstanceQueryProperty.java @@ -35,6 +35,7 @@ public class ProcessInstanceQueryProperty implements QueryProperty { public static final ProcessInstanceQueryProperty PROCESS_DEFINITION_ID = new ProcessInstanceQueryProperty("RES.PROC_DEF_ID_"); public static final ProcessInstanceQueryProperty PROCESS_START_TIME = new ProcessInstanceQueryProperty("RES.START_TIME_"); public static final ProcessInstanceQueryProperty TENANT_ID = new ProcessInstanceQueryProperty("RES.TENANT_ID_"); + public static final ProcessInstanceQueryProperty BUSINESS_KEY = new ProcessInstanceQueryProperty("RES.BUSINESS_KEY_"); private String name; diff --git a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/BaseProcessInstanceResource.java b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/BaseProcessInstanceResource.java index 1ac037b7c3f..d5f84ad5787 100644 --- a/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/BaseProcessInstanceResource.java +++ b/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/BaseProcessInstanceResource.java @@ -50,6 +50,7 @@ public class BaseProcessInstanceResource { allowedSortProperties.put("id", ProcessInstanceQueryProperty.PROCESS_INSTANCE_ID); allowedSortProperties.put("startTime", ProcessInstanceQueryProperty.PROCESS_START_TIME); allowedSortProperties.put("tenantId", ProcessInstanceQueryProperty.TENANT_ID); + allowedSortProperties.put("businessKey", ProcessInstanceQueryProperty.BUSINESS_KEY); } @Autowired diff --git a/modules/flowable-rest/src/test/java/org/flowable/rest/service/api/runtime/ProcessInstanceCollectionResourceTest.java b/modules/flowable-rest/src/test/java/org/flowable/rest/service/api/runtime/ProcessInstanceCollectionResourceTest.java index 112022f9f2c..dd8fbe454dd 100644 --- a/modules/flowable-rest/src/test/java/org/flowable/rest/service/api/runtime/ProcessInstanceCollectionResourceTest.java +++ b/modules/flowable-rest/src/test/java/org/flowable/rest/service/api/runtime/ProcessInstanceCollectionResourceTest.java @@ -293,6 +293,41 @@ public void testGetProcessInstancesSorted() throws Exception { assertResultsExactlyPresentInDataResponse(url, nowPlus1InstanceId, nowInstanceId, nowMinus1InstanceId); } + /** + * Test getting a list of sorted process instance + */ + @Test + @Deployment(resources = { "org/flowable/rest/service/api/runtime/ProcessInstanceResourceTest.process-one.bpmn20.xml" }) + public void testGetProcessInstancesSortedByBusinessKey() throws Exception { + Instant initialTime = Instant.now(); + processEngineConfiguration.getClock().setCurrentTime(Date.from(initialTime)); + String businessKey3 = runtimeService.startProcessInstanceByKey("processOne", "businessKey3").getId(); + + processEngineConfiguration.getClock().setCurrentTime(Date.from(initialTime.plus(1, ChronoUnit.HOURS))); + String businessKey1 = runtimeService.startProcessInstanceByKey("processOne", "businessKey1").getId(); + + processEngineConfiguration.getClock().setCurrentTime(Date.from(initialTime.minus(1, ChronoUnit.HOURS))); + String businessKey2 = runtimeService.startProcessInstanceByKey("processOne", "businessKey2").getId(); + + List sortedIds = new ArrayList<>(); + sortedIds.add(businessKey3); + sortedIds.add(businessKey1); + sortedIds.add(businessKey2); + Collections.sort(sortedIds); + + // Test without any parameters + String url = RestUrls.createRelativeResourceUrl(RestUrls.URL_PROCESS_INSTANCE_COLLECTION); + assertResultsExactlyPresentInDataResponse(url, sortedIds.toArray(new String[0])); + + // Sort by businessKey + url = RestUrls.createRelativeResourceUrl(RestUrls.URL_PROCESS_INSTANCE_COLLECTION) + "?sort=businessKey"; + assertResultsExactlyPresentInDataResponse(url, businessKey1, businessKey2, businessKey3); + + // Sort by businessKey desc + url = RestUrls.createRelativeResourceUrl(RestUrls.URL_PROCESS_INSTANCE_COLLECTION) + "?sort=businessKey&order=desc"; + assertResultsExactlyPresentInDataResponse(url, businessKey3, businessKey2, businessKey1); + } + /** * Test getting a list of process instance, using all tenant filters. */ diff --git a/modules/flowable-rest/src/test/java/org/flowable/rest/service/api/runtime/ProcessInstanceQueryResourceTest.java b/modules/flowable-rest/src/test/java/org/flowable/rest/service/api/runtime/ProcessInstanceQueryResourceTest.java index 361493f1a1a..405afcb9826 100644 --- a/modules/flowable-rest/src/test/java/org/flowable/rest/service/api/runtime/ProcessInstanceQueryResourceTest.java +++ b/modules/flowable-rest/src/test/java/org/flowable/rest/service/api/runtime/ProcessInstanceQueryResourceTest.java @@ -343,4 +343,64 @@ public void testQueryProcessInstancesByActiveActivityIds() throws Exception { + "} ]" + "}"); } + + @Test + @Deployment(resources = { "org/flowable/rest/service/api/twoTaskProcess.bpmn20.xml" }) + public void testQueryProcessInstancesByBusinessKey() throws Exception { + runtimeService.startProcessInstanceByKey("oneTaskProcess", "businessKey3"); + runtimeService.startProcessInstanceByKey("oneTaskProcess", "businessKey1"); + runtimeService.startProcessInstanceByKey("oneTaskProcess", "businessKey2"); + + ObjectNode requestNode = objectMapper.createObjectNode(); + requestNode.put("order", "asc"); + requestNode.put("sort", "businessKey"); + + String url = RestUrls.createRelativeResourceUrl(RestUrls.URL_PROCESS_INSTANCE_QUERY); + HttpPost httpPost = new HttpPost(SERVER_URL_PREFIX + url); + httpPost.setEntity(new StringEntity(requestNode.toString())); + CloseableHttpResponse response = executeRequest(httpPost, HttpStatus.SC_OK); + + JsonNode rootNode = objectMapper.readTree(response.getEntity().getContent()); + closeResponse(response); + assertThatJson(rootNode) + .when(Option.IGNORING_EXTRA_FIELDS) + .isEqualTo("{" + + "data: [ " + + " {" + + " businessKey: 'businessKey1'" + + " }, " + + " {" + + " businessKey: 'businessKey2'" + + " }, " + + " {" + + " businessKey: 'businessKey3'" + + " } " + + "]" + + "}"); + + requestNode.put("order", "desc"); + + url = RestUrls.createRelativeResourceUrl(RestUrls.URL_PROCESS_INSTANCE_QUERY); + httpPost = new HttpPost(SERVER_URL_PREFIX + url); + httpPost.setEntity(new StringEntity(requestNode.toString())); + response = executeRequest(httpPost, HttpStatus.SC_OK); + + rootNode = objectMapper.readTree(response.getEntity().getContent()); + closeResponse(response); + assertThatJson(rootNode) + .when(Option.IGNORING_EXTRA_FIELDS) + .isEqualTo("{" + + "data: [ " + + " {" + + " businessKey: 'businessKey3'" + + " }, " + + " {" + + " businessKey: 'businessKey2'" + + " }, " + + " {" + + " businessKey: 'businessKey1'" + + " } " + + "]" + + "}"); + } }