This is an automated email from the ASF dual-hosted git repository.

fjtiradosarti pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-kogito-apps.git


The following commit(s) were added to refs/heads/main by this push:
     new c598a6a4e [Fix #2175]Adding count process intance and count user task 
queries (#2196)
c598a6a4e is described below

commit c598a6a4e665a182b316959224ff8901cbb0ed2f
Author: Francisco Javier Tirado Sarti 
<[email protected]>
AuthorDate: Thu Feb 27 10:41:07 2025 +0100

    [Fix #2175]Adding count process intance and count user task queries (#2196)
    
    * [Fix #2175]Adding count process intance and count user task queries
    
    * [Fix #2175] Hide json variables for DB not supporting it
    
    * [Fix #2175] Adding license exclusion
    
    * [Fix #2175] Addressing Gonzalo's comments
---
 .rat-excludes                                      |  4 ++
 .../graphql/AbstractGraphQLSchemaManager.java      | 66 ++++++++++++++++++----
 .../src/main/resources/basic.schema.graphqls       |  2 -
 .../src/main/resources/count.schema.graphqls       |  4 ++
 .../src/main/resources/json.schema.graphqls        |  7 +++
 .../service/graphql/GraphQLSchemaManagerImpl.java  |  3 +
 .../index/storage/DataIndexStorageService.java     |  9 ++-
 .../jpa/storage/JPADataIndexStorageService.java    |  8 +++
 .../org/kie/kogito/index/jpa/storage/JPAQuery.java | 26 +++++----
 .../jpa/storage/ProcessInstanceEntityStorage.java  |  6 ++
 .../AbstractProcessInstanceEntityQueryIT.java      | 18 ++++++
 .../AbstractUserTaskInstanceEntityQueryIT.java     | 22 ++++++++
 .../PostgresqlProcessInstanceEntityStorage.java    |  8 +++
 .../query/ProcessInstanceEntityQueryIT.java        | 17 +++++-
 .../graphql/GraphQLAddonSchemaManagerImpl.java     |  4 +-
 .../kie/kogito/persistence/api/StorageFetcher.java |  7 +++
 .../Query.java => StorageServiceCapability.java}   | 18 ++----
 .../kie/kogito/persistence/api/query/Query.java    |  4 ++
 18 files changed, 193 insertions(+), 40 deletions(-)

diff --git a/.rat-excludes b/.rat-excludes
index 7ed9b60ce..c6e655f26 100644
--- a/.rat-excludes
+++ b/.rat-excludes
@@ -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
diff --git 
a/data-index/data-index-graphql/src/main/java/org/kie/kogito/index/graphql/AbstractGraphQLSchemaManager.java
 
b/data-index/data-index-graphql/src/main/java/org/kie/kogito/index/graphql/AbstractGraphQLSchemaManager.java
index a3872eff8..50a996ae7 100644
--- 
a/data-index/data-index-graphql/src/main/java/org/kie/kogito/index/graphql/AbstractGraphQLSchemaManager.java
+++ 
b/data-index/data-index-graphql/src/main/java/org/kie/kogito/index/graphql/AbstractGraphQLSchemaManager.java
@@ -21,7 +21,6 @@ package org.kie.kogito.index.graphql;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 import java.util.ServiceLoader;
 import java.util.ServiceLoader.Provider;
 import java.util.concurrent.CompletableFuture;
@@ -31,6 +30,7 @@ import java.util.stream.Collectors;
 import org.kie.kogito.index.CommonUtils;
 import org.kie.kogito.index.api.KogitoRuntimeClient;
 import org.kie.kogito.index.graphql.query.GraphQLQueryOrderByParser;
+import org.kie.kogito.index.graphql.query.GraphQLQueryParser;
 import org.kie.kogito.index.graphql.query.GraphQLQueryParserRegistry;
 import org.kie.kogito.index.model.Job;
 import org.kie.kogito.index.model.Node;
@@ -41,13 +41,16 @@ import org.kie.kogito.index.model.UserTaskInstance;
 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;
 
 import graphql.schema.DataFetcher;
 import graphql.schema.DataFetchingEnvironment;
+import graphql.schema.GraphQLArgument;
 import graphql.schema.GraphQLInputObjectType;
+import graphql.schema.GraphQLInputType;
 import graphql.schema.GraphQLNamedType;
 import graphql.schema.GraphQLScalarType;
 import graphql.schema.GraphQLSchema;
@@ -109,6 +112,29 @@ public abstract class AbstractGraphQLSchemaManager 
implements GraphQLSchemaManag
         
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);
     }
@@ -182,18 +208,17 @@ public abstract class AbstractGraphQLSchemaManager 
implements GraphQLSchemaManag
         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 = buildQuery(cache, env);
         query.sort(new GraphQLQueryOrderByParser().apply(env));
-
         Map<String, Integer> pagination = env.getArgument("pagination");
         if (pagination != null) {
             Integer limit = pagination.get("limit");
@@ -205,10 +230,29 @@ public abstract class AbstractGraphQLSchemaManager 
implements GraphQLSchemaManag
                 query.offset(offset);
             }
         }
-
         return query.execute();
     }
 
+    protected <K, T> long executeCount(StorageFetcher<K, T> cache, 
DataFetchingEnvironment env) {
+        return buildQuery(cache, env).count();
+    }
+
+    private <K, T> Query<T> buildQuery(StorageFetcher<K, T> cache, 
DataFetchingEnvironment env) {
+        assert cache != null;
+        Query<T> query = cache.query();
+        GraphQLArgument arg = env.getFieldDefinition().getArgument("where");
+        if (arg != null) {
+            GraphQLInputType inputType = arg.getType();
+            if (inputType instanceof GraphQLNamedType) {
+                GraphQLQueryParser parser = 
GraphQLQueryParserRegistry.get().getParser(((GraphQLNamedType) 
inputType).getName());
+                if (parser != null) {
+                    query.filter(parser.apply(env.getArgument("where")));
+                }
+            }
+        }
+        return query;
+    }
+
     protected Collection<UserTaskInstance> 
getUserTaskInstancesValues(DataFetchingEnvironment env) {
         return 
executeAdvancedQueryForCache(cacheService.getUserTaskInstanceStorage(), env);
     }
diff --git 
a/data-index/data-index-graphql/src/main/resources/basic.schema.graphqls 
b/data-index/data-index-graphql/src/main/resources/basic.schema.graphqls
index 358454c2a..e3a2086b2 100644
--- a/data-index/data-index-graphql/src/main/resources/basic.schema.graphqls
+++ b/data-index/data-index-graphql/src/main/resources/basic.schema.graphqls
@@ -69,7 +69,6 @@ input ProcessDefinitionArgument {
     serviceUrl: StringArgument
     description: StringArgument
     type: StringArgument
-    metadata: JSON
 }
 
 type ProcessInstance {
@@ -183,7 +182,6 @@ input ProcessInstanceArgument {
     id: IdArgument
     processId: StringArgument
     processName: StringArgument
-    variables: JSON
     parentProcessInstanceId: IdArgument
     rootProcessInstanceId: IdArgument
     rootProcessId: StringArgument
diff --git 
a/data-index/data-index-graphql/src/main/resources/count.schema.graphqls 
b/data-index/data-index-graphql/src/main/resources/count.schema.graphqls
new file mode 100644
index 000000000..180ed7d0d
--- /dev/null
+++ b/data-index/data-index-graphql/src/main/resources/count.schema.graphqls
@@ -0,0 +1,4 @@
+extend type Query {
+    CountProcessInstances(where: ProcessInstanceArgument): Int
+    CountUserTaskInstances(where: UserTaskInstanceArgument): Int
+}
\ No newline at end of file
diff --git 
a/data-index/data-index-graphql/src/main/resources/json.schema.graphqls 
b/data-index/data-index-graphql/src/main/resources/json.schema.graphqls
new file mode 100644
index 000000000..ddd1d2d16
--- /dev/null
+++ b/data-index/data-index-graphql/src/main/resources/json.schema.graphqls
@@ -0,0 +1,7 @@
+extend input ProcessInstanceArgument {
+  variables: JSON
+}
+
+extend input ProcessDefinitionArgument {
+  metadata: JSON
+}
\ No newline at end of file
diff --git 
a/data-index/data-index-service/data-index-service-common/src/main/java/org/kie/kogito/index/service/graphql/GraphQLSchemaManagerImpl.java
 
b/data-index/data-index-service/data-index-service-common/src/main/java/org/kie/kogito/index/service/graphql/GraphQLSchemaManagerImpl.java
index cadff87c6..03b63f8e7 100644
--- 
a/data-index/data-index-service/data-index-service-common/src/main/java/org/kie/kogito/index/service/graphql/GraphQLSchemaManagerImpl.java
+++ 
b/data-index/data-index-service/data-index-service-common/src/main/java/org/kie/kogito/index/service/graphql/GraphQLSchemaManagerImpl.java
@@ -74,6 +74,8 @@ public class GraphQLSchemaManagerImpl extends 
AbstractGraphQLSchemaManager {
         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()
@@ -83,6 +85,7 @@ public class GraphQLSchemaManagerImpl extends 
AbstractGraphQLSchemaManager {
                     builder.dataFetcher("ProcessInstances", 
this::getProcessInstancesValues);
                     builder.dataFetcher("UserTaskInstances", 
this::getUserTaskInstancesValues);
                     builder.dataFetcher("Jobs", this::getJobsValues);
+                    addCountQueries(builder);
                     return builder;
                 })
                 .type("Mutation", builder -> {
diff --git 
a/data-index/data-index-storage/data-index-storage-api/src/main/java/org/kie/kogito/index/storage/DataIndexStorageService.java
 
b/data-index/data-index-storage/data-index-storage-api/src/main/java/org/kie/kogito/index/storage/DataIndexStorageService.java
index 43c951fd8..10e2d9195 100644
--- 
a/data-index/data-index-storage/data-index-storage-api/src/main/java/org/kie/kogito/index/storage/DataIndexStorageService.java
+++ 
b/data-index/data-index-storage/data-index-storage-api/src/main/java/org/kie/kogito/index/storage/DataIndexStorageService.java
@@ -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();
@@ -40,4 +43,8 @@ public interface DataIndexStorageService {
     String getDomainModelCacheName(String processId);
 
     Storage<String, String> getProcessIdModelCache();
+
+    default Set<StorageServiceCapability> capabilities() {
+        return EnumSet.noneOf(StorageServiceCapability.class);
+    }
 }
diff --git 
a/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/storage/JPADataIndexStorageService.java
 
b/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/storage/JPADataIndexStorageService.java
index 99bbccf0c..c1c856cd9 100644
--- 
a/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/storage/JPADataIndexStorageService.java
+++ 
b/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/storage/JPADataIndexStorageService.java
@@ -18,6 +18,8 @@
  */
 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;
@@ -25,6 +27,7 @@ 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;
 
@@ -80,4 +83,9 @@ public class JPADataIndexStorageService implements 
DataIndexStorageService {
     public Storage<String, String> getProcessIdModelCache() {
         throw new UnsupportedOperationException("Generic String cache not 
available in JPA");
     }
+
+    @Override
+    public Set<StorageServiceCapability> capabilities() {
+        return processInstanceStorage.capabilities();
+    }
 }
diff --git 
a/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/storage/JPAQuery.java
 
b/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/storage/JPAQuery.java
index 4ab1f7d6d..07a3a479c 100644
--- 
a/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/storage/JPAQuery.java
+++ 
b/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/storage/JPAQuery.java
@@ -86,10 +86,7 @@ public class JPAQuery<K, E extends AbstractEntity, T> 
implements Query<T> {
         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());
@@ -97,9 +94,7 @@ public class JPAQuery<K, E extends AbstractEntity, T> 
implements Query<T> {
             }).collect(toList());
             criteriaQuery.orderBy(orderBy);
         }
-
         jakarta.persistence.Query query = 
repository.getEntityManager().createQuery(criteriaQuery);
-
         if (limit != null) {
             query.setMaxResults(limit);
         }
@@ -109,10 +104,6 @@ public class JPAQuery<K, E extends AbstractEntity, T> 
implements Query<T> {
         return (List<T>) 
query.getResultList().stream().map(mapper).collect(toList());
     }
 
-    protected List<Predicate> getPredicates(CriteriaBuilder builder, Root<E> 
root) {
-        return filters.stream().map(filterPredicateFunction(root, 
builder)).collect(toList());
-    }
-
     protected Function<AttributeFilter<?>, Predicate> 
filterPredicateFunction(Root<E> root, CriteriaBuilder builder) {
         return filter -> buildPredicateFunction(filter, root, builder);
     }
@@ -195,4 +186,19 @@ public class JPAQuery<K, E extends AbstractEntity, T> 
implements Query<T> {
                 .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()) {
+            
criteriaQuery.where(filters.stream().map(filterPredicateFunction(root, 
builder)).toArray(Predicate[]::new));
+        }
+    }
 }
diff --git 
a/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/storage/ProcessInstanceEntityStorage.java
 
b/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/storage/ProcessInstanceEntityStorage.java
index b9fe816cb..b6ab5aa3e 100644
--- 
a/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/storage/ProcessInstanceEntityStorage.java
+++ 
b/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/storage/ProcessInstanceEntityStorage.java
@@ -20,6 +20,7 @@ package org.kie.kogito.index.jpa.storage;
 
 import java.time.ZonedDateTime;
 import java.util.ArrayList;
+import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
@@ -47,6 +48,7 @@ import org.kie.kogito.index.json.JsonUtils;
 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;
 
@@ -234,4 +236,8 @@ public class ProcessInstanceEntityStorage extends 
AbstractJPAStorageFetcher<Stri
     private void indexSla(ProcessInstanceEntity orInit, 
ProcessInstanceSLAEventBody data) {
         // SLA does nothing for now
     }
+
+    public Set<StorageServiceCapability> capabilities() {
+        return EnumSet.of(StorageServiceCapability.COUNT);
+    }
 }
diff --git 
a/data-index/data-index-storage/data-index-storage-jpa-common/src/test/java/org/kie/kogito/index/jpa/query/AbstractProcessInstanceEntityQueryIT.java
 
b/data-index/data-index-storage/data-index-storage-jpa-common/src/test/java/org/kie/kogito/index/jpa/query/AbstractProcessInstanceEntityQueryIT.java
index f2fc96790..269da8167 100644
--- 
a/data-index/data-index-storage/data-index-storage-jpa-common/src/test/java/org/kie/kogito/index/jpa/query/AbstractProcessInstanceEntityQueryIT.java
+++ 
b/data-index/data-index-storage/data-index-storage-jpa-common/src/test/java/org/kie/kogito/index/jpa/query/AbstractProcessInstanceEntityQueryIT.java
@@ -18,11 +18,21 @@
  */
 package org.kie.kogito.index.jpa.query;
 
+import java.util.List;
+import java.util.UUID;
+
+import org.junit.jupiter.api.Test;
+import org.kie.kogito.event.process.ProcessInstanceStateDataEvent;
 import org.kie.kogito.index.jpa.storage.ProcessInstanceEntityStorage;
+import org.kie.kogito.index.test.TestUtils;
 import org.kie.kogito.index.test.query.AbstractProcessInstanceQueryIT;
 
 import jakarta.inject.Inject;
 
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.kie.kogito.index.model.ProcessInstanceState.COMPLETED;
+import static org.kie.kogito.persistence.api.query.QueryFilterFactory.in;
+
 public abstract class AbstractProcessInstanceEntityQueryIT extends 
AbstractProcessInstanceQueryIT {
 
     @Inject
@@ -32,4 +42,12 @@ public abstract class AbstractProcessInstanceEntityQueryIT 
extends AbstractProce
     public ProcessInstanceEntityStorage getStorage() {
         return storage;
     }
+
+    @Test
+    void testCount() {
+        ProcessInstanceStateDataEvent processInstanceEvent = 
TestUtils.createProcessInstanceEvent(UUID.randomUUID().toString(), "counting", 
null, null, COMPLETED.ordinal());
+        storage.indexState(processInstanceEvent);
+        assertThat(storage.query().count()).isNotZero();
+        assertThat(storage.query().filter(List.of(in("state", 
List.of(34)))).count()).isZero();
+    }
 }
diff --git 
a/data-index/data-index-storage/data-index-storage-jpa-common/src/test/java/org/kie/kogito/index/jpa/query/AbstractUserTaskInstanceEntityQueryIT.java
 
b/data-index/data-index-storage/data-index-storage-jpa-common/src/test/java/org/kie/kogito/index/jpa/query/AbstractUserTaskInstanceEntityQueryIT.java
index 347b2765c..4fe86e415 100644
--- 
a/data-index/data-index-storage/data-index-storage-jpa-common/src/test/java/org/kie/kogito/index/jpa/query/AbstractUserTaskInstanceEntityQueryIT.java
+++ 
b/data-index/data-index-storage/data-index-storage-jpa-common/src/test/java/org/kie/kogito/index/jpa/query/AbstractUserTaskInstanceEntityQueryIT.java
@@ -18,11 +18,20 @@
  */
 package org.kie.kogito.index.jpa.query;
 
+import java.util.List;
+import java.util.UUID;
+
+import org.junit.jupiter.api.Test;
+import org.kie.kogito.event.usertask.UserTaskInstanceStateDataEvent;
+import org.kie.kogito.event.usertask.UserTaskInstanceStateEventBody;
 import org.kie.kogito.index.jpa.storage.UserTaskInstanceEntityStorage;
 import org.kie.kogito.index.test.query.AbstractUserTaskInstanceQueryIT;
 
 import jakarta.inject.Inject;
 
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.kie.kogito.persistence.api.query.QueryFilterFactory.in;
+
 public abstract class AbstractUserTaskInstanceEntityQueryIT extends 
AbstractUserTaskInstanceQueryIT {
 
     @Inject
@@ -37,4 +46,17 @@ public abstract class AbstractUserTaskInstanceEntityQueryIT 
extends AbstractUser
     protected Boolean isDateTimeAsLong() {
         return false;
     }
+
+    @Test
+    void testCount() {
+        String taskId = UUID.randomUUID().toString();
+        String processInstanceId = UUID.randomUUID().toString();
+        UserTaskInstanceStateDataEvent event = new 
UserTaskInstanceStateDataEvent();
+        event.setKogitoProcessInstanceId(processInstanceId);
+        event.setKogitoUserTaskInstanceId(taskId);
+        
event.setData(UserTaskInstanceStateEventBody.create().processInstanceId(processInstanceId).state("InProgress").userTaskInstanceId(taskId).build());
+        storage.indexState(event);
+        assertThat(storage.query().count()).isNotZero();
+        assertThat(storage.query().filter(List.of(in("state", 
List.of("Javierito")))).count()).isZero();
+    }
 }
diff --git 
a/data-index/data-index-storage/data-index-storage-postgresql/src/main/java/org/kie/kogito/index/postgresql/PostgresqlProcessInstanceEntityStorage.java
 
b/data-index/data-index-storage/data-index-storage-postgresql/src/main/java/org/kie/kogito/index/postgresql/PostgresqlProcessInstanceEntityStorage.java
index db6a00156..9b9c32d5e 100644
--- 
a/data-index/data-index-storage/data-index-storage-postgresql/src/main/java/org/kie/kogito/index/postgresql/PostgresqlProcessInstanceEntityStorage.java
+++ 
b/data-index/data-index-storage/data-index-storage-postgresql/src/main/java/org/kie/kogito/index/postgresql/PostgresqlProcessInstanceEntityStorage.java
@@ -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;
@@ -39,4 +43,8 @@ public class PostgresqlProcessInstanceEntityStorage extends 
ProcessInstanceEntit
     public Query<ProcessInstance> query() {
         return new PostgresqlJsonJPAQuery<>(repository, mapToModel, 
entityClass);
     }
+
+    public Set<StorageServiceCapability> capabilities() {
+        return EnumSet.allOf(StorageServiceCapability.class);
+    }
 }
diff --git 
a/data-index/data-index-storage/data-index-storage-postgresql/src/test/java/org/kie/kogito/index/postgresql/query/ProcessInstanceEntityQueryIT.java
 
b/data-index/data-index-storage/data-index-storage-postgresql/src/test/java/org/kie/kogito/index/postgresql/query/ProcessInstanceEntityQueryIT.java
index fe2a33237..84bb06418 100644
--- 
a/data-index/data-index-storage/data-index-storage-postgresql/src/test/java/org/kie/kogito/index/postgresql/query/ProcessInstanceEntityQueryIT.java
+++ 
b/data-index/data-index-storage/data-index-storage-postgresql/src/test/java/org/kie/kogito/index/postgresql/query/ProcessInstanceEntityQueryIT.java
@@ -42,7 +42,22 @@ import static java.util.Collections.singletonList;
 import static org.kie.kogito.index.json.JsonUtils.jsonFilter;
 import static org.kie.kogito.index.test.QueryTestUtils.assertNotId;
 import static org.kie.kogito.index.test.QueryTestUtils.assertWithId;
-import static org.kie.kogito.persistence.api.query.QueryFilterFactory.*;
+import static org.kie.kogito.persistence.api.query.QueryFilterFactory.and;
+import static org.kie.kogito.persistence.api.query.QueryFilterFactory.between;
+import static org.kie.kogito.persistence.api.query.QueryFilterFactory.contains;
+import static 
org.kie.kogito.persistence.api.query.QueryFilterFactory.containsAll;
+import static 
org.kie.kogito.persistence.api.query.QueryFilterFactory.containsAny;
+import static org.kie.kogito.persistence.api.query.QueryFilterFactory.equalTo;
+import static 
org.kie.kogito.persistence.api.query.QueryFilterFactory.greaterThan;
+import static 
org.kie.kogito.persistence.api.query.QueryFilterFactory.greaterThanEqual;
+import static org.kie.kogito.persistence.api.query.QueryFilterFactory.in;
+import static org.kie.kogito.persistence.api.query.QueryFilterFactory.isNull;
+import static org.kie.kogito.persistence.api.query.QueryFilterFactory.lessThan;
+import static 
org.kie.kogito.persistence.api.query.QueryFilterFactory.lessThanEqual;
+import static org.kie.kogito.persistence.api.query.QueryFilterFactory.like;
+import static org.kie.kogito.persistence.api.query.QueryFilterFactory.not;
+import static org.kie.kogito.persistence.api.query.QueryFilterFactory.notNull;
+import static org.kie.kogito.persistence.api.query.QueryFilterFactory.or;
 
 @QuarkusTest
 @QuarkusTestResource(PostgreSqlQuarkusTestResource.class)
diff --git 
a/data-index/kogito-addons-quarkus-data-index/kogito-addons-quarkus-data-index-common/runtime/src/main/java/org/kie/kogito/index/addon/graphql/GraphQLAddonSchemaManagerImpl.java
 
b/data-index/kogito-addons-quarkus-data-index/kogito-addons-quarkus-data-index-common/runtime/src/main/java/org/kie/kogito/index/addon/graphql/GraphQLAddonSchemaManagerImpl.java
index ca8a07eb3..31c41815e 100644
--- 
a/data-index/kogito-addons-quarkus-data-index/kogito-addons-quarkus-data-index-common/runtime/src/main/java/org/kie/kogito/index/addon/graphql/GraphQLAddonSchemaManagerImpl.java
+++ 
b/data-index/kogito-addons-quarkus-data-index/kogito-addons-quarkus-data-index-common/runtime/src/main/java/org/kie/kogito/index/addon/graphql/GraphQLAddonSchemaManagerImpl.java
@@ -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()
@@ -42,6 +44,7 @@ public class GraphQLAddonSchemaManagerImpl extends 
AbstractGraphQLSchemaManager
                     builder.dataFetcher("ProcessInstances", 
this::getProcessInstancesValues);
                     builder.dataFetcher("UserTaskInstances", 
this::getUserTaskInstancesValues);
                     builder.dataFetcher("Jobs", this::getJobsValues);
+                    addCountQueries(builder);
                     return builder;
                 })
                 .type("Mutation", builder -> {
@@ -86,5 +89,4 @@ public class GraphQLAddonSchemaManagerImpl extends 
AbstractGraphQLSchemaManager
         SchemaGenerator schemaGenerator = new SchemaGenerator();
         return schemaGenerator.makeExecutableSchema(typeDefinitionRegistry, 
runtimeWiring);
     }
-
 }
diff --git 
a/persistence-commons/persistence-commons-api/src/main/java/org/kie/kogito/persistence/api/StorageFetcher.java
 
b/persistence-commons/persistence-commons-api/src/main/java/org/kie/kogito/persistence/api/StorageFetcher.java
index 73cce384a..b84cc3d78 100644
--- 
a/persistence-commons/persistence-commons-api/src/main/java/org/kie/kogito/persistence/api/StorageFetcher.java
+++ 
b/persistence-commons/persistence-commons-api/src/main/java/org/kie/kogito/persistence/api/StorageFetcher.java
@@ -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;
@@ -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.
      *
diff --git 
a/persistence-commons/persistence-commons-api/src/main/java/org/kie/kogito/persistence/api/query/Query.java
 
b/persistence-commons/persistence-commons-api/src/main/java/org/kie/kogito/persistence/api/StorageServiceCapability.java
similarity index 72%
copy from 
persistence-commons/persistence-commons-api/src/main/java/org/kie/kogito/persistence/api/query/Query.java
copy to 
persistence-commons/persistence-commons-api/src/main/java/org/kie/kogito/persistence/api/StorageServiceCapability.java
index 1232444f3..6c5c001f2 100644
--- 
a/persistence-commons/persistence-commons-api/src/main/java/org/kie/kogito/persistence/api/query/Query.java
+++ 
b/persistence-commons/persistence-commons-api/src/main/java/org/kie/kogito/persistence/api/StorageServiceCapability.java
@@ -16,19 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.kie.kogito.persistence.api.query;
+package org.kie.kogito.persistence.api;
 
-import java.util.List;
-
-public interface Query<T> {
-
-    Query<T> limit(Integer limit);
-
-    Query<T> offset(Integer offset);
-
-    Query<T> filter(List<AttributeFilter<?>> filters);
-
-    Query<T> sort(List<AttributeSort> sortBy);
-
-    List<T> execute();
+public enum StorageServiceCapability {
+    COUNT,
+    JSON_QUERY
 }
diff --git 
a/persistence-commons/persistence-commons-api/src/main/java/org/kie/kogito/persistence/api/query/Query.java
 
b/persistence-commons/persistence-commons-api/src/main/java/org/kie/kogito/persistence/api/query/Query.java
index 1232444f3..9cd20b553 100644
--- 
a/persistence-commons/persistence-commons-api/src/main/java/org/kie/kogito/persistence/api/query/Query.java
+++ 
b/persistence-commons/persistence-commons-api/src/main/java/org/kie/kogito/persistence/api/query/Query.java
@@ -31,4 +31,8 @@ public interface Query<T> {
     Query<T> sort(List<AttributeSort> sortBy);
 
     List<T> execute();
+
+    default long count() {
+        throw new UnsupportedOperationException("Count is an optional 
operation not supported by the underlying datastore");
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to