Skip to content

Commit

Permalink
[Fix #2158] Adding more filter conditions
Browse files Browse the repository at this point in the history
  • Loading branch information
fjtirado committed Dec 12, 2024
1 parent 1da630c commit 265c623
Show file tree
Hide file tree
Showing 10 changed files with 237 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,11 @@ private static ObjectNode createObjectNode(String variableName, Object variableV
}
return result;
}

public static <T> AttributeFilter<T> jsonFilter(AttributeFilter<T> filter) {
filter.setJson(true);
if (filter != null) {
filter.setJson(true);
}
return filter;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,18 @@ private AttributeFilter<?> mapJsonArgument(String attribute, String key, Object
return jsonFilter(lessThanEqual(sb.toString(), value));
case BETWEEN:
return jsonFilter(filterValueMap(value, val -> between(sb.toString(), val.get("from"), val.get("to"))));
case IN:
return jsonFilter(filterValueList(value, val -> in(sb.toString(), val)));
case IS_NULL:
return jsonFilter(Boolean.TRUE.equals(value) ? isNull(sb.toString()) : notNull(sb.toString()));
case CONTAINS:
return jsonFilter(contains(sb.toString(), value));
case LIKE:
return jsonFilter(like(sb.toString(), value.toString()));
case CONTAINS_ALL:
return filterValueList(value, val -> containsAll(sb.toString(), val));
case CONTAINS_ANY:
return filterValueList(value, val -> containsAny(sb.toString(), val));
case EQUAL:
default:
return jsonFilter(equalTo(sb.toString(), value));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
*/
package org.kie.kogito.index.graphql.query;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -71,4 +73,34 @@ void testJsonMapperBetween() {
assertThat(mapper.mapJsonArgument("variables").apply(Map.of("workflowdata", Map.of("number", Map.of("between", Map.of("from", 1, "to", 3)))))).containsExactly(
jsonFilter(between("variables.workflowdata.number", 1, 3)));
}

@Test
void testJsonMapperIn() {
assertThat(mapper.mapJsonArgument("variables").apply(Map.of("workflowdata", Map.of("number", Map.of("in", List.of(1, 3)))))).containsExactly(
jsonFilter(in("variables.workflowdata.number", Arrays.asList(1, 3))));
}

@Test
void testJsonMapperContains() {
assertThat(mapper.mapJsonArgument("variables").apply(Map.of("workflowdata", Map.of("number", Map.of("contains", 1))))).containsExactly(
jsonFilter(contains("variables.workflowdata.number", 1)));
}

@Test
void testJsonMapperLike() {
assertThat(mapper.mapJsonArgument("variables").apply(Map.of("workflowdata", Map.of("number", Map.of("like", "kk"))))).containsExactly(
jsonFilter(like("variables.workflowdata.number", "kk")));
}

@Test
void testJsonMapperNull() {
assertThat(mapper.mapJsonArgument("variables").apply(Map.of("workflowdata", Map.of("number", Map.of("isNull", true))))).containsExactly(
jsonFilter(isNull("variables.workflowdata.number")));
}

@Test
void testJsonMapperNotNull() {
assertThat(mapper.mapJsonArgument("variables").apply(Map.of("workflowdata", Map.of("number", Map.of("isNull", false))))).containsExactly(
jsonFilter(notNull("variables.workflowdata.number")));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,9 @@ public static BiConsumer<List<ObjectNode>, String[]> assertWithObjectNodeInOrder
public static BiConsumer<List<ObjectNode>, String[]> assertWithObjectNode() {
return (instances, ids) -> assertThat(instances).hasSize(ids == null ? 0 : ids.length).extracting(n -> n.get("id").asText()).containsExactlyInAnyOrder(ids);
}

public static <V> BiConsumer<List<V>, String[]> assertNotId() {
return (instances, ids) -> assertThat(instances).extracting("id").doesNotContainAnyElementsOf(List.of(ids));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@
import org.kie.kogito.jackson.utils.ObjectMapperFactory;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;

import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;
Expand Down Expand Up @@ -83,6 +85,20 @@ public static ProcessInstanceVariableDataEvent createProcessInstanceVariableEven
return event;
}

public static ProcessInstanceVariableDataEvent createProcessInstanceVariableEvent(String processInstance,
String processId, String name, int age, boolean isMartian, List<String> aliases) {
ProcessInstanceVariableDataEvent event = new ProcessInstanceVariableDataEvent();
event.setKogitoProcessId(processId);
event.setKogitoProcessInstanceId(processInstance);
ArrayNode node = ObjectMapperFactory.get().createArrayNode();
aliases.forEach(s -> node.add(new TextNode(s)));
event.setData(ProcessInstanceVariableEventBody.create().processId(processId).processInstanceId(processInstance)
.variableName("traveller").variableValue(ObjectMapperFactory.get().createObjectNode().put("name", name).put("age", age).put("isMartian", isMartian)
.set("aliases", node))
.build());
return event;
}

public static ProcessInstanceNodeDataEvent createProcessInstanceNodeDataEvent(String processInstance, String processId, String nodeDefinitionId, String nodeInstanceId, String nodeName,
String nodeType, int eventType) {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* 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.index.postgresql;

import java.util.List;
import java.util.stream.Collectors;

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

import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;

import static java.util.stream.Collectors.toList;

public class PostgresqlJsonHelper {

private PostgresqlJsonHelper() {
}

public static Predicate buildPredicate(AttributeFilter<?> filter, Root<?> root,
CriteriaBuilder builder) {
boolean isString;
List<Object> values;
switch (filter.getCondition()) {
case EQUAL:
isString = filter.getValue() instanceof String;
return builder.equal(buildPathExpression(builder, root, filter.getAttribute(), isString), buildObjectExpression(builder, filter.getValue(), isString));
case GT:
isString = filter.getValue() instanceof String;
return builder.greaterThan(buildPathExpression(builder, root, filter.getAttribute(), isString), buildObjectExpression(builder, filter.getValue(), isString));
case GTE:
isString = filter.getValue() instanceof String;
return builder.greaterThanOrEqualTo(buildPathExpression(builder, root, filter.getAttribute(), isString), buildObjectExpression(builder, filter.getValue(), isString));
case LT:
isString = filter.getValue() instanceof String;
return builder.lessThan(buildPathExpression(builder, root, filter.getAttribute(), isString), buildObjectExpression(builder, filter.getValue(), isString));
case LTE:
isString = filter.getValue() instanceof String;
return builder
.lessThanOrEqualTo(buildPathExpression(builder, root, filter.getAttribute(), isString), buildObjectExpression(builder, filter.getValue(), isString));
case LIKE:
return builder.like(buildPathExpression(builder, root, filter.getAttribute(), true),
filter.getValue().toString().replaceAll("\\*", "%"));
case IS_NULL:
return builder.isNull(buildPathExpression(builder, root, filter.getAttribute(), false));
case NOT_NULL:
return builder.isNotNull(buildPathExpression(builder, root, filter.getAttribute(), false));
case BETWEEN:
values = (List<Object>) filter.getValue();
isString = values.get(0) instanceof String;
return builder.between(buildPathExpression(builder, root, filter.getAttribute(), isString), buildObjectExpression(builder, values.get(0), isString),
buildObjectExpression(builder, values.get(1), isString));
case IN:
values = (List<Object>) filter.getValue();
isString = values.get(0) instanceof String;
return buildPathExpression(builder, root, filter.getAttribute(), isString).in(values.stream().map(o -> buildObjectExpression(builder, o, isString)).collect(Collectors.toList()));
}
throw new UnsupportedOperationException("Filter " + filter + " is not supported");
}

private static Expression buildObjectExpression(CriteriaBuilder builder, Object value, boolean isString) {
return isString ? builder.literal(value) : builder.function("to_jsonb", Object.class, builder.literal(value));
}

private static Expression buildObjectExpression(CriteriaBuilder builder, Object value) {
return buildObjectExpression(builder, value, value instanceof String);
}

private static Expression buildPathExpression(CriteriaBuilder builder, Root<?> root, String attributeName, boolean isStr) {
String[] attributes = attributeName.split("\\.");
Expression<?>[] arguments = new Expression[attributes.length];
arguments[0] = root.get(attributes[0]);
for (int i = 1; i < attributes.length; i++) {
arguments[i] = builder.literal(attributes[i]);
}
return isStr ? builder.function("jsonb_extract_path_text", String.class, arguments) : builder.function("jsonb_extract_path", Object.class, arguments);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,6 @@ public PostgresqlJsonJPAQuery(PanacheRepositoryBase<E, K> repository, Function<E
}

protected Function<AttributeFilter<?>, Predicate> filterPredicateFunction(Root<E> root, CriteriaBuilder builder) {
return filter -> filter.isJson() ? PostgresqlJsonNavigator.buildPredicate(filter, root, builder) : buildPredicateFunction(filter, root, builder);
return filter -> filter.isJson() ? PostgresqlJsonHelper.buildPredicate(filter, root, builder) : buildPredicateFunction(filter, root, builder);
}
}

This file was deleted.

Loading

0 comments on commit 265c623

Please sign in to comment.