From dc5efe527bafa0fb4c0fa128d5b7cd70806e20d9 Mon Sep 17 00:00:00 2001 From: ryzheboka <25465835+ryzheboka@users.noreply.github.com> Date: Wed, 31 Aug 2022 15:46:36 +0200 Subject: [PATCH] TSK-1951: Extend WorkbasketPriorityReport for customInt --- .../reports/TimeIntervalReportBuilder.java | 62 ++++++ .../api/reports/WorkbasketPriorityReport.java | 97 +++++++-- .../internal/MonitorMapperSqlProvider.java | 17 ++ .../TimeIntervalReportBuilderImpl.java | 191 ++++++++++++++++++ .../WorkbasketPriorityReportBuilderImpl.java | 191 ++++++++++++++++++ ...rovideWorkbasketPriorityReportAccTest.java | 178 +++++++++++++++- 6 files changed, 720 insertions(+), 16 deletions(-) diff --git a/lib/taskana-core/src/main/java/pro/taskana/monitor/api/reports/TimeIntervalReportBuilder.java b/lib/taskana-core/src/main/java/pro/taskana/monitor/api/reports/TimeIntervalReportBuilder.java index 22dd3b6e1..2c70b765f 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/monitor/api/reports/TimeIntervalReportBuilder.java +++ b/lib/taskana-core/src/main/java/pro/taskana/monitor/api/reports/TimeIntervalReportBuilder.java @@ -2,6 +2,7 @@ package pro.taskana.monitor.api.reports; import java.util.List; +import pro.taskana.common.api.IntInterval; import pro.taskana.common.api.exceptions.InvalidArgumentException; import pro.taskana.common.api.exceptions.NotAuthorizedException; import pro.taskana.monitor.api.SelectedItem; @@ -9,6 +10,7 @@ import pro.taskana.monitor.api.TaskTimestamp; import pro.taskana.monitor.api.reports.header.TimeIntervalColumnHeader; import pro.taskana.monitor.api.reports.item.AgeQueryItem; import pro.taskana.task.api.TaskCustomField; +import pro.taskana.task.api.TaskCustomIntField; import pro.taskana.task.api.TaskState; import pro.taskana.task.api.models.Task; @@ -127,6 +129,66 @@ public interface TimeIntervalReportBuilder< B customAttributeNotIn(TaskCustomField customField, String... strings) throws InvalidArgumentException; + /** + * Adds the values of a certain {@linkplain TaskCustomIntField} for exact matching to the builder. + * + *

The created {@linkplain Report} contains only {@linkplain Task Tasks} with a {@linkplain + * Task#getCustomIntField(TaskCustomIntField) custom attribute} value exactly matching one of the + * items in the List. + * + * @param customIntField the specified {@linkplain TaskCustomIntField} + * @param values the values the specified {@linkplain Task#getCustomIntField(TaskCustomIntField) + * customIntField } should match + * @return the modified {@linkplain TimeIntervalReportBuilder} + * @throws InvalidArgumentException if filter values are not given + */ + B customIntAttributeIn(TaskCustomIntField customIntField, Integer... values) + throws InvalidArgumentException; + + /** + * Excludes the values of a certain {@linkplain TaskCustomIntField} to the builder. + * + *

The created {@linkplain Report} contains only {@linkplain Task Tasks} with a {@linkplain + * Task#getCustomIntField(TaskCustomIntField) custom attribute} value not matching one of the + * items in the List. + * + * @param customIntField the specified {@linkplain TaskCustomIntField} + * @param values the values the specified {@linkplain Task#getCustomIntField(TaskCustomIntField) + * customIntFields} should not match + * @return the modified TimeIntervalReportBuilder + * @throws InvalidArgumentException if filter values are not given + */ + B customIntAttributeNotIn(TaskCustomIntField customIntField, Integer... values) + throws InvalidArgumentException; + + /** + * Adds ranges of {@linkplain TaskCustomIntField} for matching to the TimeIntervalReportBuilder. + * + *

The created {@linkplain Report} contains only {@linkplain Task Tasks} with a {@linkplain + * Task#getCustomIntField(TaskCustomIntField) customIntField} value being inside the range of one + * of the items in the list. + * + * @param customIntField the specified {@linkplain TaskCustomIntField} + * @param values the values the specified {@linkplain Task#getCustomIntField(TaskCustomIntField) + * customIntField} should match + * @return the modified {@linkplain TimeIntervalReportBuilder} + */ + B customIntAttributeWithin(TaskCustomIntField customIntField, IntInterval... values); + + /** + * Exclude ranges of {@linkplain TaskCustomIntField} for matching to the builder. + * + *

The created report contains only {@linkplain Task Tasks} with a {@linkplain + * Task#getCustomIntField(TaskCustomIntField) customIntField} value being not inside the range of + * one of the items in the list. + * + * @param customIntField the specified {@linkplain TaskCustomIntField} + * @param values the values the specified {@linkplain Task#getCustomIntField(TaskCustomIntField) + * customIntField} should match + * @return the modified {@linkplain TimeIntervalReportBuilder} + */ + B customIntAttributeNotWithin(TaskCustomIntField customIntField, IntInterval... values); + /** * Adds the values of a certain {@linkplain TaskCustomField} for pattern matching to the builder. * diff --git a/lib/taskana-core/src/main/java/pro/taskana/monitor/api/reports/WorkbasketPriorityReport.java b/lib/taskana-core/src/main/java/pro/taskana/monitor/api/reports/WorkbasketPriorityReport.java index 5e18515ec..d91864b37 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/monitor/api/reports/WorkbasketPriorityReport.java +++ b/lib/taskana-core/src/main/java/pro/taskana/monitor/api/reports/WorkbasketPriorityReport.java @@ -2,6 +2,7 @@ package pro.taskana.monitor.api.reports; import java.util.List; +import pro.taskana.common.api.IntInterval; import pro.taskana.common.api.exceptions.InvalidArgumentException; import pro.taskana.common.api.exceptions.NotAuthorizedException; import pro.taskana.monitor.api.reports.header.ColumnHeader; @@ -9,6 +10,7 @@ import pro.taskana.monitor.api.reports.header.PriorityColumnHeader; import pro.taskana.monitor.api.reports.item.PriorityQueryItem; import pro.taskana.monitor.api.reports.row.Row; import pro.taskana.task.api.TaskCustomField; +import pro.taskana.task.api.TaskCustomIntField; import pro.taskana.task.api.TaskState; import pro.taskana.task.api.models.Task; import pro.taskana.workbasket.api.WorkbasketType; @@ -35,10 +37,10 @@ public class WorkbasketPriorityReport extends Report workbasketIds); @@ -56,7 +58,7 @@ public class WorkbasketPriorityReport extends Report states); @@ -65,7 +67,7 @@ public class WorkbasketPriorityReport extends Report classificationCategory); @@ -74,7 +76,7 @@ public class WorkbasketPriorityReport extends Report classificationIds); @@ -83,7 +85,7 @@ public class WorkbasketPriorityReport extends Report excludedClassificationIds); @@ -92,7 +94,7 @@ public class WorkbasketPriorityReport extends Report domains); @@ -106,7 +108,7 @@ public class WorkbasketPriorityReport extends ReportThe created {@linkplain Report} contains only {@linkplain Task Tasks} with a {@linkplain + * Task#getCustomIntField(TaskCustomIntField) customIntField} value exactly matching one of the + * items in the list. + * + * @param customIntField the specified {@linkplain TaskCustomIntField} + * @param values the values the specified {@linkplain Task#getCustomIntField(TaskCustomIntField) + * customIntField} should match + * @return the modified {@linkplain Builder} + * @throws InvalidArgumentException if filter values are not given + */ + Builder customIntAttributeIn(TaskCustomIntField customIntField, Integer... values) + throws InvalidArgumentException; + + /** + * Excludes the values of a certain {@linkplain TaskCustomIntField} to the builder. + * + *

The created {@linkplain Report} contains only {@linkplain Task Tasks} with a {@linkplain + * Task#getCustomIntField(TaskCustomIntField) customIntField} value not matching one of the + * items in the list. + * + * @param customIntField the specified {@linkplain TaskCustomIntField} + * @param values the values the specified {@linkplain Task#getCustomIntField(TaskCustomIntField) + * customIntField} should not match + * @return the modified {@linkplain Builder} + * @throws InvalidArgumentException if filter values are not given + */ + Builder customIntAttributeNotIn(TaskCustomIntField customIntField, Integer... values) + throws InvalidArgumentException; + + /** + * Adds ranges of {@linkplain TaskCustomIntField} for matching to the builder. + * + *

The created report contains only {@linkplain Task Tasks} with a {@linkplain + * Task#getCustomIntField(TaskCustomIntField) customIntField} value being inside the range of + * one of the items in the list. + * + * @param customIntField the specified {@linkplain TaskCustomIntField} + * @param values the values the specified {@linkplain Task#getCustomIntField(TaskCustomIntField) + * customIntField} should match + * @return the modified {@linkplain Builder} + * @throws InvalidArgumentException if filter values are not given + */ + Builder customIntAttributeWithin(TaskCustomIntField customIntField, IntInterval... values) + throws InvalidArgumentException; + + /** + * Exclude ranges of {@linkplain TaskCustomIntField} for matching to the builder. + * + *

The created report contains only {@linkplain Task Tasks} with a {@linkplain + * Task#getCustomIntField(TaskCustomIntField) customIntField} value being not inside the range + * of one of the items in the list. + * + * @param customIntField the specified {@linkplain TaskCustomIntField} + * @param values the values the specified {@linkplain Task#getCustomIntField(TaskCustomIntField) + * customIntField} should match + * @return the modified {@linkplain Builder} + * @throws InvalidArgumentException if filter values are not given + */ + Builder customIntAttributeNotWithin(TaskCustomIntField customIntField, IntInterval... values) + throws InvalidArgumentException; + + /** + * Adds a list of {@linkplain PriorityColumnHeader PriorityColumnHeaders} to the builder to + * subdivide the report into clusters. * * @param columnHeaders the column headers the report should consist of. - * @return the builder + * @return the {@linkplain Builder} */ Builder withColumnHeaders(List columnHeaders); /** * If this filter is used, the days of the report are counted in working days. * - * @return the TimeIntervalReportBuilder + * @return the {@linkplain Builder} */ Builder inWorkingDays(); } diff --git a/lib/taskana-core/src/main/java/pro/taskana/monitor/internal/MonitorMapperSqlProvider.java b/lib/taskana-core/src/main/java/pro/taskana/monitor/internal/MonitorMapperSqlProvider.java index 469ce4095..468ec2c1e 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/monitor/internal/MonitorMapperSqlProvider.java +++ b/lib/taskana-core/src/main/java/pro/taskana/monitor/internal/MonitorMapperSqlProvider.java @@ -5,8 +5,10 @@ import static pro.taskana.common.internal.util.SqlProviderUtil.CLOSING_WHERE_TAG import static pro.taskana.common.internal.util.SqlProviderUtil.OPENING_SCRIPT_TAG; import static pro.taskana.common.internal.util.SqlProviderUtil.OPENING_WHERE_TAG; import static pro.taskana.common.internal.util.SqlProviderUtil.whereIn; +import static pro.taskana.common.internal.util.SqlProviderUtil.whereInInterval; import static pro.taskana.common.internal.util.SqlProviderUtil.whereLike; import static pro.taskana.common.internal.util.SqlProviderUtil.whereNotIn; +import static pro.taskana.common.internal.util.SqlProviderUtil.whereNotInInterval; import java.util.stream.IntStream; @@ -293,6 +295,20 @@ public class MonitorMapperSqlProvider { return sb; } + private static StringBuilder whereCustomIntStatements( + String baseCollection, String baseColumn, int customBound, StringBuilder sb) { + IntStream.rangeClosed(1, customBound) + .forEach( + x -> { + String column = baseColumn + "_" + x; + whereIn(baseCollection + x + "In", column, sb); + whereNotIn(baseCollection + x + "NotIn", column, sb); + whereInInterval(baseCollection + x + "Within", column, sb); + whereNotInInterval(baseCollection + x + "NotWithin", column, sb); + }); + return sb; + } + private static StringBuilder taskWhereStatements() { StringBuilder sb = new StringBuilder(); SqlProviderUtil.whereIn("report.workbasketIds", "T.WORKBASKET_ID", sb); @@ -302,6 +318,7 @@ public class MonitorMapperSqlProvider { SqlProviderUtil.whereIn("report.classificationIds", "T.CLASSIFICATION_ID", sb); SqlProviderUtil.whereNotIn("report.excludedClassificationIds", "T.CLASSIFICATION_ID", sb); whereCustomStatements("report.custom", "T.CUSTOM", 16, sb); + whereCustomIntStatements("report.customInt", "T.CUSTOM_INT", 8, sb); return sb; } diff --git a/lib/taskana-core/src/main/java/pro/taskana/monitor/internal/reports/TimeIntervalReportBuilderImpl.java b/lib/taskana-core/src/main/java/pro/taskana/monitor/internal/reports/TimeIntervalReportBuilderImpl.java index 01d7cc6ca..9185ab7dd 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/monitor/internal/reports/TimeIntervalReportBuilderImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/monitor/internal/reports/TimeIntervalReportBuilderImpl.java @@ -5,6 +5,7 @@ import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +import pro.taskana.common.api.IntInterval; import pro.taskana.common.api.TaskanaRole; import pro.taskana.common.api.WorkingDaysToDaysConverter; import pro.taskana.common.api.exceptions.InvalidArgumentException; @@ -21,6 +22,7 @@ import pro.taskana.monitor.api.reports.item.AgeQueryItem; import pro.taskana.monitor.internal.MonitorMapper; import pro.taskana.monitor.internal.preprocessor.WorkingDaysToDaysReportConverter; import pro.taskana.task.api.TaskCustomField; +import pro.taskana.task.api.TaskCustomIntField; import pro.taskana.task.api.TaskState; /** @@ -95,6 +97,39 @@ abstract class TimeIntervalReportBuilderImpl< private String[] custom16In; private String[] custom16NotIn; private String[] custom16Like; + private Integer[] customInt1In; + private Integer[] customInt1NotIn; + private Integer[] customInt2In; + private Integer[] customInt2NotIn; + private Integer[] customInt3In; + private Integer[] customInt3NotIn; + private Integer[] customInt4In; + private Integer[] customInt4NotIn; + private Integer[] customInt5In; + private Integer[] customInt5NotIn; + private Integer[] customInt6In; + private Integer[] customInt6NotIn; + private Integer[] customInt7In; + private Integer[] customInt7NotIn; + private Integer[] customInt8In; + private Integer[] customInt8NotIn; + + private IntInterval[] customInt1Within; + private IntInterval[] customInt1NotWithin; + private IntInterval[] customInt2Within; + private IntInterval[] customInt2NotWithin; + private IntInterval[] customInt3Within; + private IntInterval[] customInt3NotWithin; + private IntInterval[] customInt4Within; + private IntInterval[] customInt4NotWithin; + private IntInterval[] customInt5Within; + private IntInterval[] customInt5NotWithin; + private IntInterval[] customInt6Within; + private IntInterval[] customInt6NotWithin; + private IntInterval[] customInt7Within; + private IntInterval[] customInt7NotWithin; + private IntInterval[] customInt8Within; + private IntInterval[] customInt8NotWithin; TimeIntervalReportBuilderImpl(InternalTaskanaEngine taskanaEngine, MonitorMapper monitorMapper) { this.taskanaEngine = taskanaEngine; @@ -289,6 +324,162 @@ abstract class TimeIntervalReportBuilderImpl< return _this(); } + @Override + public B customIntAttributeIn(TaskCustomIntField customIntField, Integer... values) + throws InvalidArgumentException { + if (values.length == 0) { + throw new InvalidArgumentException( + "At least one Integer has to be provided as a search parameter"); + } + switch (customIntField) { + case CUSTOM_INT_1: + this.customInt1In = values; + break; + case CUSTOM_INT_2: + this.customInt2In = values; + break; + case CUSTOM_INT_3: + this.customInt3In = values; + break; + case CUSTOM_INT_4: + this.customInt4In = values; + break; + case CUSTOM_INT_5: + this.customInt5In = values; + break; + case CUSTOM_INT_6: + this.customInt6In = values; + break; + case CUSTOM_INT_7: + this.customInt7In = values; + break; + case CUSTOM_INT_8: + this.customInt8In = values; + break; + default: + throw new SystemException("Unknown custom int attribute '" + customIntField + "'"); + } + + return _this(); + } + + @Override + public B customIntAttributeNotIn(TaskCustomIntField customIntField, Integer... values) + throws InvalidArgumentException { + if (values.length == 0) { + throw new InvalidArgumentException( + "At least one Integer has to be provided as a search parameter"); + } + switch (customIntField) { + case CUSTOM_INT_1: + this.customInt1NotIn = values; + break; + case CUSTOM_INT_2: + this.customInt2NotIn = values; + break; + case CUSTOM_INT_3: + this.customInt3NotIn = values; + break; + case CUSTOM_INT_4: + this.customInt4NotIn = values; + break; + case CUSTOM_INT_5: + this.customInt5NotIn = values; + break; + case CUSTOM_INT_6: + this.customInt6NotIn = values; + break; + case CUSTOM_INT_7: + this.customInt7NotIn = values; + break; + case CUSTOM_INT_8: + this.customInt8NotIn = values; + break; + default: + throw new SystemException("Unknown custom int attribute '" + customIntField + "'"); + } + + return _this(); + } + + @Override + public B customIntAttributeWithin(TaskCustomIntField customIntField, IntInterval... values) + throws IllegalArgumentException { + for (IntInterval i : values) { + if (!i.isValid()) { + throw new IllegalArgumentException("IntInterval " + i + " is invalid."); + } + } + switch (customIntField) { + case CUSTOM_INT_1: + this.customInt1Within = values; + break; + case CUSTOM_INT_2: + this.customInt2Within = values; + break; + case CUSTOM_INT_3: + this.customInt3Within = values; + break; + case CUSTOM_INT_4: + this.customInt4Within = values; + break; + case CUSTOM_INT_5: + this.customInt5Within = values; + break; + case CUSTOM_INT_6: + this.customInt6Within = values; + break; + case CUSTOM_INT_7: + this.customInt7Within = values; + break; + case CUSTOM_INT_8: + this.customInt8Within = values; + break; + default: + throw new SystemException("Unknown custom int attribute '" + customIntField + "'"); + } + return _this(); + } + + @Override + public B customIntAttributeNotWithin(TaskCustomIntField customIntField, IntInterval... values) + throws IllegalArgumentException { + for (IntInterval i : values) { + if (!i.isValid()) { + throw new IllegalArgumentException("IntInterval " + i + " is invalid."); + } + } + switch (customIntField) { + case CUSTOM_INT_1: + this.customInt1NotWithin = values; + break; + case CUSTOM_INT_2: + this.customInt2NotWithin = values; + break; + case CUSTOM_INT_3: + this.customInt3NotWithin = values; + break; + case CUSTOM_INT_4: + this.customInt4NotWithin = values; + break; + case CUSTOM_INT_5: + this.customInt5NotWithin = values; + break; + case CUSTOM_INT_6: + this.customInt6NotWithin = values; + break; + case CUSTOM_INT_7: + this.customInt7NotWithin = values; + break; + case CUSTOM_INT_8: + this.customInt8NotWithin = values; + break; + default: + throw new SystemException("Unknown custom int attribute '" + customIntField + "'"); + } + return _this(); + } + @Override public B customAttributeLike(TaskCustomField customField, String... strings) throws InvalidArgumentException { diff --git a/lib/taskana-core/src/main/java/pro/taskana/monitor/internal/reports/WorkbasketPriorityReportBuilderImpl.java b/lib/taskana-core/src/main/java/pro/taskana/monitor/internal/reports/WorkbasketPriorityReportBuilderImpl.java index 0215989b3..90e3315b4 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/monitor/internal/reports/WorkbasketPriorityReportBuilderImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/monitor/internal/reports/WorkbasketPriorityReportBuilderImpl.java @@ -3,6 +3,7 @@ package pro.taskana.monitor.internal.reports; import java.util.Collections; import java.util.List; +import pro.taskana.common.api.IntInterval; import pro.taskana.common.api.TaskanaRole; import pro.taskana.common.api.WorkingDaysToDaysConverter; import pro.taskana.common.api.exceptions.InvalidArgumentException; @@ -15,6 +16,7 @@ import pro.taskana.monitor.api.reports.header.PriorityColumnHeader; import pro.taskana.monitor.api.reports.item.PriorityQueryItem; import pro.taskana.monitor.internal.MonitorMapper; import pro.taskana.task.api.TaskCustomField; +import pro.taskana.task.api.TaskCustomIntField; import pro.taskana.task.api.TaskState; import pro.taskana.workbasket.api.WorkbasketType; @@ -80,6 +82,39 @@ public class WorkbasketPriorityReportBuilderImpl implements WorkbasketPriorityRe private String[] custom16In; private String[] custom16NotIn; private String[] custom16Like; + private Integer[] customInt1In; + private Integer[] customInt1NotIn; + private Integer[] customInt2In; + private Integer[] customInt2NotIn; + private Integer[] customInt3In; + private Integer[] customInt3NotIn; + private Integer[] customInt4In; + private Integer[] customInt4NotIn; + private Integer[] customInt5In; + private Integer[] customInt5NotIn; + private Integer[] customInt6In; + private Integer[] customInt6NotIn; + private Integer[] customInt7In; + private Integer[] customInt7NotIn; + private Integer[] customInt8In; + private Integer[] customInt8NotIn; + + private IntInterval[] customInt1Within; + private IntInterval[] customInt1NotWithin; + private IntInterval[] customInt2Within; + private IntInterval[] customInt2NotWithin; + private IntInterval[] customInt3Within; + private IntInterval[] customInt3NotWithin; + private IntInterval[] customInt4Within; + private IntInterval[] customInt4NotWithin; + private IntInterval[] customInt5Within; + private IntInterval[] customInt5NotWithin; + private IntInterval[] customInt6Within; + private IntInterval[] customInt6NotWithin; + private IntInterval[] customInt7Within; + private IntInterval[] customInt7NotWithin; + private IntInterval[] customInt8Within; + private IntInterval[] customInt8NotWithin; @SuppressWarnings("unused") public WorkbasketPriorityReportBuilderImpl( @@ -292,6 +327,162 @@ public class WorkbasketPriorityReportBuilderImpl implements WorkbasketPriorityRe return this; } + @Override + public Builder customIntAttributeIn(TaskCustomIntField customIntField, Integer... values) + throws InvalidArgumentException { + if (values.length == 0) { + throw new InvalidArgumentException( + "At least one Integer has to be provided as a search parameter"); + } + switch (customIntField) { + case CUSTOM_INT_1: + this.customInt1In = values; + break; + case CUSTOM_INT_2: + this.customInt2In = values; + break; + case CUSTOM_INT_3: + this.customInt3In = values; + break; + case CUSTOM_INT_4: + this.customInt4In = values; + break; + case CUSTOM_INT_5: + this.customInt5In = values; + break; + case CUSTOM_INT_6: + this.customInt6In = values; + break; + case CUSTOM_INT_7: + this.customInt7In = values; + break; + case CUSTOM_INT_8: + this.customInt8In = values; + break; + default: + throw new SystemException("Unknown custom int attribute '" + customIntField + "'"); + } + + return this; + } + + @Override + public Builder customIntAttributeNotIn(TaskCustomIntField customIntField, Integer... values) + throws InvalidArgumentException { + if (values.length == 0) { + throw new InvalidArgumentException( + "At least one Integer has to be provided as a search parameter"); + } + switch (customIntField) { + case CUSTOM_INT_1: + this.customInt1NotIn = values; + break; + case CUSTOM_INT_2: + this.customInt2NotIn = values; + break; + case CUSTOM_INT_3: + this.customInt3NotIn = values; + break; + case CUSTOM_INT_4: + this.customInt4NotIn = values; + break; + case CUSTOM_INT_5: + this.customInt5NotIn = values; + break; + case CUSTOM_INT_6: + this.customInt6NotIn = values; + break; + case CUSTOM_INT_7: + this.customInt7NotIn = values; + break; + case CUSTOM_INT_8: + this.customInt8NotIn = values; + break; + default: + throw new SystemException("Unknown custom int attribute '" + customIntField + "'"); + } + + return this; + } + + @Override + public Builder customIntAttributeWithin( + TaskCustomIntField customIntField, IntInterval... values) { + for (IntInterval i : values) { + if (!i.isValid()) { + throw new IllegalArgumentException("IntInterval " + i + " is invalid."); + } + } + switch (customIntField) { + case CUSTOM_INT_1: + this.customInt1Within = values; + break; + case CUSTOM_INT_2: + this.customInt2Within = values; + break; + case CUSTOM_INT_3: + this.customInt3Within = values; + break; + case CUSTOM_INT_4: + this.customInt4Within = values; + break; + case CUSTOM_INT_5: + this.customInt5Within = values; + break; + case CUSTOM_INT_6: + this.customInt6Within = values; + break; + case CUSTOM_INT_7: + this.customInt7Within = values; + break; + case CUSTOM_INT_8: + this.customInt8Within = values; + break; + default: + throw new SystemException("Unknown custom int attribute '" + customIntField + "'"); + } + return this; + } + + @Override + public Builder customIntAttributeNotWithin( + TaskCustomIntField customIntField, IntInterval... values) { + for (IntInterval i : values) { + if (!i.isValid()) { + throw new IllegalArgumentException("IntInterval " + i + " is invalid."); + } + } + switch (customIntField) { + case CUSTOM_INT_1: + this.customInt1NotWithin = values; + break; + case CUSTOM_INT_2: + this.customInt2NotWithin = values; + break; + case CUSTOM_INT_3: + this.customInt3NotWithin = values; + break; + case CUSTOM_INT_4: + this.customInt4NotWithin = values; + break; + case CUSTOM_INT_5: + this.customInt5NotWithin = values; + break; + case CUSTOM_INT_6: + this.customInt6NotWithin = values; + break; + case CUSTOM_INT_7: + this.customInt7NotWithin = values; + break; + case CUSTOM_INT_8: + this.customInt8NotWithin = values; + break; + default: + throw new SystemException("Unknown custom int attribute '" + customIntField + "'"); + } + return this; + } + @Override public Builder customAttributeLike(TaskCustomField customField, String... strings) throws InvalidArgumentException { diff --git a/lib/taskana-core/src/test/java/acceptance/report/ProvideWorkbasketPriorityReportAccTest.java b/lib/taskana-core/src/test/java/acceptance/report/ProvideWorkbasketPriorityReportAccTest.java index 46e431220..8094f7db7 100644 --- a/lib/taskana-core/src/test/java/acceptance/report/ProvideWorkbasketPriorityReportAccTest.java +++ b/lib/taskana-core/src/test/java/acceptance/report/ProvideWorkbasketPriorityReportAccTest.java @@ -6,11 +6,18 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.util.Arrays; import java.util.List; +import java.util.stream.Stream; +import org.assertj.core.api.ThrowableAssert.ThrowingCallable; +import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.function.ThrowingConsumer; +import pro.taskana.common.api.IntInterval; import pro.taskana.common.api.exceptions.MismatchedRoleException; +import pro.taskana.common.internal.util.Pair; import pro.taskana.common.test.security.JaasExtension; import pro.taskana.common.test.security.WithAccessId; import pro.taskana.monitor.api.MonitorService; @@ -19,10 +26,10 @@ import pro.taskana.monitor.api.reports.WorkbasketPriorityReport; import pro.taskana.monitor.api.reports.header.PriorityColumnHeader; import pro.taskana.monitor.api.reports.row.Row; import pro.taskana.task.api.TaskCustomField; +import pro.taskana.task.api.TaskCustomIntField; import pro.taskana.task.api.TaskState; import pro.taskana.workbasket.api.WorkbasketType; -/** Acceptance test for all "workbasket priority report" scenarios. */ @ExtendWith(JaasExtension.class) class ProvideWorkbasketPriorityReportAccTest extends AbstractReportAccTest { @@ -329,4 +336,173 @@ class ProvideWorkbasketPriorityReportAccTest extends AbstractReportAccTest { int[] row1 = report.getRow("USER-1-1").getCells(); assertThat(row1).isEqualTo(new int[] {1, 0, 0}); } + + @WithAccessId(user = "monitor") + @TestFactory + Stream should_ApplyFilter_When_QueryingForCustomIntIn() { + List> testCases = + List.of( + Pair.of(TaskCustomIntField.CUSTOM_INT_1, 1), + Pair.of(TaskCustomIntField.CUSTOM_INT_2, 2), + Pair.of(TaskCustomIntField.CUSTOM_INT_3, 3), + Pair.of(TaskCustomIntField.CUSTOM_INT_4, 4), + Pair.of(TaskCustomIntField.CUSTOM_INT_5, 5), + Pair.of(TaskCustomIntField.CUSTOM_INT_6, 6), + Pair.of(TaskCustomIntField.CUSTOM_INT_7, 7), + Pair.of(TaskCustomIntField.CUSTOM_INT_8, 8)); + + ThrowingConsumer> test = + p -> { + WorkbasketPriorityReport report = + MONITOR_SERVICE + .createWorkbasketPriorityReportBuilder() + .withColumnHeaders(DEFAULT_TEST_HEADERS) + .customIntAttributeIn(p.getLeft(), p.getRight()) + .inWorkingDays() + .buildReport(); + assertThat(report).isNotNull(); + assertThat(report.rowSize()).isEqualTo(5); + assertThat(report.getRow("USER-1-1").getCells()).isEqualTo(new int[] {20, 0, 0}); + }; + + return DynamicTest.stream(testCases.iterator(), p -> p.getLeft().name(), test); + } + + @WithAccessId(user = "monitor") + @TestFactory + Stream should_ApplyFilter_When_QueryingForCustomIntNotIn() { + List> testCases = + List.of( + Pair.of(TaskCustomIntField.CUSTOM_INT_1, 1), + Pair.of(TaskCustomIntField.CUSTOM_INT_2, 2), + Pair.of(TaskCustomIntField.CUSTOM_INT_3, 3), + Pair.of(TaskCustomIntField.CUSTOM_INT_4, 4), + Pair.of(TaskCustomIntField.CUSTOM_INT_5, 5), + Pair.of(TaskCustomIntField.CUSTOM_INT_6, 6), + Pair.of(TaskCustomIntField.CUSTOM_INT_7, 7), + Pair.of(TaskCustomIntField.CUSTOM_INT_8, 8)); + + ThrowingConsumer> test = + p -> { + WorkbasketPriorityReport report = + MONITOR_SERVICE + .createWorkbasketPriorityReportBuilder() + .withColumnHeaders(DEFAULT_TEST_HEADERS) + .customIntAttributeNotIn(p.getLeft(), p.getRight()) + .inWorkingDays() + .buildReport(); + assertThat(report).isNotNull(); + assertThat(report.rowSize()).isZero(); + }; + + return DynamicTest.stream(testCases.iterator(), p -> p.getLeft().name(), test); + } + + @WithAccessId(user = "monitor") + @TestFactory + Stream should_ApplyFilter_When_QueryingForCustomIntWithin() { + List> testCases = + List.of( + Pair.of(TaskCustomIntField.CUSTOM_INT_1, new IntInterval(1, null)), + Pair.of(TaskCustomIntField.CUSTOM_INT_2, new IntInterval(2, null)), + Pair.of(TaskCustomIntField.CUSTOM_INT_3, new IntInterval(3, null)), + Pair.of(TaskCustomIntField.CUSTOM_INT_4, new IntInterval(4, null)), + Pair.of(TaskCustomIntField.CUSTOM_INT_5, new IntInterval(5, null)), + Pair.of(TaskCustomIntField.CUSTOM_INT_6, new IntInterval(6, null)), + Pair.of(TaskCustomIntField.CUSTOM_INT_7, new IntInterval(7, null)), + Pair.of(TaskCustomIntField.CUSTOM_INT_8, new IntInterval(8, null))); + + ThrowingConsumer> test = + p -> { + WorkbasketPriorityReport report = + MONITOR_SERVICE + .createWorkbasketPriorityReportBuilder() + .withColumnHeaders(DEFAULT_TEST_HEADERS) + .customIntAttributeWithin(p.getLeft(), p.getRight()) + .inWorkingDays() + .buildReport(); + assertThat(report).isNotNull(); + assertThat(report.rowSize()).isEqualTo(5); + assertThat(report.getRow("USER-1-1").getCells()).isEqualTo(new int[] {20, 0, 0}); + }; + + return DynamicTest.stream(testCases.iterator(), p -> p.getLeft().name(), test); + } + + @WithAccessId(user = "monitor") + @TestFactory + Stream should_ApplyFilter_When_QueryingForCustomIntNotWithin() { + List> testCases = + List.of( + Pair.of(TaskCustomIntField.CUSTOM_INT_1, new IntInterval(3, null)), + Pair.of(TaskCustomIntField.CUSTOM_INT_2, new IntInterval(4, null)), + Pair.of(TaskCustomIntField.CUSTOM_INT_3, new IntInterval(5, null)), + Pair.of(TaskCustomIntField.CUSTOM_INT_4, new IntInterval(6, null)), + Pair.of(TaskCustomIntField.CUSTOM_INT_5, new IntInterval(7, null)), + Pair.of(TaskCustomIntField.CUSTOM_INT_6, new IntInterval(8, null)), + Pair.of(TaskCustomIntField.CUSTOM_INT_7, new IntInterval(9, null)), + Pair.of(TaskCustomIntField.CUSTOM_INT_8, new IntInterval(10, null))); + + ThrowingConsumer> test = + p -> { + WorkbasketPriorityReport report = + MONITOR_SERVICE + .createWorkbasketPriorityReportBuilder() + .withColumnHeaders(DEFAULT_TEST_HEADERS) + .customIntAttributeNotWithin(p.getLeft(), p.getRight()) + .inWorkingDays() + .buildReport(); + assertThat(report).isNotNull(); + assertThat(report.rowSize()).isEqualTo(5); + assertThat(report.getRow("USER-1-1").getCells()).isEqualTo(new int[] {20, 0, 0}); + }; + + return DynamicTest.stream(testCases.iterator(), p -> p.getLeft().name(), test); + } + + @WithAccessId(user = "monitor") + @TestFactory + Stream should_ThrowException_When_FilteringByCustomIntWithinWithInvalidIntervals() { + List> testCases = + List.of( + Pair.of(TaskCustomIntField.CUSTOM_INT_1, new IntInterval[] {new IntInterval(4, 1)}), + // Only first interval invalid + Pair.of( + TaskCustomIntField.CUSTOM_INT_2, + new IntInterval[] {new IntInterval(null, null), new IntInterval(0, null)}), + // Only second interval invalid + Pair.of( + TaskCustomIntField.CUSTOM_INT_3, + new IntInterval[] {new IntInterval(-1, 5), new IntInterval(null, null)}), + // Both intervals invalid + Pair.of( + TaskCustomIntField.CUSTOM_INT_4, + new IntInterval[] {new IntInterval(0, -5), new IntInterval(-2, -10)}), + // One interval invalid + Pair.of( + TaskCustomIntField.CUSTOM_INT_5, new IntInterval[] {new IntInterval(null, null)}), + Pair.of(TaskCustomIntField.CUSTOM_INT_6, new IntInterval[] {new IntInterval(0, -5)}), + Pair.of( + TaskCustomIntField.CUSTOM_INT_7, + new IntInterval[] {new IntInterval(null, null), new IntInterval(null, null)}), + Pair.of( + TaskCustomIntField.CUSTOM_INT_8, new IntInterval[] {new IntInterval(123, 122)})); + + ThrowingConsumer> test = + p -> { + ThrowingCallable result = + () -> + MONITOR_SERVICE + .createWorkbasketPriorityReportBuilder() + .withColumnHeaders(DEFAULT_TEST_HEADERS) + .customIntAttributeWithin(p.getLeft(), p.getRight()) + .inWorkingDays() + .buildReport(); + assertThatThrownBy(result) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("IntInterval"); + }; + + return DynamicTest.stream(testCases.iterator(), p -> p.getLeft().name(), test); + } }