Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fix #2175]Adding count process intance and count user task queries #2196

Merged
merged 4 commits into from
Feb 27, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .rat-excludes
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ org.kie.kogito.app.audit.spi.GraphQLSchemaQueryProvider
application.properties
# data-index/data-index-graphql/src/main/resources/basic.schema.graphqls
basic.schema.graphqls
# data-index/data-index-graphql/src/main/resources/count.schema.graphqls
count.schema.graphqls
# data-index/data-index-graphql/src/main/resources/json.schema.graphqls
json.schema.graphqls
# data-index/data-index-service/data-index-service-common/src/main/resources/domain.schema.graphqls
domain.schema.graphqls
# /data-index/data-index-mutations/data-index-shared-output-mutation/src/main/resources/mutation.schema.graphqls
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.kie.kogito.index.service.DataIndexServiceException;
import org.kie.kogito.index.storage.DataIndexStorageService;
import org.kie.kogito.persistence.api.StorageFetcher;
import org.kie.kogito.persistence.api.StorageServiceCapability;
import org.kie.kogito.persistence.api.query.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -109,6 +110,29 @@ protected final void loadAdditionalMutations(TypeDefinitionRegistry typeRegistry
mutations.stream().map(GraphQLMutationsProvider::registry).forEach(typeRegistry::merge);
}

protected final void addCountQueries(TypeDefinitionRegistry typeRegistry) {
if (supportsCount()) {
typeRegistry.merge(loadSchemaDefinitionFile("count.schema.graphqls"));
}
}

protected final void addJsonQueries(TypeDefinitionRegistry typeRegistry) {
if (cacheService.capabilities().contains(StorageServiceCapability.JSON_QUERY)) {
typeRegistry.merge(loadSchemaDefinitionFile("json.schema.graphqls"));
}
}

protected final void addCountQueries(Builder builder) {
if (supportsCount()) {
builder.dataFetcher("CountProcessInstances", this::countProcessInstances);
builder.dataFetcher("CountUserTaskInstances", this::countUserTaskInstances);
}
}

private boolean supportsCount() {
return cacheService.capabilities().contains(StorageServiceCapability.COUNT);
}

protected TypeDefinitionRegistry loadSchemaDefinitionFile(String fileName) {
return CommonUtils.loadSchemaDefinitionFile(fileName);
}
Expand Down Expand Up @@ -182,18 +206,17 @@ protected Collection<ProcessInstance> getProcessInstancesValues(DataFetchingEnvi
return executeAdvancedQueryForCache(cacheService.getProcessInstanceStorage(), env);
}

protected <K, T> List<T> executeAdvancedQueryForCache(StorageFetcher<K, T> cache, DataFetchingEnvironment env) {
Objects.requireNonNull(cache, "Cache not found");

String inputTypeName = ((GraphQLNamedType) env.getFieldDefinition().getArgument("where").getType()).getName();

Query<T> query = cache.query();
protected long countProcessInstances(DataFetchingEnvironment env) {
return executeCount(cacheService.getProcessInstanceStorage(), env);
}

Map<String, Object> where = env.getArgument("where");
query.filter(GraphQLQueryParserRegistry.get().getParser(inputTypeName).apply(where));
protected long countUserTaskInstances(DataFetchingEnvironment env) {
return executeCount(cacheService.getUserTaskInstanceStorage(), env);
}

protected <K, T> List<T> executeAdvancedQueryForCache(StorageFetcher<K, T> cache, DataFetchingEnvironment env) {
Query<T> query = setupQuery(cache, env);
query.sort(new GraphQLQueryOrderByParser().apply(env));

Map<String, Integer> pagination = env.getArgument("pagination");
if (pagination != null) {
Integer limit = pagination.get("limit");
Expand All @@ -205,10 +228,22 @@ protected <K, T> List<T> executeAdvancedQueryForCache(StorageFetcher<K, T> cache
query.offset(offset);
}
}

return query.execute();
}

protected <K, T> long executeCount(StorageFetcher<K, T> cache, DataFetchingEnvironment env) {
return setupQuery(cache, env).count();
}

private <K, T> Query<T> setupQuery(StorageFetcher<K, T> cache, DataFetchingEnvironment env) {
Objects.requireNonNull(cache, "Cache not found");
String inputTypeName = ((GraphQLNamedType) env.getFieldDefinition().getArgument("where").getType()).getName();
Query<T> query = cache.query();
Map<String, Object> where = env.getArgument("where");
query.filter(GraphQLQueryParserRegistry.get().getParser(inputTypeName).apply(where));
return query;
}

protected Collection<UserTaskInstance> getUserTaskInstancesValues(DataFetchingEnvironment env) {
return executeAdvancedQueryForCache(cacheService.getUserTaskInstanceStorage(), env);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ input ProcessDefinitionArgument {
serviceUrl: StringArgument
description: StringArgument
type: StringArgument
metadata: JSON
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we are preventing json properties to appear int he contextual graphql help in case the datastore does not support it

}

type ProcessInstance {
Expand Down Expand Up @@ -183,7 +182,6 @@ input ProcessInstanceArgument {
id: IdArgument
processId: StringArgument
processName: StringArgument
variables: JSON
parentProcessInstanceId: IdArgument
rootProcessInstanceId: IdArgument
rootProcessId: StringArgument
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
extend type Query {
CountProcessInstances(where: ProcessInstanceArgument): Int
CountUserTaskInstances(where: UserTaskInstanceArgument): Int
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
extend input ProcessInstanceArgument {
variables: JSON
}

extend input ProcessDefinitionArgument {
metadata: JSON
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ public GraphQLSchema createSchema() {
TypeDefinitionRegistry typeDefinitionRegistry = new TypeDefinitionRegistry();
typeDefinitionRegistry.merge(loadSchemaDefinitionFile("basic.schema.graphqls"));
typeDefinitionRegistry.merge(loadSchemaDefinitionFile("domain.schema.graphqls"));
addCountQueries(typeDefinitionRegistry);
addJsonQueries(typeDefinitionRegistry);
loadAdditionalMutations(typeDefinitionRegistry);

RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring()
Expand All @@ -83,6 +85,7 @@ public GraphQLSchema createSchema() {
builder.dataFetcher("ProcessInstances", this::getProcessInstancesValues);
builder.dataFetcher("UserTaskInstances", this::getUserTaskInstancesValues);
builder.dataFetcher("Jobs", this::getJobsValues);
addCountQueries(builder);
return builder;
})
.type("Mutation", builder -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,18 @@
*/
package org.kie.kogito.index.storage;

import java.util.EnumSet;
import java.util.Set;

import org.kie.kogito.index.model.Job;
import org.kie.kogito.index.model.ProcessDefinition;
import org.kie.kogito.index.model.ProcessDefinitionKey;
import org.kie.kogito.persistence.api.Storage;
import org.kie.kogito.persistence.api.StorageServiceCapability;

import com.fasterxml.jackson.databind.node.ObjectNode;

public interface DataIndexStorageService {

Storage<ProcessDefinitionKey, ProcessDefinition> getProcessDefinitionStorage();

ProcessInstanceStorage getProcessInstanceStorage();
Expand All @@ -40,4 +43,8 @@ public interface DataIndexStorageService {
String getDomainModelCacheName(String processId);

Storage<String, String> getProcessIdModelCache();

default Set<StorageServiceCapability> capabilities() {
return EnumSet.noneOf(StorageServiceCapability.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@
*/
package org.kie.kogito.index.jpa.storage;

import java.util.Set;

import org.kie.kogito.index.model.Job;
import org.kie.kogito.index.model.ProcessDefinition;
import org.kie.kogito.index.model.ProcessDefinitionKey;
import org.kie.kogito.index.storage.DataIndexStorageService;
import org.kie.kogito.index.storage.ProcessInstanceStorage;
import org.kie.kogito.index.storage.UserTaskInstanceStorage;
import org.kie.kogito.persistence.api.Storage;
import org.kie.kogito.persistence.api.StorageServiceCapability;

import com.fasterxml.jackson.databind.node.ObjectNode;

Expand Down Expand Up @@ -80,4 +83,9 @@ public String getDomainModelCacheName(String processId) {
public Storage<String, String> getProcessIdModelCache() {
throw new UnsupportedOperationException("Generic String cache not available in JPA");
}

@Override
public Set<StorageServiceCapability> capabilities() {
return processInstanceStorage.capabilities();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,7 @@ public List<T> execute() {
CriteriaBuilder builder = repository.getEntityManager().getCriteriaBuilder();
CriteriaQuery<E> criteriaQuery = builder.createQuery(entityClass);
Root<E> root = criteriaQuery.from(entityClass);
if (filters != null && !filters.isEmpty()) {
List<Predicate> predicates = getPredicates(builder, root);
criteriaQuery.where(predicates.toArray(new Predicate[] {}));
}
addWhere(builder, criteriaQuery, root);
if (sortBy != null && !sortBy.isEmpty()) {
List<Order> orderBy = sortBy.stream().map(f -> {
Path attributePath = getAttributePath(root, f.getAttribute());
Expand All @@ -99,7 +96,6 @@ public List<T> execute() {
}

jakarta.persistence.Query query = repository.getEntityManager().createQuery(criteriaQuery);

if (limit != null) {
query.setMaxResults(limit);
}
Expand Down Expand Up @@ -195,4 +191,21 @@ private List<Predicate> getRecursivePredicate(AttributeFilter<?> filter, Root<E>
.collect(toList());
}

@Override
public long count() {
CriteriaBuilder builder = repository.getEntityManager().getCriteriaBuilder();
CriteriaQuery<Long> criteriaQuery = builder.createQuery(Long.class);
Root<E> root = criteriaQuery.from(entityClass);
criteriaQuery.select(builder.count(root));
addWhere(builder, criteriaQuery, root);
return repository.getEntityManager().createQuery(criteriaQuery).getSingleResult();
}

private <V> void addWhere(CriteriaBuilder builder, CriteriaQuery<V> criteriaQuery, Root<E> root) {
if (filters != null && !filters.isEmpty()) {
List<Predicate> predicates = getPredicates(builder, root);
criteriaQuery.where(predicates.toArray(new Predicate[] {}));
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -47,6 +48,7 @@
import org.kie.kogito.index.model.MilestoneStatus;
import org.kie.kogito.index.model.ProcessInstance;
import org.kie.kogito.index.storage.ProcessInstanceStorage;
import org.kie.kogito.persistence.api.StorageServiceCapability;

import io.quarkus.arc.DefaultBean;

Expand Down Expand Up @@ -234,4 +236,8 @@ private void indexVariable(ProcessInstanceEntity pi, ProcessInstanceVariableEven
private void indexSla(ProcessInstanceEntity orInit, ProcessInstanceSLAEventBody data) {
// SLA does nothing for now
}

public Set<StorageServiceCapability> capabilities() {
return EnumSet.of(StorageServiceCapability.COUNT);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@
*/
package org.kie.kogito.index.jpa.query;

import org.junit.jupiter.api.Test;
import org.kie.kogito.index.jpa.storage.ProcessInstanceEntityStorage;
import org.kie.kogito.index.test.query.AbstractProcessInstanceQueryIT;

import jakarta.inject.Inject;

import static org.assertj.core.api.Assertions.assertThat;

public abstract class AbstractProcessInstanceEntityQueryIT extends AbstractProcessInstanceQueryIT {

@Inject
Expand All @@ -32,4 +35,9 @@ public abstract class AbstractProcessInstanceEntityQueryIT extends AbstractProce
public ProcessInstanceEntityStorage getStorage() {
return storage;
}

@Test
void testCount() {
assertThat(storage.query().count()).isOne();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@
*/
package org.kie.kogito.index.postgresql;

import java.util.EnumSet;
import java.util.Set;

import org.kie.kogito.index.jpa.mapper.ProcessInstanceEntityMapper;
import org.kie.kogito.index.jpa.model.ProcessInstanceEntityRepository;
import org.kie.kogito.index.jpa.storage.ProcessInstanceEntityStorage;
import org.kie.kogito.index.model.ProcessInstance;
import org.kie.kogito.persistence.api.StorageServiceCapability;
import org.kie.kogito.persistence.api.query.Query;

import jakarta.enterprise.context.ApplicationScoped;
Expand All @@ -39,4 +43,8 @@ public PostgresqlProcessInstanceEntityStorage(ProcessInstanceEntityRepository re
public Query<ProcessInstance> query() {
return new PostgresqlJsonJPAQuery<>(repository, mapToModel, entityClass);
}

public Set<StorageServiceCapability> capabilities() {
return EnumSet.allOf(StorageServiceCapability.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public class GraphQLAddonSchemaManagerImpl extends AbstractGraphQLSchemaManager
public GraphQLSchema createSchema() {
TypeDefinitionRegistry typeDefinitionRegistry = new TypeDefinitionRegistry();
typeDefinitionRegistry.merge(loadSchemaDefinitionFile("basic.schema.graphqls"));
addCountQueries(typeDefinitionRegistry);
addJsonQueries(typeDefinitionRegistry);
loadAdditionalMutations(typeDefinitionRegistry);

RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring()
Expand All @@ -42,6 +44,7 @@ public GraphQLSchema createSchema() {
builder.dataFetcher("ProcessInstances", this::getProcessInstancesValues);
builder.dataFetcher("UserTaskInstances", this::getUserTaskInstancesValues);
builder.dataFetcher("Jobs", this::getJobsValues);
addCountQueries(builder);
return builder;
})
.type("Mutation", builder -> {
Expand Down Expand Up @@ -86,5 +89,4 @@ public GraphQLSchema createSchema() {
SchemaGenerator schemaGenerator = new SchemaGenerator();
return schemaGenerator.makeExecutableSchema(typeDefinitionRegistry, runtimeWiring);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
*/
package org.kie.kogito.persistence.api;

import java.util.EnumSet;
import java.util.Set;

import org.kie.kogito.persistence.api.query.Query;

import io.smallrye.mutiny.Multi;
Expand Down Expand Up @@ -45,6 +48,10 @@ public interface StorageFetcher<K, V> {
*/
Query<V> query();

default Set<StorageServiceCapability> capabilities() {
return EnumSet.noneOf(StorageServiceCapability.class);
}

/**
* Gets an element by key. If the element is not present in the storage, then `null` is returned.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.kie.kogito.persistence.api;

public enum StorageServiceCapability {
COUNT,
JSON_QUERY
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,8 @@ public interface Query<T> {
Query<T> sort(List<AttributeSort> sortBy);

List<T> execute();

default long count() {
throw new UnsupportedOperationException();
}
}