From e4d2c19674f16fc270c3342355c626dfe475b084 Mon Sep 17 00:00:00 2001 From: Philipp Ossler Date: Thu, 2 Mar 2023 06:37:17 +0100 Subject: [PATCH] feat: Fetch decision evaluations by process instance Add a connection in the GraphQL API from process instance and element instance to decision evaluations. --- .../DecisionEvaluationRepository.kt | 4 + .../resolvers/type/ElementInstanceResolver.kt | 59 ++++++---- .../resolvers/type/ProcessInstanceResolver.kt | 109 ++++++++++-------- .../graphql/ElementInstance.graphqls | 3 + .../graphql/ProcessInstance.graphqls | 2 + 5 files changed, 106 insertions(+), 71 deletions(-) diff --git a/data/src/main/kotlin/io/zeebe/zeeqs/data/repository/DecisionEvaluationRepository.kt b/data/src/main/kotlin/io/zeebe/zeeqs/data/repository/DecisionEvaluationRepository.kt index 415a3c6e..1af2e4b0 100644 --- a/data/src/main/kotlin/io/zeebe/zeeqs/data/repository/DecisionEvaluationRepository.kt +++ b/data/src/main/kotlin/io/zeebe/zeeqs/data/repository/DecisionEvaluationRepository.kt @@ -13,5 +13,9 @@ interface DecisionEvaluationRepository : PagingAndSortingRepository + fun countByProcessInstanceKey(processInstanceKey: Long): Long + fun findAllByElementInstanceKey(elementInstanceKey: Long): List + + fun countByElementInstanceKey(elementInstanceKey: Long): Long } \ No newline at end of file diff --git a/graphql-api/src/main/kotlin/io/zeebe/zeeqs/graphql/resolvers/type/ElementInstanceResolver.kt b/graphql-api/src/main/kotlin/io/zeebe/zeeqs/graphql/resolvers/type/ElementInstanceResolver.kt index f4fd2b75..c01a131b 100644 --- a/graphql-api/src/main/kotlin/io/zeebe/zeeqs/graphql/resolvers/type/ElementInstanceResolver.kt +++ b/graphql-api/src/main/kotlin/io/zeebe/zeeqs/graphql/resolvers/type/ElementInstanceResolver.kt @@ -4,6 +4,7 @@ import io.zeebe.zeeqs.data.entity.* import io.zeebe.zeeqs.data.repository.* import io.zeebe.zeeqs.data.service.ProcessService import io.zeebe.zeeqs.data.service.VariableService +import io.zeebe.zeeqs.graphql.resolvers.connection.DecisionEvaluationConnection import org.springframework.data.repository.findByIdOrNull import org.springframework.graphql.data.method.annotation.Argument import org.springframework.graphql.data.method.annotation.SchemaMapping @@ -11,28 +12,29 @@ import org.springframework.stereotype.Controller @Controller class ElementInstanceResolver( - val elementInstanceRepository: ElementInstanceRepository, - val processInstanceRepository: ProcessInstanceRepository, - val incidentRepository: IncidentRepository, - val elementInstanceStateTransitionRepository: ElementInstanceStateTransitionRepository, - val timerRepository: TimerRepository, - val processService: ProcessService, - val messageSubscriptionRepository: MessageSubscriptionRepository, - val variableService: VariableService + val elementInstanceRepository: ElementInstanceRepository, + val processInstanceRepository: ProcessInstanceRepository, + val incidentRepository: IncidentRepository, + val elementInstanceStateTransitionRepository: ElementInstanceStateTransitionRepository, + val timerRepository: TimerRepository, + val processService: ProcessService, + val messageSubscriptionRepository: MessageSubscriptionRepository, + val variableService: VariableService, + private val decisionEvaluationRepository: DecisionEvaluationRepository ) { @SchemaMapping(typeName = "ElementInstance", field = "startTime") fun startTime( - elementInstance: ElementInstance, - @Argument zoneId: String + elementInstance: ElementInstance, + @Argument zoneId: String ): String? { return elementInstance.startTime?.let { ResolverExtension.timestampToString(it, zoneId) } } @SchemaMapping(typeName = "ElementInstance", field = "endTime") fun endTime( - elementInstance: ElementInstance, - @Argument zoneId: String + elementInstance: ElementInstance, + @Argument zoneId: String ): String? { return elementInstance.endTime?.let { ResolverExtension.timestampToString(it, zoneId) } } @@ -60,9 +62,9 @@ class ElementInstanceResolver( @SchemaMapping(typeName = "ElementInstance", field = "elementName") fun elementName(elementInstance: ElementInstance): String? { return processService - .getBpmnElementInfo(elementInstance.processDefinitionKey) - ?.get(elementInstance.elementId) - ?.elementName + .getBpmnElementInfo(elementInstance.processDefinitionKey) + ?.get(elementInstance.elementId) + ?.elementName } @SchemaMapping(typeName = "ElementInstance", field = "timers") @@ -78,21 +80,30 @@ class ElementInstanceResolver( @SchemaMapping(typeName = "ElementInstance", field = "element") fun element(elementInstance: ElementInstance): BpmnElement { return BpmnElement( - processDefinitionKey = elementInstance.processDefinitionKey, - elementId = elementInstance.elementId, - elementType = elementInstance.bpmnElementType + processDefinitionKey = elementInstance.processDefinitionKey, + elementId = elementInstance.elementId, + elementType = elementInstance.bpmnElementType ) } @SchemaMapping(typeName = "ElementInstance", field = "variables") fun variables( - elementInstance: ElementInstance, - @Argument localOnly: Boolean, - @Argument shadowing: Boolean): List { + elementInstance: ElementInstance, + @Argument localOnly: Boolean, + @Argument shadowing: Boolean + ): List { return variableService.getVariables( - elementInstanceKey = elementInstance.key, - localOnly = localOnly, - shadowing = shadowing + elementInstanceKey = elementInstance.key, + localOnly = localOnly, + shadowing = shadowing + ) + } + + @SchemaMapping(typeName = "ElementInstance", field = "decisionEvaluations") + fun decisionEvaluations(elementInstance: ElementInstance): DecisionEvaluationConnection { + return DecisionEvaluationConnection( + getItems = { decisionEvaluationRepository.findAllByElementInstanceKey(elementInstanceKey = elementInstance.key) }, + getCount = { decisionEvaluationRepository.countByElementInstanceKey(elementInstanceKey = elementInstance.key) } ) } diff --git a/graphql-api/src/main/kotlin/io/zeebe/zeeqs/graphql/resolvers/type/ProcessInstanceResolver.kt b/graphql-api/src/main/kotlin/io/zeebe/zeeqs/graphql/resolvers/type/ProcessInstanceResolver.kt index f20d03b9..8b5d260e 100644 --- a/graphql-api/src/main/kotlin/io/zeebe/zeeqs/graphql/resolvers/type/ProcessInstanceResolver.kt +++ b/graphql-api/src/main/kotlin/io/zeebe/zeeqs/graphql/resolvers/type/ProcessInstanceResolver.kt @@ -2,6 +2,7 @@ package io.zeebe.zeeqs.graphql.resolvers.type import io.zeebe.zeeqs.data.entity.* import io.zeebe.zeeqs.data.repository.* +import io.zeebe.zeeqs.graphql.resolvers.connection.DecisionEvaluationConnection import io.zeebe.zeeqs.graphql.resolvers.connection.UserTaskConnection import io.zeebe.zeeqs.graphql.resolvers.type.ResolverExtension.timestampToString import org.springframework.data.domain.PageRequest @@ -12,38 +13,39 @@ import org.springframework.stereotype.Controller @Controller class ProcessInstanceResolver( - val processInstanceRepository: ProcessInstanceRepository, - val variableRepository: VariableRepository, - val processRepository: ProcessRepository, - val jobRepository: JobRepository, - val userTaskRepository: UserTaskRepository, - val incidentRepository: IncidentRepository, - val elementInstanceRepository: ElementInstanceRepository, - val timerRepository: TimerRepository, - val messageSubscriptionRepository: MessageSubscriptionRepository, - val errorRepository: ErrorRepository + val processInstanceRepository: ProcessInstanceRepository, + val variableRepository: VariableRepository, + val processRepository: ProcessRepository, + val jobRepository: JobRepository, + val userTaskRepository: UserTaskRepository, + val incidentRepository: IncidentRepository, + val elementInstanceRepository: ElementInstanceRepository, + val timerRepository: TimerRepository, + val messageSubscriptionRepository: MessageSubscriptionRepository, + val errorRepository: ErrorRepository, + private val decisionEvaluationRepository: DecisionEvaluationRepository ) { @SchemaMapping(typeName = "ProcessInstance", field = "startTime") fun startTime( - processInstance: ProcessInstance, - @Argument zoneId: String + processInstance: ProcessInstance, + @Argument zoneId: String ): String? { return processInstance.startTime?.let { timestampToString(it, zoneId) } } @SchemaMapping(typeName = "ProcessInstance", field = "endTime") fun endTime( - processInstance: ProcessInstance, - @Argument zoneId: String + processInstance: ProcessInstance, + @Argument zoneId: String ): String? { return processInstance.endTime?.let { timestampToString(it, zoneId) } } @SchemaMapping(typeName = "ProcessInstance", field = "variables") fun variables( - processInstance: ProcessInstance, - @Argument globalOnly: Boolean + processInstance: ProcessInstance, + @Argument globalOnly: Boolean ): List { return if (globalOnly) { variableRepository.findByScopeKey(scopeKey = processInstance.key) @@ -54,40 +56,42 @@ class ProcessInstanceResolver( @SchemaMapping(typeName = "ProcessInstance", field = "jobs") fun jobs( - processInstance: ProcessInstance, - @Argument stateIn: List, - @Argument jobTypeIn: List + processInstance: ProcessInstance, + @Argument stateIn: List, + @Argument jobTypeIn: List ): List { return if (jobTypeIn.isEmpty()) { jobRepository.findByProcessInstanceKeyAndStateIn(processInstance.key, stateIn) } else { jobRepository.findByProcessInstanceKeyAndStateInAndJobTypeIn( - processInstanceKey = processInstance.key, - stateIn = stateIn, - jobTypeIn = jobTypeIn + processInstanceKey = processInstance.key, + stateIn = stateIn, + jobTypeIn = jobTypeIn ) } } @SchemaMapping(typeName = "ProcessInstance", field = "userTasks") fun userTasks( - processInstance: ProcessInstance, - @Argument perPage: Int, - @Argument page: Int, - @Argument stateIn: List): UserTaskConnection { + processInstance: ProcessInstance, + @Argument perPage: Int, + @Argument page: Int, + @Argument stateIn: List + ): UserTaskConnection { return UserTaskConnection( - getItems = { - userTaskRepository.findByProcessInstanceKeyAndStateIn( - processInstanceKey = processInstance.key, - stateIn = stateIn, - pageable = PageRequest.of(page, perPage)) - }, - getCount = { - userTaskRepository.countByProcessInstanceKeyAndStateIn( - processInstanceKey = processInstance.key, - stateIn = stateIn - ) - } + getItems = { + userTaskRepository.findByProcessInstanceKeyAndStateIn( + processInstanceKey = processInstance.key, + stateIn = stateIn, + pageable = PageRequest.of(page, perPage) + ) + }, + getCount = { + userTaskRepository.countByProcessInstanceKeyAndStateIn( + processInstanceKey = processInstance.key, + stateIn = stateIn + ) + } ) } @@ -98,18 +102,22 @@ class ProcessInstanceResolver( @SchemaMapping(typeName = "ProcessInstance", field = "incidents") fun incidents( - processInstance: ProcessInstance, - @Argument stateIn: List + processInstance: ProcessInstance, + @Argument stateIn: List ): List { return incidentRepository.findByProcessInstanceKeyAndStateIn( - processInstanceKey = processInstance.key, - stateIn = stateIn + processInstanceKey = processInstance.key, + stateIn = stateIn ) } @SchemaMapping(typeName = "ProcessInstance", field = "parentElementInstance") fun parentElementInstance(processInstance: ProcessInstance): ElementInstance? { - return processInstance.parentElementInstanceKey?.let { elementInstanceRepository.findByIdOrNull(it) } + return processInstance.parentElementInstanceKey?.let { + elementInstanceRepository.findByIdOrNull( + it + ) + } } @SchemaMapping(typeName = "ProcessInstance", field = "childProcessInstances") @@ -119,12 +127,12 @@ class ProcessInstanceResolver( @SchemaMapping(typeName = "ProcessInstance", field = "elementInstances") fun elementInstances( - processInstance: ProcessInstance, - @Argument stateIn: List + processInstance: ProcessInstance, + @Argument stateIn: List ): List { return elementInstanceRepository.findByProcessInstanceKeyAndStateIn( - processInstanceKey = processInstance.key, - stateIn = stateIn + processInstanceKey = processInstance.key, + stateIn = stateIn ) } @@ -143,4 +151,11 @@ class ProcessInstanceResolver( return errorRepository.findByProcessInstanceKey(processInstance.key) } + @SchemaMapping(typeName = "ProcessInstance", field = "decisionEvaluations") + fun decisionEvaluations(processInstance: ProcessInstance): DecisionEvaluationConnection { + return DecisionEvaluationConnection( + getItems = { decisionEvaluationRepository.findAllByProcessInstanceKey(processInstanceKey = processInstance.key) }, + getCount = { decisionEvaluationRepository.countByProcessInstanceKey(processInstanceKey = processInstance.key) } + ) + } } \ No newline at end of file diff --git a/graphql-api/src/main/resources/graphql/ElementInstance.graphqls b/graphql-api/src/main/resources/graphql/ElementInstance.graphqls index 3c579d05..7afb86eb 100644 --- a/graphql-api/src/main/resources/graphql/ElementInstance.graphqls +++ b/graphql-api/src/main/resources/graphql/ElementInstance.graphqls @@ -38,6 +38,9 @@ type ElementInstance { # If false, it returns all variables, including variables with the same name. shadowing: Boolean = true ): [Variable!]! + + # The evaluated decisions that are called by this element instance if the element is a business rule task. + decisionEvaluations: DecisionEvaluationConnection } type ElementInstanceStateTransition { diff --git a/graphql-api/src/main/resources/graphql/ProcessInstance.graphqls b/graphql-api/src/main/resources/graphql/ProcessInstance.graphqls index 6e8b7c85..f0520466 100644 --- a/graphql-api/src/main/resources/graphql/ProcessInstance.graphqls +++ b/graphql-api/src/main/resources/graphql/ProcessInstance.graphqls @@ -44,6 +44,8 @@ type ProcessInstance { timers: [Timer!] # the opened message subscriptions related to the process instance (e.g. message catch events) messageSubscriptions: [MessageSubscription!] + # The evaluated decisions that are called by a business rule task of this process instance. + decisionEvaluations: DecisionEvaluationConnection # the occurred error related to the process instance error: Error }