TSK-2001: add filtering by priorityWithin and notWithin

This commit is contained in:
Elena Mokeeva 2023-02-15 15:13:40 +01:00 committed by Elena Mokeeva
parent ca6aeb084c
commit 73fed96627
6 changed files with 330 additions and 11 deletions

View File

@ -944,6 +944,8 @@ class TaskQueryImplAccTest {
WorkbasketSummary wb; WorkbasketSummary wb;
TaskSummary taskSummary1; TaskSummary taskSummary1;
TaskSummary taskSummary2; TaskSummary taskSummary2;
TaskSummary taskSummary3;
@WithAccessId(user = "user-1-1") @WithAccessId(user = "user-1-1")
@BeforeAll @BeforeAll
@ -951,6 +953,8 @@ class TaskQueryImplAccTest {
wb = createWorkbasketWithPermission(); wb = createWorkbasketWithPermission();
taskSummary1 = taskInWorkbasket(wb).priority(1).buildAndStoreAsSummary(taskService); taskSummary1 = taskInWorkbasket(wb).priority(1).buildAndStoreAsSummary(taskService);
taskSummary2 = taskInWorkbasket(wb).priority(2).buildAndStoreAsSummary(taskService); taskSummary2 = taskInWorkbasket(wb).priority(2).buildAndStoreAsSummary(taskService);
taskSummary3 = taskInWorkbasket(wb).priority(4).buildAndStoreAsSummary(taskService);
} }
@WithAccessId(user = "user-1-1") @WithAccessId(user = "user-1-1")
@ -968,7 +972,33 @@ class TaskQueryImplAccTest {
List<TaskSummary> list = List<TaskSummary> list =
taskService.createTaskQuery().workbasketIdIn(wb.getId()).priorityNotIn(1).list(); taskService.createTaskQuery().workbasketIdIn(wb.getId()).priorityNotIn(1).list();
assertThat(list).containsExactly(taskSummary2); assertThat(list).containsExactlyInAnyOrder(taskSummary2, taskSummary3);
}
@WithAccessId(user = "user-1-1")
@Test
void should_ApplyFilter_When_QueryingForPriorityWithin() {
List<TaskSummary> list =
taskService
.createTaskQuery()
.workbasketIdIn(wb.getId())
.priorityWithin(new IntInterval(2, 4))
.list();
assertThat(list).containsExactlyInAnyOrder(taskSummary2, taskSummary3);
}
@WithAccessId(user = "user-1-1")
@Test
void should_ApplyFilter_When_QueryingForPriorityNotWithin() {
List<TaskSummary> list =
taskService
.createTaskQuery()
.workbasketIdIn(wb.getId())
.priorityNotWithin(new IntInterval(2, 4))
.list();
assertThat(list).containsExactly(taskSummary1);
} }
} }

View File

@ -481,6 +481,24 @@ public interface TaskQuery extends BaseQuery<TaskSummary, TaskQueryColumnName> {
*/ */
TaskQuery priorityNotIn(int... priorities); TaskQuery priorityNotIn(int... priorities);
/**
* Includes the priorities in the provided range (inclusive) to your query (eg. priorities = [1,3]
* includes 1,2,3).
*
* @param priorities as an integer intervals
* @return the query
*/
TaskQuery priorityWithin(IntInterval... priorities);
/**
* Excludes the priorities in the provided range (inclusive) to your query (eg. priorities = [1,3]
* excludes 1,2,3).
*
* @param priorities as an integer intervals
* @return the query
*/
TaskQuery priorityNotWithin(IntInterval... priorities);
/** /**
* This method sorts the query result according to the priority. * This method sorts the query result according to the priority.
* *

View File

@ -102,6 +102,8 @@ public class TaskQueryImpl implements TaskQuery {
private String[] descriptionNotLike; private String[] descriptionNotLike;
private int[] priority; private int[] priority;
private int[] priorityNotIn; private int[] priorityNotIn;
private IntInterval[] priorityWithin;
private IntInterval[] priorityNotWithin;
private TaskState[] stateIn; private TaskState[] stateIn;
private TaskState[] stateNotIn; private TaskState[] stateNotIn;
private String[] classificationIdIn; private String[] classificationIdIn;
@ -602,6 +604,18 @@ public class TaskQueryImpl implements TaskQuery {
return this; return this;
} }
@Override
public TaskQuery priorityWithin(IntInterval[] priorities) {
this.priorityWithin = priorities;
return this;
}
@Override
public TaskQuery priorityNotWithin(IntInterval[] priorities) {
this.priorityNotWithin = priorities;
return this;
}
@Override @Override
public TaskQuery orderByPriority(SortDirection sortDirection) { public TaskQuery orderByPriority(SortDirection sortDirection) {
return addOrderCriteria("PRIORITY", sortDirection); return addOrderCriteria("PRIORITY", sortDirection);
@ -2328,6 +2342,10 @@ public class TaskQueryImpl implements TaskQuery {
+ Arrays.toString(priority) + Arrays.toString(priority)
+ ", priorityNotIn=" + ", priorityNotIn="
+ Arrays.toString(priorityNotIn) + Arrays.toString(priorityNotIn)
+ ", priorityWithin="
+ Arrays.toString(priorityWithin)
+ ", priorityNotWithin="
+ Arrays.toString(priorityNotWithin)
+ ", stateIn=" + ", stateIn="
+ Arrays.toString(stateIn) + Arrays.toString(stateIn)
+ ", stateNotIn=" + ", stateNotIn="

View File

@ -506,6 +506,8 @@ public class TaskQuerySqlProvider {
whereNotInInterval("plannedNotWithin", "t.PLANNED", sb); whereNotInInterval("plannedNotWithin", "t.PLANNED", sb);
whereInInterval("receivedWithin", "t.RECEIVED", sb); whereInInterval("receivedWithin", "t.RECEIVED", sb);
whereNotInInterval("receivedNotWithin", "t.RECEIVED", sb); whereNotInInterval("receivedNotWithin", "t.RECEIVED", sb);
whereInInterval("priorityWithin", "t.PRIORITY", sb);
whereNotInInterval("priorityNotWithin", "t.PRIORITY", sb);
whereLike("ownerLongNameLike", "u.LONG_NAME", sb); whereLike("ownerLongNameLike", "u.LONG_NAME", sb);
whereNotLike("ownerLongNameNotLike", "u.LONG_NAME", sb); whereNotLike("ownerLongNameNotLike", "u.LONG_NAME", sb);

View File

@ -6,6 +6,7 @@ import java.time.Instant;
import java.util.Arrays; import java.util.Arrays;
import java.util.Optional; import java.util.Optional;
import pro.taskana.common.api.IntInterval;
import pro.taskana.common.api.KeyDomain; import pro.taskana.common.api.KeyDomain;
import pro.taskana.common.api.TimeInterval; import pro.taskana.common.api.TimeInterval;
import pro.taskana.common.api.exceptions.InvalidArgumentException; import pro.taskana.common.api.exceptions.InvalidArgumentException;
@ -483,6 +484,30 @@ public class TaskQueryFilterParameter implements QueryParameter<TaskQuery, Void>
/** Filter by what the priority of the Task shouldn't be. This is an exact match. */ /** Filter by what the priority of the Task shouldn't be. This is an exact match. */
@JsonProperty("priority-not") @JsonProperty("priority-not")
private final int[] priorityNotIn; private final int[] priorityNotIn;
/** Filter by the range of values of the priority field of the Task. */
@JsonProperty("priority-within")
private final Integer[] priorityWithin;
/** Filter by priority starting from the given value (inclusive). */
@JsonProperty("priority-from")
private final Integer priorityFrom;
/** Filter by priority up to the given value (inclusive). */
@JsonProperty("priority-until")
private final Integer priorityUntil;
/** Filter by exclusing the range of values of the priority field of the Task. */
@JsonProperty("priority-not-within")
private final Integer[] priorityNotWithin;
/** Filter by excluding priority starting from the given value (inclusive). */
@JsonProperty("priority-not-from")
private final Integer priorityNotFrom;
/** Filter by excluding priority up to the given value (inclusive). */
@JsonProperty("priority-not-until")
private final Integer priorityNotUntil;
// endregion // endregion
// region state // region state
/** Filter by the Task state. This is an exact match. */ /** Filter by the Task state. This is an exact match. */
@ -1192,6 +1217,12 @@ public class TaskQueryFilterParameter implements QueryParameter<TaskQuery, Void>
"description-not-like", "description-not-like",
"priority", "priority",
"priority-not", "priority-not",
"priority-within",
"priority-from",
"priority-until",
"priority-not-within",
"priority-not-from",
"priority-not-until",
"state", "state",
"state-not", "state-not",
"classification-id", "classification-id",
@ -1342,6 +1373,12 @@ public class TaskQueryFilterParameter implements QueryParameter<TaskQuery, Void>
String[] descriptionNotLike, String[] descriptionNotLike,
int[] priorityIn, int[] priorityIn,
int[] priorityNotIn, int[] priorityNotIn,
Integer[] priorityWithin,
Integer priorityFrom,
Integer priorityUntil,
Integer[] priorityNotWithin,
Integer priorityNotFrom,
Integer priorityNotUntil,
TaskState[] stateIn, TaskState[] stateIn,
TaskState[] stateNotIn, TaskState[] stateNotIn,
String[] classificationIdIn, String[] classificationIdIn,
@ -1491,6 +1528,12 @@ public class TaskQueryFilterParameter implements QueryParameter<TaskQuery, Void>
this.descriptionNotLike = descriptionNotLike; this.descriptionNotLike = descriptionNotLike;
this.priorityIn = priorityIn; this.priorityIn = priorityIn;
this.priorityNotIn = priorityNotIn; this.priorityNotIn = priorityNotIn;
this.priorityWithin = priorityWithin;
this.priorityFrom = priorityFrom;
this.priorityUntil = priorityUntil;
this.priorityNotWithin = priorityNotWithin;
this.priorityNotFrom = priorityNotFrom;
this.priorityNotUntil = priorityNotUntil;
this.stateIn = stateIn; this.stateIn = stateIn;
this.stateNotIn = stateNotIn; this.stateNotIn = stateNotIn;
this.classificationIdIn = classificationIdIn; this.classificationIdIn = classificationIdIn;
@ -1709,6 +1752,20 @@ public class TaskQueryFilterParameter implements QueryParameter<TaskQuery, Void>
Optional.ofNullable(priorityIn).ifPresent(query::priorityIn); Optional.ofNullable(priorityIn).ifPresent(query::priorityIn);
Optional.ofNullable(priorityNotIn).ifPresent(query::priorityNotIn); Optional.ofNullable(priorityNotIn).ifPresent(query::priorityNotIn);
Optional.ofNullable(priorityWithin)
.map(this::extractIntIntervals)
.ifPresent(query::priorityWithin);
if (priorityFrom != null || priorityUntil != null) {
query.priorityWithin(new IntInterval(priorityFrom, priorityUntil));
}
Optional.ofNullable(priorityNotWithin)
.map(this::extractIntIntervals)
.ifPresent(query::priorityNotWithin);
if (priorityNotFrom != null || priorityNotUntil != null) {
query.priorityNotWithin(new IntInterval(priorityNotFrom, priorityNotUntil));
}
Optional.ofNullable(stateIn).ifPresent(query::stateIn); Optional.ofNullable(stateIn).ifPresent(query::stateIn);
Optional.ofNullable(stateNotIn).ifPresent(query::stateNotIn); Optional.ofNullable(stateNotIn).ifPresent(query::stateNotIn);
@ -2001,6 +2058,28 @@ public class TaskQueryFilterParameter implements QueryParameter<TaskQuery, Void>
+ "'completed-not-in-from' and / or 'completed-not-in-until'"); + "'completed-not-in-from' and / or 'completed-not-in-until'");
} }
if (priorityWithin != null && (priorityFrom != null || priorityUntil != null)) {
throw new InvalidArgumentException(
"It is prohibited to use the param 'priority-within' in combination with the params "
+ "'priority-from' and / or 'priority-until'");
}
if (priorityNotWithin != null && (priorityNotFrom != null || priorityNotUntil != null)) {
throw new InvalidArgumentException(
"It is prohibited to use the param 'priority-not-within' in combination with the params "
+ "'priority-not-from' and / or 'priority-not-until'");
}
if (priorityWithin != null && priorityWithin.length % 2 != 0) {
throw new InvalidArgumentException(
"provided length of the property 'priority-within' is not dividable by 2");
}
if (priorityNotWithin != null && priorityNotWithin.length % 2 != 0) {
throw new InvalidArgumentException(
"provided length of the property 'priority-not-within' is not dividable by 2");
}
if (wildcardSearchFieldIn == null ^ wildcardSearchValue == null) { if (wildcardSearchFieldIn == null ^ wildcardSearchValue == null) {
throw new InvalidArgumentException( throw new InvalidArgumentException(
"The params 'wildcard-search-field' and 'wildcard-search-value' must be used together"); "The params 'wildcard-search-field' and 'wildcard-search-value' must be used together");

View File

@ -586,6 +586,182 @@ class TaskControllerIntTest {
assertThat(response.getBody().getContent()).hasSize(22); assertThat(response.getBody().getContent()).hasSize(22);
} }
@Test
void should_GetAllTasks_For_SpecifiedWorkbasketIdAndPriorityFromAndUntil() {
Integer priorityFrom = 2;
Integer priorityTo = 3;
String url =
restHelper.toUrl(RestEndpoints.URL_TASKS)
+ String.format(
"?workbasket-id=WBI:100000000000000000000000000000000006"
+ "&priority-from=%s&priority-until=%s",
priorityFrom, priorityTo);
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1"));
ResponseEntity<TaskSummaryPagedRepresentationModel> response =
TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE);
assertThat(response.getBody()).isNotNull();
assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull();
assertThat(response.getBody().getContent()).hasSize(2);
}
@Test
void should_GetAllTasks_For_SpecifiedWorkbasketIdAndMultiplePriorityWithinIntervals() {
Integer priorityFrom1 = 2;
Integer priorityFrom2 = 0;
String url =
restHelper.toUrl(RestEndpoints.URL_TASKS)
+ String.format(
"?workbasket-id=WBI:100000000000000000000000000000000006"
+ "&priority-within=%s&priority-within=&priority-within=%s&priority-within=",
priorityFrom1, priorityFrom2);
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1"));
ResponseEntity<TaskSummaryPagedRepresentationModel> response =
TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE);
assertThat(response.getBody()).isNotNull();
assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull();
assertThat(response.getBody().getContent()).hasSize(3);
}
@Test
void should_GetAllTasks_For_SpecifiedWorkbasketIdAndPriorityNotFromAndNotUntil() {
Integer priorityFrom = 2;
Integer priorityTo = 3;
String url =
restHelper.toUrl(RestEndpoints.URL_TASKS)
+ String.format(
"?workbasket-id=WBI:100000000000000000000000000000000006"
+ "&priority-not-from=%s&priority-not-until=%s",
priorityFrom, priorityTo);
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1"));
ResponseEntity<TaskSummaryPagedRepresentationModel> response =
TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE);
assertThat(response.getBody()).isNotNull();
assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull();
assertThat(response.getBody().getContent()).hasSize(1);
}
@Test
void should_GetAllTasks_For_SpecifiedWorkbasketIdAndMultiplePriorityNotWithinIntervals() {
Integer priorityFrom1 = 2;
Integer priorityFrom2 = 1;
String url =
restHelper.toUrl(RestEndpoints.URL_TASKS)
+ String.format(
"?workbasket-id=WBI:100000000000000000000000000000000006"
+ "&priority-not-within=%s&priority-not-within="
+ "&priority-not-within=%s&priority-not-within=",
priorityFrom1, priorityFrom2);
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1"));
ResponseEntity<TaskSummaryPagedRepresentationModel> response =
TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE);
assertThat(response.getBody()).isNotNull();
assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull();
assertThat(response.getBody().getContent()).hasSize(1);
}
@Test
void should_ThrowException_When_GettingTasksByWorkbasketIdWithPriorityNotWithinAndNotFrom() {
Integer priorityFrom1 = 2;
Integer priorityFrom2 = 1;
String url =
restHelper.toUrl(RestEndpoints.URL_TASKS)
+ String.format(
"?workbasket-id=WBI:100000000000000000000000000000000006"
+ "&priority-not-within=%s&priority-not-within="
+ "&priority-not-from=%s&priority-not-until=",
priorityFrom1, priorityFrom2);
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1"));
ThrowingCallable httpCall =
() -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE);
assertThatThrownBy(httpCall)
.isInstanceOf(HttpStatusCodeException.class)
.extracting(HttpStatusCodeException.class::cast)
.extracting(HttpStatusCodeException::getStatusCode)
.isEqualTo(HttpStatus.BAD_REQUEST);
}
@Test
void should_ThrowException_When_GettingTasksByWorkbasketIdWithPriorityWithinAndPriorityFrom() {
Integer priorityFrom1 = 2;
Integer priorityFrom2 = 1;
String url =
restHelper.toUrl(RestEndpoints.URL_TASKS)
+ String.format(
"?workbasket-id=WBI:100000000000000000000000000000000006"
+ "&priority-within=%s&priority-within=&priority-from=%s&priority-until=",
priorityFrom1, priorityFrom2);
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1"));
ThrowingCallable httpCall =
() -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE);
assertThatThrownBy(httpCall)
.isInstanceOf(HttpStatusCodeException.class)
.extracting(HttpStatusCodeException.class::cast)
.extracting(HttpStatusCodeException::getStatusCode)
.isEqualTo(HttpStatus.BAD_REQUEST);
}
@Test
void
should_ThrowException_When_GettingTasksByWorkbasketIdWithEvenNumberOfPriorityWithin() {
Integer priorityFrom1 = 2;
Integer priorityFrom2 = 1;
String url =
restHelper.toUrl(RestEndpoints.URL_TASKS)
+ String.format(
"?workbasket-id=WBI:100000000000000000000000000000000006"
+ "&priority-within=%s&priority-within=&priority-within=%s",
priorityFrom1, priorityFrom2);
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1"));
ThrowingCallable httpCall =
() -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE);
assertThatThrownBy(httpCall)
.isInstanceOf(HttpStatusCodeException.class)
.extracting(HttpStatusCodeException.class::cast)
.extracting(HttpStatusCodeException::getStatusCode)
.isEqualTo(HttpStatus.BAD_REQUEST);
}
@Test
void
should_ThrowException_When_GettingTasksByWorkbasketIdWithEvenNumberOfPriorityNotWithin() {
Integer priorityFrom1 = 2;
Integer priorityFrom2 = 1;
String url =
restHelper.toUrl(RestEndpoints.URL_TASKS)
+ String.format(
"?workbasket-id=WBI:100000000000000000000000000000000006"
+ "&priority-not-within=%s&priority-not-within=&priority-not-within=%s",
priorityFrom1, priorityFrom2);
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1"));
ThrowingCallable httpCall =
() -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE);
assertThatThrownBy(httpCall)
.isInstanceOf(HttpStatusCodeException.class)
.extracting(HttpStatusCodeException.class::cast)
.extracting(HttpStatusCodeException::getStatusCode)
.isEqualTo(HttpStatus.BAD_REQUEST);
}
@Test @Test
void should_ReturnAllTasks_For_SpecifiedWorkbasketIdAndClassificationParentKeyIn() { void should_ReturnAllTasks_For_SpecifiedWorkbasketIdAndClassificationParentKeyIn() {
String parentKey = "L11010"; String parentKey = "L11010";
@ -627,9 +803,7 @@ class TaskControllerIntTest {
String parentKey = "L%"; String parentKey = "L%";
String url = String url =
restHelper.toUrl(RestEndpoints.URL_TASKS) restHelper.toUrl(RestEndpoints.URL_TASKS)
+ String.format( + String.format("?classification-parent-key-like=%s", parentKey);
"?classification-parent-key-like=%s",
parentKey);
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin"));
ResponseEntity<TaskSummaryPagedRepresentationModel> response = ResponseEntity<TaskSummaryPagedRepresentationModel> response =
TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE);
@ -644,9 +818,7 @@ class TaskControllerIntTest {
String parentKey = "L%"; String parentKey = "L%";
String url = String url =
restHelper.toUrl(RestEndpoints.URL_TASKS) restHelper.toUrl(RestEndpoints.URL_TASKS)
+ String.format( + String.format("?classification-parent-key-not-like=%s", parentKey);
"?classification-parent-key-not-like=%s",
parentKey);
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin"));
ResponseEntity<TaskSummaryPagedRepresentationModel> response = ResponseEntity<TaskSummaryPagedRepresentationModel> response =
TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE);