diff --git a/data/src/main/kotlin/io/zeebe/zeeqs/data/entity/VariableFilter.kt b/data/src/main/kotlin/io/zeebe/zeeqs/data/entity/VariableFilter.kt new file mode 100644 index 0000000..eaa4923 --- /dev/null +++ b/data/src/main/kotlin/io/zeebe/zeeqs/data/entity/VariableFilter.kt @@ -0,0 +1,12 @@ +package io.zeebe.zeeqs.data.entity + +enum class EqualityOperation { + EQUALS, + CONTAINS +} + +class VariableFilter ( + val name: String, + val value: String, + val equalityOperation: EqualityOperation = EqualityOperation.EQUALS +) \ No newline at end of file diff --git a/data/src/main/kotlin/io/zeebe/zeeqs/data/repository/VariableRepository.kt b/data/src/main/kotlin/io/zeebe/zeeqs/data/repository/VariableRepository.kt index 82c8700..5410721 100644 --- a/data/src/main/kotlin/io/zeebe/zeeqs/data/repository/VariableRepository.kt +++ b/data/src/main/kotlin/io/zeebe/zeeqs/data/repository/VariableRepository.kt @@ -17,4 +17,8 @@ interface VariableRepository : PagingAndSortingRepository { @Transactional(readOnly = true) fun findByProcessInstanceKeyInAndName(processInstanceKey: List, name: String): List + + @Transactional(readOnly = true) + fun findByProcessInstanceKeyInAndNameIn(processInstanceKey: List, name: List): List + } \ No newline at end of file diff --git a/data/src/main/kotlin/io/zeebe/zeeqs/data/service/ProcessInstanceService.kt b/data/src/main/kotlin/io/zeebe/zeeqs/data/service/ProcessInstanceService.kt index dc860be..e9d0468 100644 --- a/data/src/main/kotlin/io/zeebe/zeeqs/data/service/ProcessInstanceService.kt +++ b/data/src/main/kotlin/io/zeebe/zeeqs/data/service/ProcessInstanceService.kt @@ -1,8 +1,6 @@ package io.zeebe.zeeqs.data.service -import io.zeebe.zeeqs.data.entity.ProcessInstance -import io.zeebe.zeeqs.data.entity.ProcessInstanceState -import io.zeebe.zeeqs.data.entity.Variable +import io.zeebe.zeeqs.data.entity.* import io.zeebe.zeeqs.data.repository.ProcessInstanceKeyOnly import io.zeebe.zeeqs.data.repository.ProcessInstanceRepository import io.zeebe.zeeqs.data.repository.VariableRepository @@ -14,26 +12,35 @@ class ProcessInstanceService( private val processInstancesRepository: ProcessInstanceRepository, private val variableRepository: VariableRepository) { - private fun getVariables(stateIn: List, variableName: String, variableValue: String): List { + private fun getVariables(stateIn: List, variables: List): List { val processInstances = processInstancesRepository.findByStateIn(stateIn).toList(); - return getVariablesByProcessInstanceKeys(processInstances, variableName, variableValue); + return getVariablesByProcessInstanceKeys(processInstances, variables); } - private fun getVariables(stateIn: List, processDefinitionKey: Long, variableName: String, variableValue: String): List { + private fun getVariables(stateIn: List, processDefinitionKey: Long, variables: List): List { val processInstances = processInstancesRepository.findByProcessDefinitionKeyAndStateIn(processDefinitionKey, stateIn).toList(); - return getVariablesByProcessInstanceKeys(processInstances, variableName, variableValue); + return getVariablesByProcessInstanceKeys(processInstances, variables); } - private fun getVariablesByProcessInstanceKeys(processInstances: List, variableName: String, variableValue: String): List { - val variables = variableRepository.findByProcessInstanceKeyInAndName(processInstances.map { it.getKey() }, variableName); - val filteredVariables = variables.filter { it.value == variableValue }; + private fun getVariablesByProcessInstanceKeys(processInstances: List, variables: List): List { + val variableNames = variables.map { it.name } + val processInstancesKeys = processInstances.map { it.getKey() } + val variablesList = variableRepository.findByProcessInstanceKeyInAndNameIn(processInstancesKeys, variableNames); + val filteredVariables = variablesList.filter { variable -> + variables.any { filter -> + when (filter.equalityOperation) { + EqualityOperation.EQUALS -> variable.name == filter.name && variable.value == filter.value + EqualityOperation.CONTAINS -> variable.name == filter.name && variable.value.contains(filter.value) + } + } + } return filteredVariables; } - fun getProcessInstances(perPage: Int, page: Int, stateIn: List, variableName: String?, variableValue: String?): List { - if(variableName != null && variableValue != null) { - val filteredVariables = getVariables(stateIn, variableName, variableValue); + fun getProcessInstances(perPage: Int, page: Int, stateIn: List, variables: List?): List { + if(!variables.isNullOrEmpty()) { + val filteredVariables = getVariables(stateIn, variables); val filteredProcessInstances = processInstancesRepository.findByStateInAndKeyIn(stateIn, filteredVariables.map { it.processInstanceKey }, PageRequest.of(page, perPage)).toList(); return filteredProcessInstances; } @@ -42,9 +49,9 @@ class ProcessInstanceService( } } - fun countProcessInstances(stateIn: List, variableName: String?, variableValue: String?): Long { - if(variableName != null && variableValue != null) { - val filteredVariables = getVariables(stateIn, variableName, variableValue); + fun countProcessInstances(stateIn: List, variables: List?): Long { + if(!variables.isNullOrEmpty()) { + val filteredVariables = getVariables(stateIn, variables); return filteredVariables.count().toLong(); } @@ -54,9 +61,9 @@ class ProcessInstanceService( } - fun getProcessInstances(perPage: Int, page: Int, stateIn: List, processDefinitionKey: Long, variableName: String?, variableValue: String?): List { - if(variableName != null && variableValue != null) { - val filteredVariables = getVariables(stateIn, processDefinitionKey, variableName, variableValue); + fun getProcessInstances(perPage: Int, page: Int, stateIn: List, processDefinitionKey: Long, variables: List?): List { + if(!variables.isNullOrEmpty()) { + val filteredVariables = getVariables(stateIn, processDefinitionKey, variables); val filteredProcessInstances = processInstancesRepository.findByStateInAndKeyIn(stateIn, filteredVariables.map { it.processInstanceKey }, PageRequest.of(page, perPage)).toList(); return filteredProcessInstances; } @@ -65,9 +72,9 @@ class ProcessInstanceService( } } - fun countProcessInstances(stateIn: List, processDefinitionKey: Long, variableName: String?, variableValue: String?): Long { - if(variableName != null && variableValue != null) { - val filteredVariables = getVariables(stateIn, processDefinitionKey, variableName, variableValue); + fun countProcessInstances(stateIn: List, processDefinitionKey: Long, variables: List?): Long { + if(!variables.isNullOrEmpty()) { + val filteredVariables = getVariables(stateIn, processDefinitionKey, variables); return filteredVariables.count().toLong(); } diff --git a/data/src/main/kotlin/io/zeebe/zeeqs/data/service/ProcessService.kt b/data/src/main/kotlin/io/zeebe/zeeqs/data/service/ProcessService.kt index fa698a1..192a822 100644 --- a/data/src/main/kotlin/io/zeebe/zeeqs/data/service/ProcessService.kt +++ b/data/src/main/kotlin/io/zeebe/zeeqs/data/service/ProcessService.kt @@ -168,11 +168,15 @@ class ProcessService(val processRepository: ProcessRepository) { } private fun getExtensionProperties(element: BaseElement): Collection? { - return element.extensionElements?.elementsQuery + return element.extensionElements?.elementsQuery ?.filterByType(ZeebeProperties::class.java) - ?.singleResult() - ?.properties - ?.map { BpmnElementExtensionProperties(name = it.name, value = it.value) } + ?.findSingleResult() + ?.map { properties -> + properties.properties?.map { property -> + BpmnElementExtensionProperties(name = property.name, value = property.value) + } + } + ?.orElse(null) } diff --git a/data/src/test/kotlin/io/zeebe/zeeqs/ProcessServiceTest.kt b/data/src/test/kotlin/io/zeebe/zeeqs/ProcessServiceTest.kt index 8b5445c..2ca531f 100644 --- a/data/src/test/kotlin/io/zeebe/zeeqs/ProcessServiceTest.kt +++ b/data/src/test/kotlin/io/zeebe/zeeqs/ProcessServiceTest.kt @@ -52,12 +52,12 @@ class ProcessServiceTest( // then assertThat(info) .isNotNull() - .contains(entry("s", BpmnElementInfo("s", "start", BpmnElementType.START_EVENT, BpmnElementMetadata(), listOf(BpmnElementExtensionProperties()), ""))) - .contains(entry("t", BpmnElementInfo("t", "task", BpmnElementType.SERVICE_TASK, BpmnElementMetadata(jobType = "test"), listOf(BpmnElementExtensionProperties()), ""))) + .contains(entry("s", BpmnElementInfo("s", "start", BpmnElementType.START_EVENT, BpmnElementMetadata(), null, ""))) + .contains(entry("t", BpmnElementInfo("t", "task", BpmnElementType.SERVICE_TASK, BpmnElementMetadata(jobType = "test"), null, ""))) .contains(entry("u", BpmnElementInfo("u", "userTask", BpmnElementType.USER_TASK, BpmnElementMetadata( - userTaskAssignmentDefinition = UserTaskAssignmentDefinition(assignee = "user1", candidateGroups = "group1")), listOf(BpmnElementExtensionProperties()), "")) + userTaskAssignmentDefinition = UserTaskAssignmentDefinition(assignee = "user1", candidateGroups = "group1")), null, "")) ) - .contains(entry("e", BpmnElementInfo("e", null, BpmnElementType.END_EVENT, BpmnElementMetadata(), listOf(BpmnElementExtensionProperties()), ""))) + .contains(entry("e", BpmnElementInfo("e", null, BpmnElementType.END_EVENT, BpmnElementMetadata(), null, ""))) } @Test @@ -91,7 +91,7 @@ class ProcessServiceTest( resource = """{"x":1}""" ) ), - listOf(BpmnElementExtensionProperties()), "" + null, "" ) ) } diff --git a/graphql-api/src/main/kotlin/io/zeebe/zeeqs/graphql/resolvers/query/ProcessInstanceQueryResolver.kt b/graphql-api/src/main/kotlin/io/zeebe/zeeqs/graphql/resolvers/query/ProcessInstanceQueryResolver.kt index 7310f05..4b7af6c 100644 --- a/graphql-api/src/main/kotlin/io/zeebe/zeeqs/graphql/resolvers/query/ProcessInstanceQueryResolver.kt +++ b/graphql-api/src/main/kotlin/io/zeebe/zeeqs/graphql/resolvers/query/ProcessInstanceQueryResolver.kt @@ -2,6 +2,7 @@ package io.zeebe.zeeqs.graphql.resolvers.query import io.zeebe.zeeqs.data.entity.ProcessInstance import io.zeebe.zeeqs.data.entity.ProcessInstanceState +import io.zeebe.zeeqs.data.entity.VariableFilter import io.zeebe.zeeqs.data.repository.ProcessInstanceRepository import io.zeebe.zeeqs.data.service.ProcessInstanceService import io.zeebe.zeeqs.graphql.resolvers.connection.ProcessInstanceConnection @@ -22,12 +23,11 @@ class ProcessInstanceQueryResolver( @Argument perPage: Int, @Argument page: Int, @Argument stateIn: List, - @Argument variableName: String?, - @Argument variableValue: String? + @Argument variables: List? ): ProcessInstanceConnection { return ProcessInstanceConnection( - getItems = { processInstanceService.getProcessInstances(perPage, page, stateIn, variableName, variableValue) }, - getCount = { processInstanceService.countProcessInstances(stateIn, variableName, variableValue) } + getItems = { processInstanceService.getProcessInstances(perPage, page, stateIn, variables) }, + getCount = { processInstanceService.countProcessInstances(stateIn, variables) } ) } diff --git a/graphql-api/src/main/kotlin/io/zeebe/zeeqs/graphql/resolvers/type/ProcessResolver.kt b/graphql-api/src/main/kotlin/io/zeebe/zeeqs/graphql/resolvers/type/ProcessResolver.kt index 98172e2..1a28c8e 100644 --- a/graphql-api/src/main/kotlin/io/zeebe/zeeqs/graphql/resolvers/type/ProcessResolver.kt +++ b/graphql-api/src/main/kotlin/io/zeebe/zeeqs/graphql/resolvers/type/ProcessResolver.kt @@ -30,8 +30,7 @@ class ProcessResolver( @Argument perPage: Int, @Argument page: Int, @Argument stateIn: List, - @Argument variableName: String?, - @Argument variableValue: String? + @Argument variables: List? ): ProcessInstanceConnection { return ProcessInstanceConnection( getItems = { @@ -40,16 +39,14 @@ class ProcessResolver( page, stateIn, process.key, - variableName, - variableValue + variables ).toList() }, getCount = { processInstanceService.countProcessInstances( stateIn, process.key, - variableName, - variableValue + variables ) } ) diff --git a/graphql-api/src/main/resources/graphql/Process.graphqls b/graphql-api/src/main/resources/graphql/Process.graphqls index d182d2b..78c65ba 100644 --- a/graphql-api/src/main/resources/graphql/Process.graphqls +++ b/graphql-api/src/main/resources/graphql/Process.graphqls @@ -14,8 +14,7 @@ type Process { perPage: Int = 10, page: Int = 0, stateIn: [ProcessInstanceState!] = [ACTIVATED, COMPLETED, TERMINATED] - variableName: String = null, - variableValue: String = null): ProcessInstanceConnection! + variables: [VariableFilter] = null): ProcessInstanceConnection! # the scheduled timers of the timer start events of the process timers: [Timer!] # the opened message subscriptions of the message start events of the process diff --git a/graphql-api/src/main/resources/graphql/ProcessInstance.graphqls b/graphql-api/src/main/resources/graphql/ProcessInstance.graphqls index ff7afe3..470fede 100644 --- a/graphql-api/src/main/resources/graphql/ProcessInstance.graphqls +++ b/graphql-api/src/main/resources/graphql/ProcessInstance.graphqls @@ -74,8 +74,7 @@ type Query { perPage: Int = 10, page: Int = 0, stateIn: [ProcessInstanceState!] = [ACTIVATED, COMPLETED, TERMINATED], - variableName: String = null, - variableValue: String = null + variables: [VariableFilter] = null ): ProcessInstanceConnection! } diff --git a/graphql-api/src/main/resources/graphql/Variable.graphqls b/graphql-api/src/main/resources/graphql/Variable.graphqls index 29e38f9..a6d467f 100644 --- a/graphql-api/src/main/resources/graphql/Variable.graphqls +++ b/graphql-api/src/main/resources/graphql/Variable.graphqls @@ -14,3 +14,15 @@ type VariableUpdate { value: String! timestamp(zoneId: String = "Z"): String! } + +input VariableFilter { + name: String!, + value: String!, + equalityOperation: EqualityOperation = EQUALS +} + +# The type of a variable value filter +enum EqualityOperation { + EQUALS, + CONTAINS +}