diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/TaskService.java b/modules/flowable-engine/src/main/java/org/flowable/engine/TaskService.java index 8434d5fd89c..1e8ee5623de 100644 --- a/modules/flowable-engine/src/main/java/org/flowable/engine/TaskService.java +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/TaskService.java @@ -19,6 +19,7 @@ import java.util.Map; import java.util.Set; +import org.flowable.engine.task.CommentQuery; import org.flowable.task.api.TaskCompletionBuilder; import org.flowable.common.engine.api.FlowableException; import org.flowable.common.engine.api.FlowableObjectNotFoundException; @@ -816,6 +817,11 @@ void completeTaskWithForm(String taskId, String formDefinitionId, String outcome /** The comments related to the given process instance. */ List getProcessInstanceComments(String processInstanceId, String type); + /** + * Returns a new {@link CommentQuery} that can be used to dynamically query comments. + */ + CommentQuery createCommentQuery(); + /** * Add a new attachment to a task and/or a process instance and use an input stream to provide the content */ diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/CommentQueryImpl.java b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/CommentQueryImpl.java new file mode 100644 index 00000000000..c4678471e38 --- /dev/null +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/CommentQueryImpl.java @@ -0,0 +1,160 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.engine.impl; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Date; +import java.util.List; + +import org.flowable.common.engine.api.FlowableIllegalArgumentException; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.common.engine.impl.interceptor.CommandExecutor; +import org.flowable.common.engine.impl.query.AbstractQuery; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.task.Comment; +import org.flowable.engine.task.CommentQuery; + +/** + * @author David Lamas + */ +public class CommentQueryImpl extends AbstractQuery implements CommentQuery, Serializable { + private ProcessEngineConfigurationImpl processEngineConfiguration; + + private String commentId; + private String taskId; + private String processInstanceId; + private String type; + private String createdBy; + private Collection createdByOneOf; + private Date createdBefore; + private Date createdAfter; + private Date createdOn; + + public CommentQueryImpl() { + } + + public CommentQueryImpl(CommandExecutor commandExecutor, ProcessEngineConfigurationImpl processEngineConfiguration) { + super(commandExecutor); + this.processEngineConfiguration = processEngineConfiguration; + } + + public CommentQueryImpl(CommandContext commandContext, ProcessEngineConfigurationImpl processEngineConfiguration) { + super(commandContext); + this.processEngineConfiguration = processEngineConfiguration; + } + + @Override + public CommentQuery commentId(String commentId) { + this.commentId = commentId; + return this; + } + + @Override + public CommentQuery taskId(String taskId) { + this.taskId = taskId; + return this; + } + + @Override + public CommentQuery processInstanceId(String processInstanceId) { + this.processInstanceId = processInstanceId; + return this; + } + + @Override + public CommentQuery type(String type) { + this.type = type; + return this; + } + + @Override + public CommentQuery createdBy(String userId) { + if (userId != null) { + if (createdByOneOf != null) { + throw new FlowableIllegalArgumentException("Invalid query usage: cannot set both createdBy and createdByOneOf"); + } + } + this.createdBy = userId; + return this; + } + + @Override + public CommentQuery createdByOneOf(Collection userIds) { + if (userIds != null) { + if (userIds.isEmpty()) { + throw new FlowableIllegalArgumentException("User id list cannot be empty"); + } + + if (createdBy != null) { + throw new FlowableIllegalArgumentException("Invalid query usage: cannot set both createdBy and createdByOneOf"); + } + } + + this.createdByOneOf = userIds; + return this; + } + + @Override + public CommentQuery createdBefore(Date beforeTime) { + this.createdBefore = beforeTime; + return this; + } + + @Override + public CommentQuery createdAfter(Date afterTime) { + this.createdAfter = afterTime; + return this; + } + + @Override + public CommentQuery createdOn(Date createTime) { + this.createdOn = createTime; + return this; + } + + @Override + public CommentQuery orderByCreateTime() { + return orderBy(CommentQueryProperty.TIME); + } + + @Override + public CommentQuery orderByUser() { + return orderBy(CommentQueryProperty.USER_ID); + } + + @Override + public CommentQuery orderByType() { + return orderBy(CommentQueryProperty.TYPE); + } + + @Override + public CommentQuery orderByTaskId() { + return orderBy(CommentQueryProperty.TASK_ID); + } + + @Override + public CommentQuery orderByProcessInstanceId() { + return orderBy(CommentQueryProperty.PROCESS_INSTANCE_ID); + } + + @Override + public long executeCount(CommandContext commandContext) { + return processEngineConfiguration.getCommentEntityManager().findCommentCountByQueryCriteria(this); + } + + @Override + public List executeList(CommandContext commandContext) { + return processEngineConfiguration.getCommentEntityManager().findCommentsByQueryCriteria(this); + } +} diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/CommentQueryProperty.java b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/CommentQueryProperty.java new file mode 100644 index 00000000000..4603e77b416 --- /dev/null +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/CommentQueryProperty.java @@ -0,0 +1,52 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.engine.impl; + +import java.util.HashMap; +import java.util.Map; + +import org.flowable.common.engine.api.query.QueryProperty; + +/** + * Contains the possible properties which can be used in a {@link org.flowable.engine.task.CommentQuery}. + * + * @author David Lamas + */ +public class CommentQueryProperty implements QueryProperty { + private static final long serialVersionUID = 1L; + + private static final Map properties = new HashMap<>(); + + public static final CommentQueryProperty ID = new CommentQueryProperty("RES.ID_"); + public static final CommentQueryProperty TIME = new CommentQueryProperty("RES.TIME_"); + public static final CommentQueryProperty USER_ID = new CommentQueryProperty("RES.USER_ID_"); + public static final CommentQueryProperty TYPE = new CommentQueryProperty("RES.TYPE_"); + public static final CommentQueryProperty TASK_ID = new CommentQueryProperty("RES.TASK_ID_"); + public static final CommentQueryProperty PROCESS_INSTANCE_ID = new CommentQueryProperty("RES.PROC_INST_ID_"); + + private String name; + + public CommentQueryProperty(String name) { + this.name = name; + properties.put(name, this); + } + + @Override + public String getName() { + return name; + } + + public static CommentQueryProperty findByName(String propertyName) { + return properties.get(propertyName); + } +} diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/TaskServiceImpl.java b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/TaskServiceImpl.java index 66c65f2a183..928922276da 100644 --- a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/TaskServiceImpl.java +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/TaskServiceImpl.java @@ -72,6 +72,7 @@ import org.flowable.engine.runtime.DataObject; import org.flowable.engine.task.Attachment; import org.flowable.engine.task.Comment; +import org.flowable.engine.task.CommentQuery; import org.flowable.engine.task.Event; import org.flowable.form.api.FormInfo; import org.flowable.identitylink.api.IdentityLink; @@ -460,6 +461,11 @@ public List getProcessInstanceComments(String processInstanceId, String return commandExecutor.execute(new GetProcessInstanceCommentsCmd(processInstanceId, type)); } + @Override + public CommentQuery createCommentQuery() { + return new CommentQueryImpl(getCommandExecutor(), getConfiguration()); + } + @Override public Attachment createAttachment(String attachmentType, String taskId, String processInstanceId, String attachmentName, String attachmentDescription, InputStream content) { return commandExecutor.execute(new CreateAttachmentCmd(attachmentType, taskId, processInstanceId, attachmentName, attachmentDescription, content, null)); diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/CommentEntityManager.java b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/CommentEntityManager.java index 6aa59e038dd..3ed64e3a116 100644 --- a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/CommentEntityManager.java +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/CommentEntityManager.java @@ -15,6 +15,7 @@ import java.util.List; import org.flowable.common.engine.impl.persistence.entity.EntityManager; +import org.flowable.engine.impl.CommentQueryImpl; import org.flowable.engine.task.Comment; import org.flowable.engine.task.Event; @@ -45,4 +46,8 @@ public interface CommentEntityManager extends EntityManager { Event findEvent(String commentId); + List findCommentsByQueryCriteria(CommentQueryImpl query); + + long findCommentCountByQueryCriteria(CommentQueryImpl query); + } \ No newline at end of file diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/CommentEntityManagerImpl.java b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/CommentEntityManagerImpl.java index 0847a87cb43..4571110cc10 100644 --- a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/CommentEntityManagerImpl.java +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/CommentEntityManagerImpl.java @@ -19,6 +19,7 @@ import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType; import org.flowable.engine.delegate.event.impl.FlowableEventBuilder; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.CommentQueryImpl; import org.flowable.engine.impl.history.HistoryManager; import org.flowable.engine.impl.persistence.entity.data.CommentDataManager; import org.flowable.engine.task.Comment; @@ -176,6 +177,16 @@ public void delete(CommentEntity commentEntity) { } } + @Override + public List findCommentsByQueryCriteria(CommentQueryImpl query) { + return dataManager.findCommentsByQueryCriteria(query); + } + + @Override + public long findCommentCountByQueryCriteria(CommentQueryImpl query) { + return dataManager.findCommentCountByQueryCriteria(query); + } + protected void checkHistoryEnabled() { if (!getHistoryManager().isHistoryEnabled()) { throw new FlowableException("In order to use comments, history should be enabled"); diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/data/CommentDataManager.java b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/data/CommentDataManager.java index 4373e917b61..b3916b5fde1 100644 --- a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/data/CommentDataManager.java +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/data/CommentDataManager.java @@ -15,6 +15,7 @@ import java.util.List; import org.flowable.common.engine.impl.persistence.entity.data.DataManager; +import org.flowable.engine.impl.CommentQueryImpl; import org.flowable.engine.impl.persistence.entity.CommentEntity; import org.flowable.engine.task.Comment; import org.flowable.engine.task.Event; @@ -46,4 +47,8 @@ public interface CommentDataManager extends DataManager { Event findEvent(String commentId); + List findCommentsByQueryCriteria(CommentQueryImpl commentQuery); + + long findCommentCountByQueryCriteria(CommentQueryImpl commentQuery); + } diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/data/impl/MybatisCommentDataManager.java b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/data/impl/MybatisCommentDataManager.java index 95b05580a81..73a85b31033 100644 --- a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/data/impl/MybatisCommentDataManager.java +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/data/impl/MybatisCommentDataManager.java @@ -17,6 +17,7 @@ import java.util.Map; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.CommentQueryImpl; import org.flowable.engine.impl.persistence.entity.CommentEntity; import org.flowable.engine.impl.persistence.entity.CommentEntityImpl; import org.flowable.engine.impl.persistence.entity.data.AbstractProcessDataManager; @@ -111,4 +112,14 @@ public Event findEvent(String commentId) { return findById(commentId); } + @Override + public List findCommentsByQueryCriteria(CommentQueryImpl commentQuery) { + final String query = "selectCommentByQueryCriteria"; + return getDbSqlSession().selectList(query, commentQuery); + } + + @Override + public long findCommentCountByQueryCriteria(CommentQueryImpl commentQuery) { + return (Long) getDbSqlSession().selectOne("selectCommentCountByQueryCriteria", commentQuery); + } } diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/task/CommentQuery.java b/modules/flowable-engine/src/main/java/org/flowable/engine/task/CommentQuery.java new file mode 100644 index 00000000000..831ddd815a8 --- /dev/null +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/task/CommentQuery.java @@ -0,0 +1,103 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.engine.task; + +import java.util.Collection; +import java.util.Date; + +import org.flowable.common.engine.api.FlowableIllegalArgumentException; +import org.flowable.common.engine.api.query.Query; + + +/** + * @author David Lamas + */ +public interface CommentQuery extends Query { + /** + * Only select the comment with the given id. + */ + CommentQuery commentId(String commentId); + + /** + * Only select comments which have the given task id. + */ + CommentQuery taskId(String taskId); + + /** + * Only select comments which have the given process instance id. + */ + CommentQuery processInstanceId(String processInstanceId); + + /** + * Only select comments that have the given type. + */ + CommentQuery type(String type); + + /** + * Only select comments created by the given user. + * + * @throws FlowableIllegalArgumentException When query is executed and {@link #createdByOneOf(Collection)} has been + * executed on the query instance. + */ + CommentQuery createdBy(String userId); + + /** + * Only select comments created by one of the given users. + * + * @throws FlowableIllegalArgumentException When query is executed and {@link #createdBy(String)} has been executed + * on the query instance. + */ + CommentQuery createdByOneOf(Collection userIds); + + /** + * Only select comments created before the given time. + */ + CommentQuery createdBefore(Date beforeTime); + + /** + * Only select comments created after the given time. + */ + CommentQuery createdAfter(Date afterTime); + + /** + * Only select comments created at the given time + */ + CommentQuery createdOn(Date createTime); + + // ordering //////////////////////////////////////////////////////////// + + /** + * Order by the time when the comment was created (needs to be followed by {@link #asc()} or {@link #desc()}). + */ + CommentQuery orderByCreateTime(); + + /** + * Order by the user that created the comment (needs to be followed by {@link #asc()} or {@link #desc()}). + */ + CommentQuery orderByUser(); + + /** + * Order by type (needs to be followed by {@link #asc()} or {@link #desc()}). + */ + CommentQuery orderByType(); + + /** + * Order by task id (needs to be followed by {@link #asc()} or {@link #desc()}). + */ + CommentQuery orderByTaskId(); + + /** + * Order by process instance id (needs to be followed by {@link #asc()} or {@link #desc()}). + */ + CommentQuery orderByProcessInstanceId(); +} diff --git a/modules/flowable-engine/src/main/resources/org/flowable/db/mapping/entity/Comment.xml b/modules/flowable-engine/src/main/resources/org/flowable/db/mapping/entity/Comment.xml index 9f7e603c704..7d4dd439e2f 100644 --- a/modules/flowable-engine/src/main/resources/org/flowable/db/mapping/entity/Comment.xml +++ b/modules/flowable-engine/src/main/resources/org/flowable/db/mapping/entity/Comment.xml @@ -170,4 +170,54 @@ order by TIME_ desc + + + + + + from ${prefix}ACT_HI_COMMENT RES + + + RES.ID_ = #{commentId} + + + RES.TASK_ID_ = #{taskId} + + + and RES.PROC_INST_ID_ = #{processInstanceId} + + + and RES.TYPE_ = #{type} + + + and RES.USER_ID_ = #{createdBy} + + + and RES.USER_ID_ IN + + #{userId} + + + + and RES.TIME_ < #{createdBefore} + + + and RES.TIME_ > #{createdAfter} + + + and RES.TIME_ = #{createdOn} + + + + diff --git a/modules/flowable-engine/src/test/java/org/flowable/engine/test/api/comment/CommentQueryTest.java b/modules/flowable-engine/src/test/java/org/flowable/engine/test/api/comment/CommentQueryTest.java new file mode 100644 index 00000000000..cb16e68b954 --- /dev/null +++ b/modules/flowable-engine/src/test/java/org/flowable/engine/test/api/comment/CommentQueryTest.java @@ -0,0 +1,288 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.engine.test.api.comment; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import org.apache.commons.lang3.tuple.Pair; +import org.flowable.common.engine.api.FlowableException; +import org.flowable.common.engine.impl.identity.Authentication; +import org.flowable.engine.task.CommentQuery; +import org.flowable.engine.impl.test.PluggableFlowableTestCase; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.engine.task.Comment; +import org.flowable.task.api.Task; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * @author David Lamas + */ +public class CommentQueryTest extends PluggableFlowableTestCase { + private List taskIds; + private List processIds; + private List commentIds; + private Deployment deployment; + + @BeforeEach + protected void setUp() throws ParseException { + deployment = repositoryService.createDeployment().addClasspathResource("org/flowable/engine/test/api/runtime/oneTaskProcess.bpmn20.xml").deploy(); + + Authentication.setAuthenticatedUserId("userId"); + SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss"); + processEngineConfiguration.getClock().setCurrentTime(sdf.parse("01/01/2021 00:00:00")); + + Pair, List> tasks = generateCommentsForTasks(); + Pair, List> processes = generateCommentsForProcesses(); + + taskIds = tasks.getLeft(); + commentIds = tasks.getRight(); + + processIds = processes.getLeft(); + commentIds.addAll(processes.getRight()); + } + + @AfterEach + public void tearDown() { + Authentication.setAuthenticatedUserId(null); + taskService.deleteTasks(taskIds, true); + deleteDeployment(deployment.getId()); + } + + @Test + public void testQueryNoCriteria() { + CommentQuery query = taskService.createCommentQuery(); + assertThat(query.count()).isEqualTo(5); + assertThat(query.list()).hasSize(5); + assertThatThrownBy(query::singleResult).isExactlyInstanceOf(FlowableException.class); + } + + @Test + public void testQueryByCommentId() { + CommentQuery query = taskService.createCommentQuery().commentId(commentIds.get(0)); + assertThat(query.singleResult()).isNotNull(); + assertThat(query.list()).hasSize(1); + assertThat(query.count()).isEqualTo(1); + } + + @Test + public void testQueryByInvalidCommentId() { + CommentQuery query = taskService.createCommentQuery().commentId("invalid comment"); + assertThat(query.singleResult()).isNull(); + assertThat(query.list()).isEmpty(); + assertThat(query.count()).isZero(); + } + + @Test + public void testQueryByTaskId() { + CommentQuery query = taskService.createCommentQuery().taskId(taskIds.get(0)); + assertThat(query.singleResult()).isNotNull(); + assertThat(query.list()).hasSize(1); + assertThat(query.count()).isEqualTo(1); + } + + @Test + public void testQueryByInvalidTaskId() { + CommentQuery query = taskService.createCommentQuery().taskId("invalid task"); + assertThat(query.singleResult()).isNull(); + assertThat(query.list()).isEmpty(); + assertThat(query.count()).isZero(); + } + + @Test + public void testQueryByProcessInstanceId() { + CommentQuery query = taskService.createCommentQuery().processInstanceId(processIds.get(0)); + assertThat(query.singleResult()).isNotNull(); + assertThat(query.list()).hasSize(1); + assertThat(query.count()).isEqualTo(1); + } + + @Test + public void testQueryByInvalidProcessInstanceId() { + CommentQuery query = taskService.createCommentQuery().processInstanceId("invalid process"); + assertThat(query.singleResult()).isNull(); + assertThat(query.list()).isEmpty(); + assertThat(query.count()).isZero(); + } + + @Test + public void testQueryByType() { + // Create a comment with a custom type + taskService.addComment(taskIds.get(0), null, "customtype", "message"); + + CommentQuery query = taskService.createCommentQuery().type("customtype"); + assertThat(query.singleResult()).isNotNull(); + assertThat(query.list()).hasSize(1); + assertThat(query.count()).isEqualTo(1); + } + + @Test + public void testQueryByInvalidType() { + CommentQuery query = taskService.createCommentQuery().type("invalid type"); + assertThat(query.singleResult()).isNull(); + assertThat(query.list()).isEmpty(); + assertThat(query.count()).isZero(); + } + + @Test + public void testQueryByCreatedBy() { + CommentQuery query = taskService.createCommentQuery().createdBy("userId"); + assertThat(query.list()).hasSize(5); + assertThat(query.count()).isEqualTo(5); + + Authentication.setAuthenticatedUserId("kermit"); + taskService.addComment(taskIds.get(0), null, "comment by kermit"); + query = taskService.createCommentQuery().createdBy("kermit"); + assertThat(query.list()).hasSize(1); + assertThat(query.count()).isEqualTo(1); + } + + @Test + public void testQueryByInvalidCreatedBy() { + CommentQuery query = taskService.createCommentQuery().createdBy("invalid user"); + assertThat(query.singleResult()).isNull(); + assertThat(query.list()).isEmpty(); + assertThat(query.count()).isZero(); + } + + @Test + public void testQueryByCreatedByOneOf() { + CommentQuery query = taskService.createCommentQuery().createdByOneOf(Collections.singletonList("userId")); + assertThat(query.list()).hasSize(5); + assertThat(query.count()).isEqualTo(5); + + Authentication.setAuthenticatedUserId("kermit"); + taskService.addComment(taskIds.get(0), null, "comment by kermit"); + + query = taskService.createCommentQuery().createdByOneOf(Arrays.asList("userId", "kermit")); + assertThat(query.list()).hasSize(6); + assertThat(query.count()).isEqualTo(6); + + query = taskService.createCommentQuery().createdByOneOf(Collections.singletonList("invalid user")); + assertThat(query.list()).isEmpty(); + assertThat(query.count()).isZero(); + } + + @Test + public void testQueryByCreatedBefore() throws ParseException { + SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss"); + + // Should give all comments (5) + Date before = sdf.parse("02/01/2021 00:00:00"); + + CommentQuery query = taskService.createCommentQuery().createdBefore(before); + assertThat(query.list()).hasSize(5); + assertThat(query.count()).isEqualTo(5); + + // Should give 0 comments + before = sdf.parse("01/01/2021 00:00:00"); + query = taskService.createCommentQuery().createdBefore(before); + assertThat(query.list()).isEmpty(); + assertThat(query.count()).isZero(); + } + + @Test + public void testQueryByCreatedAfter() throws ParseException { + SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss"); + + // Should give all comments (5) + Date after = sdf.parse("31/12/2020 00:00:00"); + + CommentQuery query = taskService.createCommentQuery().createdAfter(after); + assertThat(query.list()).hasSize(5); + assertThat(query.count()).isEqualTo(5); + + // Should give 0 comments + after = sdf.parse("02/01/2021 00:00:00"); + query = taskService.createCommentQuery().createdAfter(after); + assertThat(query.list()).isEmpty(); + assertThat(query.count()).isZero(); + } + + @Test + public void testQueryByCreatedOn() throws ParseException { + SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss"); + + // Should give all comments (5) + Date createdOn = sdf.parse("01/01/2021 00:00:00"); + + CommentQuery query = taskService.createCommentQuery().createdOn(createdOn); + assertThat(query.list()).hasSize(5); + assertThat(query.count()).isEqualTo(5); + + // Should give 0 comments + createdOn = sdf.parse("02/01/2021 00:00:00"); + query = taskService.createCommentQuery().createdOn(createdOn); + assertThat(query.list()).isEmpty(); + assertThat(query.count()).isZero(); + } + + @Test + public void testQuerySorting() { + assertThat(taskService.createCommentQuery().orderByTaskId().asc().list()).hasSize(5); + assertThat(taskService.createCommentQuery().orderByProcessInstanceId().asc().list()).hasSize(5); + assertThat(taskService.createCommentQuery().orderByType().asc().list()).hasSize(5); + assertThat(taskService.createCommentQuery().orderByCreateTime().asc().list()).hasSize(5); + assertThat(taskService.createCommentQuery().orderByUser().asc().list()).hasSize(5); + + assertThat(taskService.createCommentQuery().orderByTaskId().desc().list()).hasSize(5); + assertThat(taskService.createCommentQuery().orderByProcessInstanceId().desc().list()).hasSize(5); + assertThat(taskService.createCommentQuery().orderByType().desc().list()).hasSize(5); + assertThat(taskService.createCommentQuery().orderByCreateTime().desc().list()).hasSize(5); + assertThat(taskService.createCommentQuery().orderByUser().desc().list()).hasSize(5); + + assertThat(taskService.createCommentQuery().orderByTaskId().type("comment").asc().list()).hasSize(5); + assertThat(taskService.createCommentQuery().orderByTaskId().type("comment").desc().list()).hasSize(5); + } + + private Pair, List> generateCommentsForTasks() { + List taskIds = new ArrayList<>(); + List commentIds = new ArrayList<>(); + // Create 2 tasks and 1 comment for each task + for (int i = 0; i < 2; i++) { + Task task = taskService.newTask(); + task.setName("New task"); + taskService.saveTask(task); + + Comment comment = taskService.addComment(task.getId(), null, "Comment " + i + " for task"); + taskIds.add(task.getId()); + commentIds.add(comment.getId()); + } + return Pair.of(taskIds, commentIds); + } + + private Pair, List> generateCommentsForProcesses() { + List processInstances = new ArrayList<>(); + List commentIds = new ArrayList<>(); + // Create 3 processes and 1 comment for each process + for (int i = 0; i < 3; i++) { + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("oneTaskProcess"); + + Comment comment = taskService.addComment(null, processInstance.getId(), "Comment " + i + " for process"); + processInstances.add(processInstance.getId()); + commentIds.add(comment.getId()); + } + return Pair.of(processInstances, commentIds); + } +}