Skip to content

Commit

Permalink
add filter for querying task types by status (#196)
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrieltaets-tw authored Apr 4, 2024
1 parent 444ccca commit 8121ef7
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 23 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

#### 1.41.4 - 2024/04/02
### Changed
- `/getTaskTypes` endpoint accepts optional query parameter `status` to filter only types of tasks in the particular status(es).
- Fixed a bug with `taskType` and `taskSubType` filters on query endpoints when multiple values are supplied, where it would consider only one value.

#### 1.41.3 - 2024/02/29
### Changed
* Add compatibility with Spring Boot 3.2.
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version=1.41.3
version=1.41.4
org.gradle.internal.http.socketTimeout=120000
Original file line number Diff line number Diff line change
Expand Up @@ -359,30 +359,36 @@ void immediatelyResumingAllTasksWorks() {

@Test
void filtersErroredTasksByTypeAndSubType() {
final UUID taskId = transactionsHelper.withTransaction().asNew().call(() -> {
final List<UUID> taskIds = transactionsHelper.withTransaction().asNew().call(() -> {
TaskTestBuilder.newTask().inStatus(TaskStatus.ERROR).withMaxStuckTime(ZonedDateTime.now().plusDays(2)).save();
TaskTestBuilder.newTask().inStatus(TaskStatus.ERROR).withMaxStuckTime(ZonedDateTime.now().plusDays(2))
.withType("B")
.withSubType("SUB")
.withType("A")
.withSubType("BAD")
.save();
TaskTestBuilder.newTask().inStatus(TaskStatus.ERROR).withMaxStuckTime(ZonedDateTime.now().plusDays(2))
.withType("A")
.withType("C")
.withSubType("BAD")
.save();
TaskTestBuilder.newTask().inStatus(TaskStatus.ERROR).withMaxStuckTime(ZonedDateTime.now().plusDays(2))
.withSubType("SUB")
.save();
return TaskTestBuilder.newTask().inStatus(TaskStatus.ERROR).withMaxStuckTime(ZonedDateTime.now().plusDays(2))
var task1 = TaskTestBuilder.newTask().inStatus(TaskStatus.ERROR).withMaxStuckTime(ZonedDateTime.now().plusDays(2))
.withType("B")
.withSubType("SUB")
.save()
.getTaskId();
var task2 = TaskTestBuilder.newTask().inStatus(TaskStatus.ERROR).withMaxStuckTime(ZonedDateTime.now().plusDays(1))
.withType("A")
.withSubType("SUB")
.save()
.getTaskId();
return List.of(task1, task2);
});

ResponseEntity<GetTasksInErrorResponse> response = goodEngineerTemplate().postForEntity(
"/v1/twTasks/getTasksInError",
new ITasksManagementPort.GetTasksInErrorRequest().setMaxCount(10)
.setTaskTypes(List.of("A"))
.setTaskTypes(List.of("A", "B"))
.setTaskSubTypes(List.of("SUB")),
GetTasksInErrorResponse.class
);
Expand All @@ -391,10 +397,14 @@ void filtersErroredTasksByTypeAndSubType() {
GetTasksInErrorResponse tasksInErrorResponse = response.getBody();
assertNotNull(tasksInErrorResponse);
List<TaskInError> tasksInError = tasksInErrorResponse.getTasksInError();
assertEquals(1, tasksInError.size());
assertEquals(taskId, tasksInError.get(0).getTaskVersionId().getId());
assertEquals("A", tasksInError.get(0).getType());
assertEquals(2, tasksInError.size());
assertEquals(taskIds.get(0), tasksInError.get(0).getTaskVersionId().getId());
assertEquals("B", tasksInError.get(0).getType());
assertEquals("SUB", tasksInError.get(0).getSubType());
assertEquals(taskIds.get(1), tasksInError.get(1).getTaskVersionId().getId());
assertEquals("A", tasksInError.get(1).getType());
assertEquals("SUB", tasksInError.get(1).getSubType());

}

@Test
Expand Down Expand Up @@ -518,6 +528,44 @@ void getTaskTypesWillReturnCorrectly() {
assertTrue(types.get(1).getSubTypes().isEmpty());
}

@Test
void getTaskTypesWillReturnFiltered() {
transactionsHelper.withTransaction().asNew().run(() -> {
TaskTestBuilder.newTask().inStatus(TaskStatus.WAITING).withMaxStuckTime(ZonedDateTime.now().plusDays(2))
.withType("C")
.withSubType("SUB-2")
.save();
TaskTestBuilder.newTask().inStatus(TaskStatus.WAITING).withMaxStuckTime(ZonedDateTime.now().plusDays(2))
.withType("C")
.withSubType("SUB-1")
.save();
TaskTestBuilder.newTask().inStatus(TaskStatus.ERROR).withMaxStuckTime(ZonedDateTime.now().plusDays(2))
.withType("B")
.save();
TaskTestBuilder.newTask().inStatus(TaskStatus.PROCESSING).withMaxStuckTime(ZonedDateTime.now().plusDays(2))
.withType("A")
.save();
TaskTestBuilder.newTask().inStatus(TaskStatus.WAITING).withMaxStuckTime(ZonedDateTime.now().plusDays(2))
.withType("C")
.save();
});

ResponseEntity<GetTaskTypesResponse> response = goodEngineerTemplate().getForEntity(
"/v1/twTasks/getTaskTypes?status=ERROR,PROCESSING",
GetTaskTypesResponse.class
);

assertEquals(200, response.getStatusCodeValue());
GetTaskTypesResponse typesResponse = response.getBody();
assertNotNull(typesResponse);
List<GetTaskTypesResponse.TaskType> types = typesResponse.getTypes();
assertEquals(2, types.size());
assertEquals("A", types.get(0).getType());
assertEquals("B", types.get(1).getType());
assertTrue(types.get(0).getSubTypes().isEmpty());
assertTrue(types.get(1).getSubTypes().isEmpty());
}

private TestRestTemplate goodEngineerTemplate() {
return testRestTemplate.withBasicAuth("goodEngineer", "q1w2e3r4");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ ResponseEntity<GetTasksInProcessingOrWaitingResponse> getTasksInProcessingOrWait

@GetMapping(value = "${tw-tasks.core.base-url:}/v1/twTasks/getTaskTypes", produces = {MediaType.APPLICATION_JSON_VALUE})
@ResponseBody
ResponseEntity<GetTaskTypesResponse> getTaskTypes();
ResponseEntity<GetTaskTypesResponse> getTaskTypes(@RequestParam(name = "status", required = false) List<String> status);


@Data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ public static class Task {
}
}

GetTaskTypesResponse getTaskTypes();
GetTaskTypesResponse getTaskTypes(List<String> status);

@Data
@Accessors(chain = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.transferwise.tasks.management.ITasksManagementPort.GetTaskDataResponse.ResultCode;
import com.transferwise.tasks.management.ITasksManagementService.GetTaskDataRequest;
import com.transferwise.tasks.management.ITasksManagementService.GetTaskDataRequest.ContentFormat;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
Expand All @@ -26,6 +27,7 @@
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@Slf4j
Expand Down Expand Up @@ -199,9 +201,9 @@ public ResponseEntity<GetTasksStuckResponse> getTasksStuck(@RequestBody(required
}

@Override
public ResponseEntity<GetTaskTypesResponse> getTaskTypes() {
public ResponseEntity<GetTaskTypesResponse> getTaskTypes(@RequestParam(name = "status", required = false) List<String> status) {
return callWithAuthentication(() -> {
ITasksManagementService.GetTaskTypesResponse serviceResponse = tasksManagementService.getTaskTypes();
ITasksManagementService.GetTaskTypesResponse serviceResponse = tasksManagementService.getTaskTypes(status);

return ResponseEntity.ok(new GetTaskTypesResponse().setTypes(serviceResponse.getTypes().stream().map(type ->
new GetTaskTypesResponse.TaskType().setType(type.getType()).setSubTypes(type.getSubTypes())).collect(Collectors.toList())));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,10 +259,10 @@ public GetTaskDataResponse getTaskData(GetTaskDataRequest request) {
}

@Override
public GetTaskTypesResponse getTaskTypes() {
public GetTaskTypesResponse getTaskTypes(List<String> status) {
return entryPointsHelper
.continueOrCreate(ManagementEntryPointGroups.TW_TASKS_MANAGEMENT, ManagementEntryPointNames.GET_TASKS_TYPES, () -> {
List<DaoTaskType> types = managementTaskDao.getTaskTypes();
List<DaoTaskType> types = managementTaskDao.getTaskTypes(status);
return new GetTaskTypesResponse().setTypes(
types.stream().map(t -> new GetTaskTypesResponse.TaskType().setType(t.getType()).setSubTypes(t.getSubTypes()))
.collect(Collectors.toList()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,5 @@ class DaoTaskType {

List<FullTaskRecord> getTasks(List<UUID> uuids);

List<DaoTaskType> getTaskTypes();
List<DaoTaskType> getTaskTypes(List<String> status);
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ QueryBuilder and(String paramName, Op op) {
this.where += " AND " + paramName;
switch (op) {
case IN:
where += " IN (?)";
where += " IN (??)";
break;
case LESS_THAN:
where += " <?";
Expand All @@ -97,6 +97,11 @@ QueryBuilder and(String paramName, Op op) {
return this;
}

QueryBuilder expand(int count) {
this.where = SqlHelper.expandParametersList(this.where, count);
return this;
}

QueryBuilder desc(String orderBy) {
this.orderBy = " order by " + orderBy + " desc";
return this;
Expand Down Expand Up @@ -309,10 +314,15 @@ public List<FullTaskRecord> getTasks(List<UUID> taskIds) {
}

@Override
public List<DaoTaskType> getTaskTypes() {
public List<DaoTaskType> getTaskTypes(List<String> status) {
var builder = Queries.queryBuilder(queries.getTaskTypes);
if (status != null && !status.isEmpty()) {
builder.and("status", Op.IN).expand(status.size());
}
List<Pair<String, String>> types = jdbcTemplate.query(
queries.getTaskTypes,
(rs, rowNum) -> ImmutablePair.of(rs.getString(1), rs.getString(2)));
builder.build(),
args(status),
(rs, rowNum) -> ImmutablePair.of(rs.getString(1), rs.getString(2)));

return types.stream()
.collect(groupingBy(Pair::getKey, mapping(Pair::getValue, filtering(Objects::nonNull, toList()))))
Expand All @@ -325,10 +335,10 @@ public List<DaoTaskType> getTaskTypes() {

protected void addTaskTypeArgs(QueryBuilder builder, List<String> taskTypes, List<String> taskSubTypes) {
if (taskTypes != null && !taskTypes.isEmpty()) {
builder.and("type", Op.IN);
builder.and("type", Op.IN).expand(taskTypes.size());
}
if (taskSubTypes != null && !taskSubTypes.isEmpty()) {
builder.and("sub_type", Op.IN);
builder.and("sub_type", Op.IN).expand(taskSubTypes.size());
}
}

Expand Down

0 comments on commit 8121ef7

Please sign in to comment.