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

feat: add ilike operator for Criterion #4114

Merged
merged 1 commit into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public static CriterionOperatorRegistry ofDefaults() {
registry.registerOperatorPredicate(EQUAL, new EqualOperatorPredicate());
registry.registerOperatorPredicate(IN, new InOperatorPredicate());
registry.registerOperatorPredicate(LIKE, new LikeOperatorPredicate());
registry.registerOperatorPredicate(ILIKE, new IlikeOperatorPredicate());
registry.registerOperatorPredicate(CONTAINS, new ContainsOperatorPredicate());
return registry;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
*
*/

package org.eclipse.edc.query;

import org.eclipse.edc.spi.query.OperatorPredicate;

import java.util.regex.Pattern;

public class IlikeOperatorPredicate implements OperatorPredicate {
@Override
public boolean test(Object property, Object operandRight) {
if (operandRight instanceof String stringOperand) {
var regexPattern = Pattern.quote(stringOperand.toLowerCase())
.replace("%", "\\E.*\\Q")
.replace("_", "\\E.\\Q");

return Pattern.compile("^" + regexPattern + "$")
.matcher(property.toString().toLowerCase())
.matches();
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
*
*/

package org.eclipse.edc.query;

import org.eclipse.edc.spi.query.OperatorPredicate;
import org.junit.jupiter.api.Test;

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

class IlikeOperatorPredicateTest {

private final OperatorPredicate predicate = new IlikeOperatorPredicate();

@Test
void shouldHandlePercentAtTheStartOfTheString() {
assertThat(predicate.test("THIS IS A TEST", "%test")).isTrue();
assertThat(predicate.test("NOT TESTED", "%test")).isFalse();
}

@Test
void shouldHandlePercentAtTheEndOfTheString() {
assertThat(predicate.test("TEST VALID", "test%")).isTrue();
assertThat(predicate.test(" TEST INVALID", "test%")).isFalse();
}

@Test
void shouldHandlePercentAtTheStartAndEndOfTheString() {
assertThat(predicate.test("THIS TEST VALID", "%test%")).isTrue();
assertThat(predicate.test("TEST ALSO VALID", "%test%")).isTrue();
assertThat(predicate.test("VALID IS THE TEST", "%test%")).isTrue();
assertThat(predicate.test("INVALID", "%test%")).isFalse();
}

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

import static org.eclipse.edc.spi.query.CriterionOperatorRegistry.CONTAINS;
import static org.eclipse.edc.spi.query.CriterionOperatorRegistry.EQUAL;
import static org.eclipse.edc.spi.query.CriterionOperatorRegistry.ILIKE;
import static org.eclipse.edc.spi.query.CriterionOperatorRegistry.IN;
import static org.eclipse.edc.spi.query.CriterionOperatorRegistry.LIKE;

Expand All @@ -31,6 +32,7 @@ public SqlOperator translate(String operator) {
return switch (operator) {
case EQUAL -> new SqlOperator("=", Object.class);
case LIKE -> new SqlOperator("like", String.class);
case ILIKE -> new SqlOperator("ilike", String.class);
case IN -> new SqlOperator("in", Collection.class);
case CONTAINS -> new SqlOperator("??", Object.class);
default -> null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ void shouldTranslate_like() {
assertThat(operator.rightOperandClass()).isEqualTo(String.class);
}

@Test
void shouldTranslate_ilike() {
var operator = translator.translate("ilike");

assertThat(operator.representation()).isEqualTo("ilike");
assertThat(operator.rightOperandClass()).isEqualTo(String.class);
}

@Test
void shouldTranslate_in() {
var operator = translator.translate("in");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public interface CriterionOperatorRegistry {
String EQUAL = "=";
String IN = "in";
String LIKE = "like";
String ILIKE = "ilike";
String CONTAINS = "contains";

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,10 +211,7 @@ void shouldReturnAllTheAssets_whenQuerySpecIsEmpty() {
@Test
@DisplayName("Query assets with query spec")
void limit() {
for (var i = 1; i <= 10; i++) {
var asset = getAsset("id" + i);
getAssetIndex().create(asset);
}
range(1, 10).mapToObj(it -> getAsset("id" + it)).forEach(asset -> getAssetIndex().create(asset));
var querySpec = QuerySpec.Builder.newInstance().limit(3).offset(2).build();

var assetsFound = getAssetIndex().queryAssets(querySpec);
Expand Down Expand Up @@ -405,8 +402,7 @@ void withPrivateSorting() {
}

@Test
@DisplayName("Query assets using the LIKE operator")
void like() {
void shouldFilter_whenLikeOperator() {
var asset1 = getAsset("id1");
getAssetIndex().create(asset1);
var asset2 = getAsset("id2");
Expand All @@ -418,6 +414,17 @@ void like() {
assertThat(assetsFound).isNotNull().hasSize(2);
}

@Test
void shouldFilter_whenIlikeOperator() {
getAssetIndex().create(getAsset("ID1"));
getAssetIndex().create(getAsset("ID2"));
var criterion = new Criterion(Asset.PROPERTY_ID, "ilike", "id%");

var assetsFound = getAssetIndex().queryAssets(filter(criterion));

assertThat(assetsFound).isNotNull().hasSize(2);
}

@Test
@DisplayName("Query assets using the LIKE operator on a json value")
void likeJson() throws JsonProcessingException {
Expand Down
Loading