Skip to content

Commit

Permalink
MODSOURMAN-1232 Add the option to exclude job profile names to GET "/…
Browse files Browse the repository at this point in the history
…metadata-provider/jobExecutions" endpoint (#937)

* MODSOURMAN-1232 Add the option to exclude job profile names to GET "/metadata-provider/jobExecutions" endpoint

* add test

* fix pr comment

* fix test

* small fixes
  • Loading branch information
JavokhirAbdullayev authored Oct 15, 2024
1 parent 3f70ca3 commit 2c4be97
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 14 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
## 2024-xx-xx v3.9.0-SNAPSHOT
* [MODSOURMAN-1232](https://folio-org.atlassian.net/browse/MODSOURMAN-1232) Add the option to exclude job profile names to GET "/metadata-provider/jobExecutions" endpoint
* [MODSOURMAN-1195](https://folio-org.atlassian.net/browse/MODSOURMAN-1195) Save job execution progress in batches
* [MODSOURMAN-1166](https://folio-org.atlassian.net/browse/MODSOURMAN-1166) Sorting by Autority, Order and Error columns is not working on Log details page
* [MODDATAIMP-1029](https://folio-org.atlassian.net/browse/MODDATAIMP-1029) The authority record loaded via data-import using Default - Create SRS MARC Authority job profile is duplicated on the job-summary page
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
import java.util.stream.Collectors;

import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
import static org.apache.commons.lang3.StringUtils.EMPTY;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
import static org.folio.dao.util.JobExecutionDBConstants.COMPLETED_DATE_FIELD;
import static org.folio.dao.util.JobExecutionDBConstants.FILE_NAME_FIELD;
import static org.folio.dao.util.JobExecutionDBConstants.HRID_FIELD;
import static org.folio.dao.util.JobExecutionDBConstants.IS_DELETED_FIELD;
import static org.folio.dao.util.JobExecutionDBConstants.JOB_PROFILE_HIDDEN_FIELD;
import static org.folio.dao.util.JobExecutionDBConstants.JOB_PROFILE_ID_FIELD;
import static org.folio.dao.util.JobExecutionDBConstants.JOB_PROFILE_NAME_FIELD;
import static org.folio.dao.util.JobExecutionDBConstants.STATUS_FIELD;
import static org.folio.dao.util.JobExecutionDBConstants.SUBORDINATION_TYPE_FIELD;
import static org.folio.dao.util.JobExecutionDBConstants.UI_STATUS_FIELD;
Expand All @@ -24,6 +26,7 @@
public class JobExecutionFilter {
public static final String LIKE = "LIKE";
public static final String ILIKE = "ILIKE";
private static final String NOT = "NOT";
private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
private List<JobExecution.Status> statusAny;
private List<String> profileIdNotAny;
Expand All @@ -37,6 +40,7 @@ public class JobExecutionFilter {
private String userId;
private Date completedAfter;
private Date completedBefore;
private String excludeJobProfileName;

public JobExecutionFilter withStatusAny(List<JobExecution.Status> statusAny) {
this.statusAny = statusAny;
Expand Down Expand Up @@ -68,6 +72,11 @@ public JobExecutionFilter withFileNamePattern(String fileNamePattern) {
return this;
}

public JobExecutionFilter withExcludeJobProfileName(String excludeJobProfileName) {
this.excludeJobProfileName = excludeJobProfileName;
return this;
}

public JobExecutionFilter withFileNameNotAny(List<String> fileNameNotAny) {
this.fileNameNotAny = fileNameNotAny;
return this;
Expand Down Expand Up @@ -121,16 +130,19 @@ public String buildCriteria() {
addCondition(conditionBuilder, buildInCondition(UI_STATUS_FIELD, uiStatuses));
}
if (isNotEmpty(hrIdPattern) && isNotEmpty(fileNamePattern)) {
conditionBuilder.append(String.format(" AND (%s OR %s)", buildCaseSensitiveLikeCondition(HRID_FIELD, hrIdPattern),
buildCaseInsensitiveLikeCondition(FILE_NAME_FIELD, fileNamePattern)));
conditionBuilder.append(String.format(" AND (%s OR %s)", buildCaseSensitiveLikeCondition(HRID_FIELD, hrIdPattern, false),
buildCaseInsensitiveLikeCondition(FILE_NAME_FIELD, fileNamePattern, false)));
} else {
if (isNotEmpty(hrIdPattern)) {
addCondition(conditionBuilder, buildCaseSensitiveLikeCondition(HRID_FIELD, hrIdPattern));
addCondition(conditionBuilder, buildCaseSensitiveLikeCondition(HRID_FIELD, hrIdPattern, false));
}
if (isNotEmpty(fileNamePattern)) {
addCondition(conditionBuilder, buildCaseInsensitiveLikeCondition(FILE_NAME_FIELD, fileNamePattern));
addCondition(conditionBuilder, buildCaseInsensitiveLikeCondition(FILE_NAME_FIELD, fileNamePattern, false));
}
}
if (isNotEmpty(excludeJobProfileName)) {
addCondition(conditionBuilder, buildCaseInsensitiveLikeCondition(JOB_PROFILE_NAME_FIELD, excludeJobProfileName, true));
}
if (isNotEmpty(fileNameNotAny)) {
addCondition(conditionBuilder, buildNotInCondition(FILE_NAME_FIELD, fileNameNotAny));
}
Expand Down Expand Up @@ -195,18 +207,19 @@ private String buildLessThanOrEqualCondition(String columnName, String value) {
return String.format("%s <= '%s'", columnName, value);
}

private String buildCaseSensitiveLikeCondition(String columnName, String pattern) {
return buildLikeCondition(columnName, pattern, true);
private String buildCaseSensitiveLikeCondition(String columnName, String pattern, boolean denial) {
return buildLikeCondition(columnName, pattern, true, denial);
}

private String buildCaseInsensitiveLikeCondition(String columnName, String pattern) {
return buildLikeCondition(columnName, pattern, false);
private String buildCaseInsensitiveLikeCondition(String columnName, String pattern, boolean denial) {
return buildLikeCondition(columnName, pattern, false, denial);
}

private String buildLikeCondition(String columnName, String pattern, boolean isCaseSensitive) {
private String buildLikeCondition(String columnName, String pattern, boolean isCaseSensitive, boolean denial) {
String preparedLikePattern = pattern.replace("*", "%");
String likeOperator = isCaseSensitive ? LIKE : ILIKE;
return String.format("%s::text %s '%s'", columnName, likeOperator, preparedLikePattern);
String denyOperator = denial ? NOT : EMPTY;
return String.format("%s::text %s %s '%s'", columnName, denyOperator, likeOperator, preparedLikePattern);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ public MetadataProviderImpl(Vertx vertx, String tenantId) { //NOSONAR
}

@Override
public void getMetadataProviderJobExecutions(List<String> statusAny, List<String> profileIdNotAny, String statusNot,
List<String> uiStatusAny, String hrId, String fileName, List<String> fileNameNotAny,
public void getMetadataProviderJobExecutions(String excludeJobProfileName, List<String> statusAny, List<String> profileIdNotAny,
String statusNot, List<String> uiStatusAny, String hrId, String fileName, List<String> fileNameNotAny,
List<String> profileIdAny, List<String> subordinationTypeNotAny, String userId, Date completedAfter,
Date completedBefore, List<String> sortBy, String totalRecords, int offset, int limit, Map<String, String> okapiHeaders,
Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
Expand All @@ -72,7 +72,7 @@ public void getMetadataProviderJobExecutions(List<String> statusAny, List<String
LOGGER.debug("getMetadataProviderJobExecutions:: sortBy {}", sortBy);
List<SortField> sortFields = mapSortQueryToSortFields(sortBy);
JobExecutionFilter filter = buildJobExecutionFilter(statusAny, profileIdNotAny, statusNot, uiStatusAny, hrId, fileName, fileNameNotAny, profileIdAny,
subordinationTypeNotAny, userId, completedAfter, completedBefore);
subordinationTypeNotAny, userId, completedAfter, completedBefore, excludeJobProfileName);
jobExecutionService.getJobExecutionsWithoutParentMultiple(filter, sortFields, offset, limit, tenantId)
.map(GetMetadataProviderJobExecutionsResponse::respond200WithApplicationJson)
.map(Response.class::cast)
Expand Down Expand Up @@ -223,7 +223,8 @@ public void getMetadataProviderIncomingRecordsByRecordId(String recordId, Map<St
private JobExecutionFilter buildJobExecutionFilter(List<String> statusAny, List<String> profileIdNotAny, String statusNot,
List<String> uiStatusAny, String hrIdPattern, String fileNamePattern,
List<String> fileNameNotAny, List<String> profileIdAny, List<String> subordinationTypeNotAny,
String userId, Date completedAfter, Date completedBefore) {
String userId, Date completedAfter, Date completedBefore,
String excludeJobProfileName) {
List<JobExecution.Status> statuses = statusAny.stream()
.map(JobExecution.Status::fromValue)
.toList();
Expand All @@ -239,6 +240,7 @@ private JobExecutionFilter buildJobExecutionFilter(List<String> statusAny, List<
return new JobExecutionFilter()
.withStatusAny(statuses)
.withProfileIdNotAny(profileIdNotAny)
.withExcludeJobProfileName(excludeJobProfileName)
.withStatusNot(statusNot == null ? null : JobExecution.Status.fromValue(statusNot))
.withUiStatusAny(uiStatuses)
.withHrIdPattern(hrIdPattern)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,49 @@ public void shouldReturnFilteredCollectionByHrIdOnGet() {
.body("jobExecutions[0].hrId", is(expectedHrid));
}

@Test
public void shouldReturnFilteredCollectionByExcludeJobProfileNameOnGet() {
List<JobExecution> createdJobExecution = constructAndPostInitJobExecutionRqDto(4).getJobExecutions();
List<JobExecution> childJobsToUpdate = createdJobExecution.stream()
.filter(jobExecution -> jobExecution.getSubordinationType().equals(CHILD))
.collect(Collectors.toList());

List<String> profilesNames = List.of("air", "Apple", "driver", "Zero");

for (int i = 0; i < childJobsToUpdate.size(); i++) {
childJobsToUpdate.get(i).withJobProfileInfo(new JobProfileInfo()
.withId(UUID.randomUUID().toString())
.withName(profilesNames.get(i))
.withDataType(MARC));
putJobExecution(childJobsToUpdate.get(i));
}

RestAssured.given()
.spec(spec)
.when()
.queryParam("excludeJobProfileName", "air")
.get(GET_JOB_EXECUTIONS_PATH)
.then()
.statusCode(HttpStatus.SC_OK)
.body("jobExecutions.size()", is(3))
.body("totalRecords", is(3));
}

@Test
public void shouldReturnFilteredCollectionByExcludeJobProfileNameWithWildcardOnGet() {
constructAndPostInitJobExecutionRqDto(5);

RestAssured.given()
.spec(spec)
.when()
.queryParam("excludeJobProfileName", "importBib*")
.get(GET_JOB_EXECUTIONS_PATH)
.then()
.statusCode(HttpStatus.SC_OK)
.body("jobExecutions.size()", is(0))
.body("totalRecords", is(0));
}

@Test
public void shouldReturnFilteredCollectionByFileNameOnGet() {
constructAndPostInitJobExecutionRqDto(5);
Expand Down
5 changes: 5 additions & 0 deletions ramls/metadata-provider.raml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ resourceTypes:
pageable
]
queryParameters:
excludeJobProfileName:
description: Filter by Job profiles name
type: string
example: Bulk operations data import job profile - *
required: false
statusAny:
description: JobExecution statuses to filter by
type: string[]
Expand Down

0 comments on commit 2c4be97

Please sign in to comment.