From 7f8c27ef6118d2ebf09f01ab1893971f9456bbc7 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sun, 10 Aug 2025 20:45:06 +0100 Subject: [PATCH 01/68] chore: include string match enum Signed-off-by: Otavio Santana --- .../org/eclipse/jnosql/communication/driver/StringMatch.java | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java diff --git a/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java b/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java new file mode 100644 index 000000000..f325fa0fb --- /dev/null +++ b/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java @@ -0,0 +1,4 @@ +package org.eclipse.jnosql.communication.driver; + +public class StringMatch { +} From 5b55c036450bf06453475a72ca1886e7e2d6926d Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sun, 10 Aug 2025 20:45:32 +0100 Subject: [PATCH 02/68] chore: include heeader at String match enum Signed-off-by: Otavio Santana --- .../jnosql/communication/driver/StringMatch.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java b/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java index f325fa0fb..aa9bf9c3f 100644 --- a/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java +++ b/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java @@ -1,3 +1,17 @@ +/* + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Otavio Santana + */ package org.eclipse.jnosql.communication.driver; public class StringMatch { From faf0307acbab705f904f513c10d6cb52ba4db448 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sun, 10 Aug 2025 20:46:21 +0100 Subject: [PATCH 03/68] feat: include the implementation on String match Signed-off-by: Otavio Santana --- .../communication/driver/StringMatch.java | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java b/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java index aa9bf9c3f..fa179e741 100644 --- a/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java +++ b/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java @@ -14,5 +14,39 @@ */ package org.eclipse.jnosql.communication.driver; -public class StringMatch { +import java.util.Objects; + +public enum StringMatch { + + DEFAULT { + @Override + public String apply(String value) { + return value; + } + }, + CONTAINS { + @Override + public String apply(String value) { + return "%" + value + "%"; + } + }, + STARTS_WITH { + @Override + public String apply(String value) { + return value + "%"; + } + }, + ENDS_WITH { + @Override + public String apply(String value) { + return "%" + value; + } + }; + + public abstract String apply(String value); + + public String format(String value) { + Objects.requireNonNull(value, "value cannot be null"); + return apply(value); + } } From fbb70453fd858a3f58a66ba583f90a6a5ebc5982 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sun, 10 Aug 2025 20:46:56 +0100 Subject: [PATCH 04/68] docs: include javadoc on spring match documentation Signed-off-by: Otavio Santana --- .../jnosql/communication/driver/StringMatch.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java b/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java index fa179e741..744f56c03 100644 --- a/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java +++ b/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java @@ -16,6 +16,20 @@ import java.util.Objects; + +/** + * Represents strategies for matching string values in database queries, + * typically for SQL {@code LIKE} clauses or NoSQL regex-like searches. + *

+ * Each constant defines a specific way to wrap the given value + * with wildcard symbols ({@code %}) to produce a matching pattern. + *

+ *

+ * Example usage: + *

{@code
+ * String pattern = StringMatch.CONTAINS.format("Ota"); // "%Ota%"
+ * }
+ */ public enum StringMatch { DEFAULT { From dbf5d3664df026ab35368b65a73b98fda22497eb Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sun, 10 Aug 2025 20:47:24 +0100 Subject: [PATCH 05/68] docs: enhance documentation on Stringmatch Signed-off-by: Otavio Santana --- .../communication/driver/StringMatch.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java b/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java index 744f56c03..b1380c932 100644 --- a/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java +++ b/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java @@ -32,24 +32,58 @@ */ public enum StringMatch { + /** + * Exact match. + *

+ * The given value will be used as-is, without adding any wildcards. + * For SQL, this corresponds to {@code column = 'value'}. + *

+ */ DEFAULT { @Override public String apply(String value) { return value; } }, + + /** + * Contains match. + *

+ * The given value will be wrapped with wildcards on both sides: + * {@code %value%}. For SQL, this corresponds to + * {@code column LIKE '%value%'}. + *

+ */ CONTAINS { @Override public String apply(String value) { return "%" + value + "%"; } }, + + /** + * Starts-with match. + *

+ * The given value will be followed by a wildcard: + * {@code value%}. For SQL, this corresponds to + * {@code column LIKE 'value%'}. + *

+ */ STARTS_WITH { @Override public String apply(String value) { return value + "%"; } }, + + /** + * Ends-with match. + *

+ * The given value will be preceded by a wildcard: + * {@code %value}. For SQL, this corresponds to + * {@code column LIKE '%value'}. + *

+ */ ENDS_WITH { @Override public String apply(String value) { @@ -57,10 +91,27 @@ public String apply(String value) { } }; + /** + * Applies the match strategy to the given value, producing a pattern string. + * + * @param value the value to be transformed into a pattern + * @return the pattern string, with wildcards applied according to the match strategy + */ public abstract String apply(String value); + /** + * Formats the given value by applying the match strategy. + *

+ * This method ensures the value is not {@code null} before applying the strategy. + *

+ * + * @param value the value to be transformed into a pattern + * @return the pattern string, with wildcards applied according to the match strategy + * @throws NullPointerException if {@code value} is {@code null} + */ public String format(String value) { Objects.requireNonNull(value, "value cannot be null"); return apply(value); } + } From 72a99cc9f9f55e84c7ed986467b7387eb0f6f17b Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Mon, 11 Aug 2025 20:01:54 +0100 Subject: [PATCH 06/68] test: initial structure on String match test Signed-off-by: Otavio Santana --- .../communication/driver/StringMatchTest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 jnosql-database-commons/src/test/java/org/eclipse/jnosql/communication/driver/StringMatchTest.java diff --git a/jnosql-database-commons/src/test/java/org/eclipse/jnosql/communication/driver/StringMatchTest.java b/jnosql-database-commons/src/test/java/org/eclipse/jnosql/communication/driver/StringMatchTest.java new file mode 100644 index 000000000..2f0fde397 --- /dev/null +++ b/jnosql-database-commons/src/test/java/org/eclipse/jnosql/communication/driver/StringMatchTest.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Otavio Santana + */ +package org.eclipse.jnosql.communication.driver; + +import static org.junit.jupiter.api.Assertions.*; + +class StringMatchTest { + +} \ No newline at end of file From 861e4884a1652f0b02cf191a2b0f3effaf1c56d5 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Mon, 11 Aug 2025 20:11:38 +0100 Subject: [PATCH 07/68] test: create stsring match test Signed-off-by: Otavio Santana --- .../communication/driver/StringMatchTest.java | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/jnosql-database-commons/src/test/java/org/eclipse/jnosql/communication/driver/StringMatchTest.java b/jnosql-database-commons/src/test/java/org/eclipse/jnosql/communication/driver/StringMatchTest.java index 2f0fde397..995ee5100 100644 --- a/jnosql-database-commons/src/test/java/org/eclipse/jnosql/communication/driver/StringMatchTest.java +++ b/jnosql-database-commons/src/test/java/org/eclipse/jnosql/communication/driver/StringMatchTest.java @@ -14,8 +14,58 @@ */ package org.eclipse.jnosql.communication.driver; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +import static org.assertj.core.api.Assertions.*; class StringMatchTest { + + @Test + @DisplayName("DEFAULT should return the exact input without wildcards") + void shouldReturnExactValueForDefault() { + String input = "Ota"; + String result = StringMatch.DEFAULT.format(input); + + assertThat(result).isEqualTo("Ota"); + } + + @Test + @DisplayName("CONTAINS should wrap input with % on both sides") + void shouldWrapWithWildcardsForContains() { + String input = "Ota"; + String result = StringMatch.CONTAINS.format(input); + + assertThat(result).isEqualTo("%Ota%"); + } + + @Test + @DisplayName("STARTS_WITH should append % to the input") + void shouldAppendPercentForStartsWith() { + String input = "Ota"; + String result = StringMatch.STARTS_WITH.format(input); + + assertThat(result).isEqualTo("Ota%"); + } + + @Test + @DisplayName("ENDS_WITH should prepend % to the input") + void shouldPrependPercentForEndsWith() { + String input = "Ota"; + String result = StringMatch.ENDS_WITH.format(input); + + assertThat(result).isEqualTo("%Ota"); + } + + @ParameterizedTest(name = "All strategies should reject null input: {0}") + @EnumSource(StringMatch.class) + @DisplayName("Null input should throw NullPointerException for every strategy") + void shouldRejectNullValuesWithNpe(StringMatch strategy) { + assertThatThrownBy(() -> strategy.format(null)) + .isInstanceOf(NullPointerException.class) + .hasMessage("value cannot be null"); + } } \ No newline at end of file From 7847c795f2f6e8c2446c0880823206ba463eb5ce Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Mon, 11 Aug 2025 20:52:03 +0100 Subject: [PATCH 08/68] feat: update query aql converter to support contains and start with Signed-off-by: Otavio Santana --- .../arangodb/communication/QueryAQLConverter.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/jnosql-arangodb/src/main/java/org/eclipse/jnosql/databases/arangodb/communication/QueryAQLConverter.java b/jnosql-arangodb/src/main/java/org/eclipse/jnosql/databases/arangodb/communication/QueryAQLConverter.java index 902f54074..89f9049a5 100644 --- a/jnosql-arangodb/src/main/java/org/eclipse/jnosql/databases/arangodb/communication/QueryAQLConverter.java +++ b/jnosql-arangodb/src/main/java/org/eclipse/jnosql/databases/arangodb/communication/QueryAQLConverter.java @@ -19,6 +19,7 @@ import jakarta.data.Sort; import org.eclipse.jnosql.communication.TypeReference; import org.eclipse.jnosql.communication.ValueUtil; +import org.eclipse.jnosql.communication.driver.StringMatch; import org.eclipse.jnosql.communication.semistructured.CriteriaCondition; import org.eclipse.jnosql.communication.semistructured.DeleteQuery; import org.eclipse.jnosql.communication.semistructured.Element; @@ -153,6 +154,15 @@ private static void definesCondition(CriteriaCondition condition, case LIKE: appendCondition(aql, params, entity, document, LIKE); return; + case CONTAINS: + appendCondition(aql, params, entity, Element.of(document.name(), StringMatch.CONTAINS.format(document.get(String.class))), LIKE); + return; + case STARTS_WITH: + appendCondition(aql, params, entity, Element.of(document.name(), StringMatch.STARTS_WITH.format(document.get(String.class))), LIKE); + return; + case ENDS_WITH: + appendCondition(aql, params, entity, Element.of(document.name(), StringMatch.ENDS_WITH.format(document.get(String.class))), LIKE); + return; case AND: for (CriteriaCondition dc : document.get(new TypeReference>() { From 08739c58aa2f49cb40e8b9e8aaae6667eae7e0f1 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Mon, 11 Aug 2025 20:52:29 +0100 Subject: [PATCH 09/68] chore: hide the apply method on string match Signed-off-by: Otavio Santana --- .../org/eclipse/jnosql/communication/driver/StringMatch.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java b/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java index b1380c932..6b4e9dc23 100644 --- a/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java +++ b/jnosql-database-commons/src/main/java/org/eclipse/jnosql/communication/driver/StringMatch.java @@ -97,7 +97,7 @@ public String apply(String value) { * @param value the value to be transformed into a pattern * @return the pattern string, with wildcards applied according to the match strategy */ - public abstract String apply(String value); + abstract String apply(String value); /** * Formats the given value by applying the match strategy. From be87404844401aaffcca7bf4061e5005b4f2adc1 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Mon, 11 Aug 2025 20:52:39 +0100 Subject: [PATCH 10/68] test: include find contains Signed-off-by: Otavio Santana --- .../ArangoDBDocumentManagerTest.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/jnosql-arangodb/src/test/java/org/eclipse/jnosql/databases/arangodb/communication/ArangoDBDocumentManagerTest.java b/jnosql-arangodb/src/test/java/org/eclipse/jnosql/databases/arangodb/communication/ArangoDBDocumentManagerTest.java index d578e0c50..8b134d79a 100644 --- a/jnosql-arangodb/src/test/java/org/eclipse/jnosql/databases/arangodb/communication/ArangoDBDocumentManagerTest.java +++ b/jnosql-arangodb/src/test/java/org/eclipse/jnosql/databases/arangodb/communication/ArangoDBDocumentManagerTest.java @@ -19,10 +19,12 @@ import org.assertj.core.api.SoftAssertions; import org.eclipse.jnosql.communication.TypeReference; import org.eclipse.jnosql.communication.semistructured.CommunicationEntity; +import org.eclipse.jnosql.communication.semistructured.CriteriaCondition; import org.eclipse.jnosql.communication.semistructured.DeleteQuery; import org.eclipse.jnosql.communication.semistructured.Element; import org.eclipse.jnosql.communication.semistructured.Elements; import org.eclipse.jnosql.communication.semistructured.SelectQuery; +import org.eclipse.jnosql.mapping.semistructured.MappingQuery; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -30,6 +32,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -404,6 +407,31 @@ void shouldFindBetween2() { }); } + @Test + void shouldFindContains() { + var entity = getEntity(); + + entityManager.insert(entity); + var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.contains(Element.of("name", + "liana")), COLLECTION_NAME, Collections.emptyList()); + + var result = entityManager.select(query).toList(); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(result).hasSize(1); + softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana"); + }); + } + + @Test + void shouldStartsWith() { + + } + + @Test + void shouldEndsWith() { + + } + private CommunicationEntity getEntity() { CommunicationEntity entity = CommunicationEntity.of(COLLECTION_NAME); Map map = new HashMap<>(); From 39c6f2f84853bf4f4ad4422c0bc9847406ae7263 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Mon, 11 Aug 2025 20:54:06 +0100 Subject: [PATCH 11/68] test: update test on arango db to support the new keyworlds Signed-off-by: Otavio Santana --- .../ArangoDBDocumentManagerTest.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/jnosql-arangodb/src/test/java/org/eclipse/jnosql/databases/arangodb/communication/ArangoDBDocumentManagerTest.java b/jnosql-arangodb/src/test/java/org/eclipse/jnosql/databases/arangodb/communication/ArangoDBDocumentManagerTest.java index 8b134d79a..8b3b5103c 100644 --- a/jnosql-arangodb/src/test/java/org/eclipse/jnosql/databases/arangodb/communication/ArangoDBDocumentManagerTest.java +++ b/jnosql-arangodb/src/test/java/org/eclipse/jnosql/databases/arangodb/communication/ArangoDBDocumentManagerTest.java @@ -413,7 +413,7 @@ void shouldFindContains() { entityManager.insert(entity); var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.contains(Element.of("name", - "liana")), COLLECTION_NAME, Collections.emptyList()); + "lia")), COLLECTION_NAME, Collections.emptyList()); var result = entityManager.select(query).toList(); SoftAssertions.assertSoftly(softly -> { @@ -424,12 +424,32 @@ void shouldFindContains() { @Test void shouldStartsWith() { + var entity = getEntity(); + + entityManager.insert(entity); + var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.startsWith(Element.of("name", + "Pol")), COLLECTION_NAME, Collections.emptyList()); + var result = entityManager.select(query).toList(); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(result).hasSize(1); + softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana"); + }); } @Test void shouldEndsWith() { + var entity = getEntity(); + + entityManager.insert(entity); + var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.endsWith(Element.of("name", + "ana")), COLLECTION_NAME, Collections.emptyList()); + var result = entityManager.select(query).toList(); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(result).hasSize(1); + softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana"); + }); } private CommunicationEntity getEntity() { From 297fa37f7761ced6d75b812258561cc86b826267 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Mon, 11 Aug 2025 20:55:17 +0100 Subject: [PATCH 12/68] chore: update arangodb driver to version 7.22.0 Signed-off-by: Otavio Santana --- jnosql-arangodb/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jnosql-arangodb/pom.xml b/jnosql-arangodb/pom.xml index bfbc8d589..96d87560b 100644 --- a/jnosql-arangodb/pom.xml +++ b/jnosql-arangodb/pom.xml @@ -29,7 +29,7 @@ The Eclipse JNoSQL layer to ArangoDB - 7.21.0 + 7.22.0 From 30b8b421b1a193a8f0e71bdd23e3417ca7d19906 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Mon, 11 Aug 2025 20:55:57 +0100 Subject: [PATCH 13/68] docs: update changelog to include arangodb info Signed-off-by: Otavio Santana --- CHANGELOG.adoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 929db2bd7..d46bdddb7 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -8,6 +8,10 @@ and this project adheres to https://semver.org/spec/v2.0.0.html[Semantic Version == [Unreleased] +=== Changed + +- Update ArangoDB driver to 7.22.0 + == [1.1.9] - 2025-07-30 === Fixed From faa2e29419977b3b879b7862e5593f1574704ba1 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Mon, 11 Aug 2025 20:56:51 +0100 Subject: [PATCH 14/68] docs: update changelog with info Signed-off-by: Otavio Santana --- CHANGELOG.adoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index d46bdddb7..901dca8ee 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -12,6 +12,10 @@ and this project adheres to https://semver.org/spec/v2.0.0.html[Semantic Version - Update ArangoDB driver to 7.22.0 +=== Added + +- Include support to Contains, StartsWith, EndsWith for NoSQL databases + == [1.1.9] - 2025-07-30 === Fixed From dccdb31b7c858df93bb59405dd751c7d79f11a27 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Mon, 11 Aug 2025 20:59:48 +0100 Subject: [PATCH 15/68] chore: update apache cassandra driver to 4.19.0 Signed-off-by: Otavio Santana --- jnosql-cassandra/pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jnosql-cassandra/pom.xml b/jnosql-cassandra/pom.xml index e18217802..91fd28b71 100644 --- a/jnosql-cassandra/pom.xml +++ b/jnosql-cassandra/pom.xml @@ -29,7 +29,7 @@ The Eclipse JNoSQL layer to Cassandra - 4.17.0 + 4.19.0 @@ -43,12 +43,12 @@ ${project.version} - com.datastax.oss + org.apache.cassandra java-driver-core ${casandra.driver.version} - com.datastax.oss + org.apache.cassandra java-driver-query-builder ${casandra.driver.version} From 31910a874369ad080ea9ec8233d8c23b8cc447ec Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Mon, 11 Aug 2025 21:00:21 +0100 Subject: [PATCH 16/68] docs: update description on changelog Signed-off-by: Otavio Santana --- CHANGELOG.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 901dca8ee..6486d5cef 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -11,6 +11,7 @@ and this project adheres to https://semver.org/spec/v2.0.0.html[Semantic Version === Changed - Update ArangoDB driver to 7.22.0 +- Update Apache Cassandra driver to 4.19.0 === Added From cae714aeb6e030ba75cb66128139034e90dd4c15 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Mon, 11 Aug 2025 21:01:30 +0100 Subject: [PATCH 17/68] chore: update couchbase on version 3.9.0 Signed-off-by: Otavio Santana --- jnosql-couchbase/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jnosql-couchbase/pom.xml b/jnosql-couchbase/pom.xml index be71105b4..c136526c6 100644 --- a/jnosql-couchbase/pom.xml +++ b/jnosql-couchbase/pom.xml @@ -49,7 +49,7 @@ com.couchbase.client java-client - 3.8.3 + 3.9.0 org.testcontainers From 2a58fda5b967cedf33fe77e3faddfc1356a22b57 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Mon, 11 Aug 2025 21:01:53 +0100 Subject: [PATCH 18/68] docs: update changelog on couchbase Signed-off-by: Otavio Santana --- CHANGELOG.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 6486d5cef..b17335803 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -12,6 +12,7 @@ and this project adheres to https://semver.org/spec/v2.0.0.html[Semantic Version - Update ArangoDB driver to 7.22.0 - Update Apache Cassandra driver to 4.19.0 +- Update Couchbase driver to 3.9.0 === Added From 516bc498b1434c1f9eb48aa187d5a5f36fe973fd Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Mon, 11 Aug 2025 21:05:57 +0100 Subject: [PATCH 19/68] feat: update n1query builder Signed-off-by: Otavio Santana --- .../couchbase/communication/N1QLBuilder.java | 10 ++++ .../CouchbaseDocumentManagerTest.java | 48 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/jnosql-couchbase/src/main/java/org/eclipse/jnosql/databases/couchbase/communication/N1QLBuilder.java b/jnosql-couchbase/src/main/java/org/eclipse/jnosql/databases/couchbase/communication/N1QLBuilder.java index 24a1317c0..b6be20983 100644 --- a/jnosql-couchbase/src/main/java/org/eclipse/jnosql/databases/couchbase/communication/N1QLBuilder.java +++ b/jnosql-couchbase/src/main/java/org/eclipse/jnosql/databases/couchbase/communication/N1QLBuilder.java @@ -17,6 +17,7 @@ import com.couchbase.client.java.json.JsonObject; import jakarta.data.Direction; import org.eclipse.jnosql.communication.TypeReference; +import org.eclipse.jnosql.communication.driver.StringMatch; import org.eclipse.jnosql.communication.semistructured.CriteriaCondition; import org.eclipse.jnosql.communication.semistructured.Element; import org.eclipse.jnosql.communication.semistructured.SelectQuery; @@ -113,6 +114,15 @@ private void condition(CriteriaCondition condition, StringBuilder n1ql, JsonObje case LIKE: predicate(n1ql, " LIKE ", document, params); return; + case CONTAINS: + predicate(n1ql, " LIKE ", Element.of(document.name(), StringMatch.CONTAINS.format(document.get(String.class))), params); + return; + case STARTS_WITH: + predicate(n1ql, " LIKE ", Element.of(document.name(), StringMatch.STARTS_WITH.format(document.get(String.class))), params); + return; + case ENDS_WITH: + predicate(n1ql, " LIKE ", Element.of(document.name(), StringMatch.ENDS_WITH.format(document.get(String.class))), params); + return; case NOT: n1ql.append(" NOT "); condition(document.get(CriteriaCondition.class), n1ql, params, ids); diff --git a/jnosql-couchbase/src/test/java/org/eclipse/jnosql/databases/couchbase/communication/CouchbaseDocumentManagerTest.java b/jnosql-couchbase/src/test/java/org/eclipse/jnosql/databases/couchbase/communication/CouchbaseDocumentManagerTest.java index 1c1de8ea8..a53457ebd 100644 --- a/jnosql-couchbase/src/test/java/org/eclipse/jnosql/databases/couchbase/communication/CouchbaseDocumentManagerTest.java +++ b/jnosql-couchbase/src/test/java/org/eclipse/jnosql/databases/couchbase/communication/CouchbaseDocumentManagerTest.java @@ -22,16 +22,19 @@ import org.eclipse.jnosql.communication.TypeReference; import org.eclipse.jnosql.communication.keyvalue.BucketManager; import org.eclipse.jnosql.communication.semistructured.CommunicationEntity; +import org.eclipse.jnosql.communication.semistructured.CriteriaCondition; import org.eclipse.jnosql.communication.semistructured.DeleteQuery; import org.eclipse.jnosql.communication.semistructured.Element; import org.eclipse.jnosql.communication.semistructured.Elements; import org.eclipse.jnosql.communication.semistructured.SelectQuery; +import org.eclipse.jnosql.mapping.semistructured.MappingQuery; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfSystemProperty; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -294,6 +297,51 @@ void shouldUpdateNull(){ }); } + @Test + void shouldFindContains() { + var entity = getEntity(); + + entityManager.insert(entity); + var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.contains(Element.of("name", + "lia")), COLLECTION_PERSON_NAME, Collections.emptyList()); + + var result = entityManager.select(query).toList(); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(result).hasSize(1); + softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana"); + }); + } + + @Test + void shouldStartsWith() { + var entity = getEntity(); + + entityManager.insert(entity); + var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.startsWith(Element.of("name", + "Pol")), COLLECTION_PERSON_NAME, Collections.emptyList()); + + var result = entityManager.select(query).toList(); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(result).hasSize(1); + softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana"); + }); + } + + @Test + void shouldEndsWith() { + var entity = getEntity(); + + entityManager.insert(entity); + var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.endsWith(Element.of("name", + "ana")), COLLECTION_PERSON_NAME, Collections.emptyList()); + + var result = entityManager.select(query).toList(); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(result).hasSize(1); + softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana"); + }); + } + private CommunicationEntity getEntity() { CommunicationEntity entity = CommunicationEntity.of(COLLECTION_PERSON_NAME); Map map = new HashMap<>(); From fbbc9305e20da950d590d74179799be851cd3a34 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Mon, 11 Aug 2025 21:11:46 +0100 Subject: [PATCH 20/68] feat: include support with contains on end with on ES Signed-off-by: Otavio Santana --- .../communication/QueryConverter.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/jnosql-elasticsearch/src/main/java/org/eclipse/jnosql/databases/elasticsearch/communication/QueryConverter.java b/jnosql-elasticsearch/src/main/java/org/eclipse/jnosql/databases/elasticsearch/communication/QueryConverter.java index 23c381b29..f3ee9ea34 100644 --- a/jnosql-elasticsearch/src/main/java/org/eclipse/jnosql/databases/elasticsearch/communication/QueryConverter.java +++ b/jnosql-elasticsearch/src/main/java/org/eclipse/jnosql/databases/elasticsearch/communication/QueryConverter.java @@ -29,6 +29,7 @@ import org.eclipse.jnosql.communication.Condition; import org.eclipse.jnosql.communication.TypeReference; import org.eclipse.jnosql.communication.ValueUtil; +import org.eclipse.jnosql.communication.driver.StringMatch; import org.eclipse.jnosql.communication.semistructured.CriteriaCondition; import org.eclipse.jnosql.communication.semistructured.Element; import org.eclipse.jnosql.communication.semistructured.SelectQuery; @@ -160,6 +161,25 @@ private static Query.Builder getCondition(IndexMappingRecord indexMappingRecord, .query(document.value().get(String.class)) .allowLeadingWildcard(true) .fields(fieldName))); + case CONTAINS: + return (Query.Builder) new Query.Builder() + .queryString(QueryStringQuery.of(rq -> rq + .query(StringMatch.CONTAINS.format(document.value().get(String.class))) + .allowLeadingWildcard(true) + .fields(fieldName))); + case STARTS_WITH: + return (Query.Builder) new Query.Builder() + .queryString(QueryStringQuery.of(rq -> rq + .query(StringMatch.STARTS_WITH.format(document.value().get(String.class))) + .allowLeadingWildcard(true) + .fields(fieldName))); + case ENDS_WITH: + return (Query.Builder) new Query.Builder() + .queryString(QueryStringQuery.of(rq -> rq + .query(StringMatch.ENDS_WITH.format(document.value().get(String.class))) + .allowLeadingWildcard(true) + .fields(fieldName))); + case IN: return (Query.Builder) ValueUtil.convertToList(document.value()) .stream() From e25fbdf627b47f0a24d0215b6374eff4e13294d7 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Mon, 11 Aug 2025 21:13:27 +0100 Subject: [PATCH 21/68] feat: include conditions to mongodb Signed-off-by: Otavio Santana --- .../communication/DocumentQueryConversor.java | 2 +- .../MongoDBDocumentManagerTest.java | 47 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/jnosql-mongodb/src/main/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConversor.java b/jnosql-mongodb/src/main/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConversor.java index 21840cc2a..6f62d703b 100644 --- a/jnosql-mongodb/src/main/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConversor.java +++ b/jnosql-mongodb/src/main/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConversor.java @@ -75,7 +75,7 @@ public static Bson convert(CriteriaCondition condition) { } default -> throw new UnsupportedOperationException("The condition " + condition.condition() - + " is not supported from mongoDB diana driver"); + + " is not supported from Eclipse JNoSQL driver"); }; } diff --git a/jnosql-mongodb/src/test/java/org/eclipse/jnosql/databases/mongodb/communication/MongoDBDocumentManagerTest.java b/jnosql-mongodb/src/test/java/org/eclipse/jnosql/databases/mongodb/communication/MongoDBDocumentManagerTest.java index 77a80f3bb..1ca93b5ad 100644 --- a/jnosql-mongodb/src/test/java/org/eclipse/jnosql/databases/mongodb/communication/MongoDBDocumentManagerTest.java +++ b/jnosql-mongodb/src/test/java/org/eclipse/jnosql/databases/mongodb/communication/MongoDBDocumentManagerTest.java @@ -18,12 +18,14 @@ import org.assertj.core.api.SoftAssertions; import org.eclipse.jnosql.communication.TypeReference; import org.eclipse.jnosql.communication.semistructured.CommunicationEntity; +import org.eclipse.jnosql.communication.semistructured.CriteriaCondition; import org.eclipse.jnosql.communication.semistructured.DatabaseManager; import org.eclipse.jnosql.communication.semistructured.DeleteQuery; import org.eclipse.jnosql.communication.semistructured.Element; import org.eclipse.jnosql.communication.semistructured.Elements; import org.eclipse.jnosql.communication.semistructured.SelectQuery; import org.eclipse.jnosql.databases.mongodb.communication.type.Money; +import org.eclipse.jnosql.mapping.semistructured.MappingQuery; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -627,6 +629,51 @@ void shouldInsertUUID() { } + @Test + void shouldFindContains() { + var entity = getEntity(); + + entityManager.insert(entity); + var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.contains(Element.of("name", + "lia")), COLLECTION_NAME, Collections.emptyList()); + + var result = entityManager.select(query).toList(); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(result).hasSize(1); + softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana"); + }); + } + + @Test + void shouldStartsWith() { + var entity = getEntity(); + + entityManager.insert(entity); + var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.startsWith(Element.of("name", + "Pol")), COLLECTION_NAME, Collections.emptyList()); + + var result = entityManager.select(query).toList(); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(result).hasSize(1); + softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana"); + }); + } + + @Test + void shouldEndsWith() { + var entity = getEntity(); + + entityManager.insert(entity); + var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.endsWith(Element.of("name", + "ana")), COLLECTION_NAME, Collections.emptyList()); + + var result = entityManager.select(query).toList(); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(result).hasSize(1); + softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana"); + }); + } + private CommunicationEntity createDocumentList() { CommunicationEntity entity = CommunicationEntity.of("AppointmentBook"); From ed2a9e204aba1d94fea36c52a153196b940224b3 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Mon, 11 Aug 2025 21:21:04 +0100 Subject: [PATCH 22/68] feat: fix like on colleciton name on mongodb Signed-off-by: Otavio Santana --- .../communication/DocumentQueryConversor.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/jnosql-mongodb/src/main/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConversor.java b/jnosql-mongodb/src/main/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConversor.java index 6f62d703b..1d8820d8c 100644 --- a/jnosql-mongodb/src/main/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConversor.java +++ b/jnosql-mongodb/src/main/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConversor.java @@ -80,11 +80,24 @@ public static Bson convert(CriteriaCondition condition) { } public static String prepareRegexValue(String rawData) { - if (rawData == null) - return "^$"; - return "^" + rawData - .replaceAll("_", ".{1}") - .replaceAll("%", ".{1,}"); + if (rawData == null) { + return "(?!)"; // matches nothing + } + StringBuilder sb = new StringBuilder("^"); + for (char c : rawData.toCharArray()) { + switch (c) { + case '%': // SQL LIKE: zero or more + sb.append(".*"); + break; + case '_': // SQL LIKE: exactly one + sb.append('.'); + break; + default: // escape all regex meta characters + sb.append(Pattern.quote(String.valueOf(c))); + } + } + sb.append('$'); + return sb.toString(); } } From 2d87330b0467a3490b86f43fdc3c1101fe780e17 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Mon, 11 Aug 2025 21:22:25 +0100 Subject: [PATCH 23/68] feaet: include new conditions to mongodb Signed-off-by: Otavio Santana --- .../communication/DocumentQueryConversor.java | 36 ++++++++++++------- .../MongoDBDocumentManagerTest.java | 2 +- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/jnosql-mongodb/src/main/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConversor.java b/jnosql-mongodb/src/main/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConversor.java index 1d8820d8c..bea807b9a 100644 --- a/jnosql-mongodb/src/main/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConversor.java +++ b/jnosql-mongodb/src/main/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConversor.java @@ -56,6 +56,9 @@ public static Bson convert(CriteriaCondition condition) { yield Filters.nor(convert(criteriaCondition)); } case LIKE -> Filters.regex(document.name(), Pattern.compile(prepareRegexValue(value.toString()))); + case CONTAINS -> Filters.regex(document.name(), Pattern.compile(prepareContains(value.toString()))); + case STARTS_WITH -> Filters.regex(document.name(), Pattern.compile(prepareStartsWith(value.toString()))); + case ENDS_WITH -> Filters.regex(document.name(), Pattern.compile(prepareEndsWith(value.toString()))); case AND -> { List andConditions = condition.element().value().get(new TypeReference<>() { }); @@ -79,25 +82,34 @@ public static Bson convert(CriteriaCondition condition) { }; } - public static String prepareRegexValue(String rawData) { - if (rawData == null) { - return "(?!)"; // matches nothing + static String prepareRegexValue(String likePattern) { + if (likePattern == null) { + return "(?!)"; // never matches } StringBuilder sb = new StringBuilder("^"); - for (char c : rawData.toCharArray()) { + for (char c : likePattern.toCharArray()) { switch (c) { - case '%': // SQL LIKE: zero or more - sb.append(".*"); - break; - case '_': // SQL LIKE: exactly one - sb.append('.'); - break; - default: // escape all regex meta characters - sb.append(Pattern.quote(String.valueOf(c))); + case '%': sb.append(".*"); break; // zero or more + case '_': sb.append('.'); break; // exactly one + default: sb.append(Pattern.quote(String.valueOf(c))); } } sb.append('$'); return sb.toString(); } + static String prepareStartsWith(String raw) { + if (raw == null) return "(?!)"; + return "^" + Pattern.quote(raw) + ".*$"; + } + static String prepareEndsWith(String raw) { + if (raw == null) return "(?!)"; + return "^.*" + Pattern.quote(raw) + "$"; + } + + static String prepareContains(String raw) { + if (raw == null) return "(?!)"; + return "^.*" + Pattern.quote(raw) + ".*$"; + } + } diff --git a/jnosql-mongodb/src/test/java/org/eclipse/jnosql/databases/mongodb/communication/MongoDBDocumentManagerTest.java b/jnosql-mongodb/src/test/java/org/eclipse/jnosql/databases/mongodb/communication/MongoDBDocumentManagerTest.java index 1ca93b5ad..46b62c4ba 100644 --- a/jnosql-mongodb/src/test/java/org/eclipse/jnosql/databases/mongodb/communication/MongoDBDocumentManagerTest.java +++ b/jnosql-mongodb/src/test/java/org/eclipse/jnosql/databases/mongodb/communication/MongoDBDocumentManagerTest.java @@ -249,7 +249,7 @@ void shouldFindDocumentLike() { List entities = StreamSupport.stream(entitiesSaved.spliterator(), false).toList(); var query = select().from(COLLECTION_NAME) - .where("name").like("Lu") + .where("name").like("Lu%") .and("type").eq("V") .build(); From 86c59b299bc6b0207204bf4e33181f29ecac2d39 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Tue, 12 Aug 2025 16:32:22 +0100 Subject: [PATCH 24/68] feat: include n4oj library Signed-off-by: Otavio Santana --- .../Neo4JDatabaseManagerTest.java | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/jnosql-neo4j/src/test/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JDatabaseManagerTest.java b/jnosql-neo4j/src/test/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JDatabaseManagerTest.java index d549779d9..83d9f5cdc 100644 --- a/jnosql-neo4j/src/test/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JDatabaseManagerTest.java +++ b/jnosql-neo4j/src/test/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JDatabaseManagerTest.java @@ -19,13 +19,16 @@ import net.datafaker.Faker; import org.assertj.core.api.SoftAssertions; import org.eclipse.jnosql.communication.semistructured.CommunicationEntity; +import org.eclipse.jnosql.communication.semistructured.CriteriaCondition; import org.eclipse.jnosql.communication.semistructured.Element; import org.eclipse.jnosql.communication.semistructured.Elements; +import org.eclipse.jnosql.mapping.semistructured.MappingQuery; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfSystemProperty; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -607,6 +610,51 @@ void shouldCreateEdgeWithProperties() { }); } + @Test + void shouldFindContains() { + var entity = getEntity(); + + entityManager.insert(entity); + var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.contains(Element.of("name", + "lia")), COLLECTION_NAME, Collections.emptyList()); + + var result = entityManager.select(query).toList(); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(result).hasSize(1); + softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana"); + }); + } + + @Test + void shouldStartsWith() { + var entity = getEntity(); + + entityManager.insert(entity); + var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.startsWith(Element.of("name", + "Pol")), COLLECTION_NAME, Collections.emptyList()); + + var result = entityManager.select(query).toList(); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(result).hasSize(1); + softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana"); + }); + } + + @Test + void shouldEndsWith() { + var entity = getEntity(); + + entityManager.insert(entity); + var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.endsWith(Element.of("name", + "ana")), COLLECTION_NAME, Collections.emptyList()); + + var result = entityManager.select(query).toList(); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(result).hasSize(1); + softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana"); + }); + } + private CommunicationEntity getEntity() { Faker faker = new Faker(); From b6da230c2848c8a8f7e20565c5741639aff96437 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Tue, 12 Aug 2025 16:33:32 +0100 Subject: [PATCH 25/68] chore: update neo4j library to 5.28.9 Signed-off-by: Otavio Santana --- CHANGELOG.adoc | 1 + jnosql-neo4j/pom.xml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index b17335803..8a4edfc49 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -13,6 +13,7 @@ and this project adheres to https://semver.org/spec/v2.0.0.html[Semantic Version - Update ArangoDB driver to 7.22.0 - Update Apache Cassandra driver to 4.19.0 - Update Couchbase driver to 3.9.0 +- Update Neo4J driver to 5.28.9 === Added diff --git a/jnosql-neo4j/pom.xml b/jnosql-neo4j/pom.xml index cc634cf6f..559d39614 100644 --- a/jnosql-neo4j/pom.xml +++ b/jnosql-neo4j/pom.xml @@ -27,7 +27,7 @@ JNoSQL Neo4J Driver - 5.28.5 + 5.28.9 From 368ceb139320d185f0b374ab298df12956a376ca Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Tue, 12 Aug 2025 16:41:25 +0100 Subject: [PATCH 26/68] feat: include condition on Signed-off-by: Otavio Santana --- .../databases/neo4j/communication/Neo4JQueryBuilder.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JQueryBuilder.java b/jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JQueryBuilder.java index 195d12c6d..36ce69d83 100644 --- a/jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JQueryBuilder.java +++ b/jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JQueryBuilder.java @@ -157,6 +157,9 @@ private String getConditionOperator(Condition condition) { case IN -> "IN"; case AND -> "AND"; case OR -> "OR"; + case STARTS_WITH -> "STARTS WITH"; + case ENDS_WITH -> "ENDS WITH"; + case CONTAINS -> "CONTAINS"; default -> throw new CommunicationException("Unsupported operator: " + condition); }; } From 4cf8a2668ee91827ba261943b2e5469b5fb3c7f7 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Tue, 12 Aug 2025 16:41:50 +0100 Subject: [PATCH 27/68] feat: include conditions on neo4jquery builder Signed-off-by: Otavio Santana --- .../databases/neo4j/communication/Neo4JQueryBuilder.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JQueryBuilder.java b/jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JQueryBuilder.java index 36ce69d83..4acf13ad1 100644 --- a/jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JQueryBuilder.java +++ b/jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JQueryBuilder.java @@ -106,6 +106,9 @@ private void createWhereClause(StringBuilder cypher, CriteriaCondition condition case LESSER_THAN: case LESSER_EQUALS_THAN: case LIKE: + case STARTS_WITH: + case ENDS_WITH: + case CONTAINS: case IN: String paramName = INTERNAL_ID.equals(fieldName) ? "id" : fieldName; // Ensure valid parameter name parameters.put(paramName, element.get()); @@ -121,7 +124,8 @@ private void createWhereClause(StringBuilder cypher, CriteriaCondition condition case AND: case OR: cypher.append("("); - List conditions = element.get(new TypeReference<>() {}); + List conditions = element.get(new TypeReference<>() { + }); for (int index = 0; index < conditions.size(); index++) { if (index > 0) { cypher.append(" ").append(getConditionOperator(condition.condition())).append(" "); From c2ec5037ef5c3e3d376b72cd7e7e3cef8762351d Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Tue, 12 Aug 2025 16:43:27 +0100 Subject: [PATCH 28/68] feat: include Neo4j database manager Signed-off-by: Otavio Santana --- .../neo4j/communication/Neo4JDatabaseManagerTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jnosql-neo4j/src/test/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JDatabaseManagerTest.java b/jnosql-neo4j/src/test/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JDatabaseManagerTest.java index 83d9f5cdc..3af5e93d4 100644 --- a/jnosql-neo4j/src/test/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JDatabaseManagerTest.java +++ b/jnosql-neo4j/src/test/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JDatabaseManagerTest.java @@ -613,7 +613,7 @@ void shouldCreateEdgeWithProperties() { @Test void shouldFindContains() { var entity = getEntity(); - + entity.add("name", "Poliana"); entityManager.insert(entity); var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.contains(Element.of("name", "lia")), COLLECTION_NAME, Collections.emptyList()); @@ -628,7 +628,7 @@ void shouldFindContains() { @Test void shouldStartsWith() { var entity = getEntity(); - + entity.add("name", "Poliana"); entityManager.insert(entity); var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.startsWith(Element.of("name", "Pol")), COLLECTION_NAME, Collections.emptyList()); @@ -643,7 +643,7 @@ void shouldStartsWith() { @Test void shouldEndsWith() { var entity = getEntity(); - + entity.add("name", "Poliana"); entityManager.insert(entity); var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.endsWith(Element.of("name", "ana")), COLLECTION_NAME, Collections.emptyList()); From af37dd4b51fbecd6dc05d1aae5834ef2ac8827cc Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Tue, 12 Aug 2025 16:58:35 +0100 Subject: [PATCH 29/68] feat: update neo4jquery builder Signed-off-by: Otavio Santana --- .../neo4j/communication/Neo4JQueryBuilder.java | 12 +++++++++--- .../communication/Neo4JDatabaseManagerTest.java | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JQueryBuilder.java b/jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JQueryBuilder.java index 4acf13ad1..1280cbcc4 100644 --- a/jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JQueryBuilder.java +++ b/jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JQueryBuilder.java @@ -111,7 +111,7 @@ private void createWhereClause(StringBuilder cypher, CriteriaCondition condition case CONTAINS: case IN: String paramName = INTERNAL_ID.equals(fieldName) ? "id" : fieldName; // Ensure valid parameter name - parameters.put(paramName, element.get()); + parameters.put(paramName, value(element.get(), condition.condition())); cypher.append(queryField).append(" ") .append(getConditionOperator(condition.condition())) .append(" $").append(paramName); @@ -139,6 +139,13 @@ private void createWhereClause(StringBuilder cypher, CriteriaCondition condition } } + private Object value(Object value, Condition condition) { + if(Condition.LIKE.equals(condition)) { + return toCypherRegex(value.toString()); + } + return value; + } + private String translateField(String field) { if (INTERNAL_ID.equals(field)) { return "elementId(e)"; @@ -149,7 +156,6 @@ private String translateField(String field) { return "e." + field; } - private String getConditionOperator(Condition condition) { return switch (condition) { case EQUALS -> "="; @@ -157,7 +163,7 @@ private String getConditionOperator(Condition condition) { case GREATER_EQUALS_THAN -> ">="; case LESSER_THAN -> "<"; case LESSER_EQUALS_THAN -> "<="; - case LIKE -> "CONTAINS"; + case LIKE -> "=~"; case IN -> "IN"; case AND -> "AND"; case OR -> "OR"; diff --git a/jnosql-neo4j/src/test/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JDatabaseManagerTest.java b/jnosql-neo4j/src/test/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JDatabaseManagerTest.java index 3af5e93d4..2a83bcc62 100644 --- a/jnosql-neo4j/src/test/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JDatabaseManagerTest.java +++ b/jnosql-neo4j/src/test/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JDatabaseManagerTest.java @@ -321,7 +321,7 @@ void shouldSelectLike() { var entity = getEntity(); entity.add("name", "Ada Lovelace"); entityManager.insert(entity); - var query = select().from(COLLECTION_NAME).where("name").like("Love").build(); + var query = select().from(COLLECTION_NAME).where("name").like("%Love%").build(); var entities = entityManager.select(query).toList(); SoftAssertions.assertSoftly(softly -> { softly.assertThat(entities).hasSize(1); From ab395bda2c89c8c9c37a58192361452096ecf6e9 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Tue, 12 Aug 2025 17:03:05 +0100 Subject: [PATCH 30/68] feat: include liketo cypher reger Signed-off-by: Otavio Santana --- .../communication/LikeToCypherRegex.java | 50 +++++++++++++++++++ .../communication/Neo4JQueryBuilder.java | 2 +- 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/LikeToCypherRegex.java diff --git a/jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/LikeToCypherRegex.java b/jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/LikeToCypherRegex.java new file mode 100644 index 000000000..a9f29ae44 --- /dev/null +++ b/jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/LikeToCypherRegex.java @@ -0,0 +1,50 @@ +/* + * + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Otavio Santana + * + */ +package org.eclipse.jnosql.databases.neo4j.communication; + +import java.util.regex.Pattern; + +enum LikeToCypherRegex { + INSTANCE; + + public String toCypherRegex(String like) { + if (like == null) { + return "(?!)"; + } + StringBuilder regex = new StringBuilder(like.length() + 8); + StringBuilder lit = new StringBuilder(); + + regex.append('^'); + for (int i = 0; i < like.length(); i++) { + char c = like.charAt(i); + if (c == '%' || c == '_') { + if (!lit.isEmpty()) { + regex.append(Pattern.quote(lit.toString())); + lit.setLength(0); + } + regex.append(c == '%' ? ".*" : "."); + } else { + lit.append(c); + } + } + if (!lit.isEmpty()) { + regex.append(Pattern.quote(lit.toString())); + } + regex.append('$'); + return regex.toString(); + } +} diff --git a/jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JQueryBuilder.java b/jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JQueryBuilder.java index 1280cbcc4..548f673d6 100644 --- a/jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JQueryBuilder.java +++ b/jnosql-neo4j/src/main/java/org/eclipse/jnosql/databases/neo4j/communication/Neo4JQueryBuilder.java @@ -141,7 +141,7 @@ private void createWhereClause(StringBuilder cypher, CriteriaCondition condition private Object value(Object value, Condition condition) { if(Condition.LIKE.equals(condition)) { - return toCypherRegex(value.toString()); + return LikeToCypherRegex.INSTANCE.toCypherRegex(value.toString()); } return value; } From b0ed392cca7efaa5b94ffcb9a94ffa6226c443d7 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Tue, 12 Aug 2025 17:06:57 +0100 Subject: [PATCH 31/68] test: update like cypher regex Signed-off-by: Otavio Santana --- .../communication/LikeToCypherRegexTest.java | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 jnosql-neo4j/src/test/java/org/eclipse/jnosql/databases/neo4j/communication/LikeToCypherRegexTest.java diff --git a/jnosql-neo4j/src/test/java/org/eclipse/jnosql/databases/neo4j/communication/LikeToCypherRegexTest.java b/jnosql-neo4j/src/test/java/org/eclipse/jnosql/databases/neo4j/communication/LikeToCypherRegexTest.java new file mode 100644 index 000000000..68dd80073 --- /dev/null +++ b/jnosql-neo4j/src/test/java/org/eclipse/jnosql/databases/neo4j/communication/LikeToCypherRegexTest.java @@ -0,0 +1,85 @@ +/* + * + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Otavio Santana + * + */ +package org.eclipse.jnosql.databases.neo4j.communication; + + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.assertj.core.api.Assertions.*; + +class LikeToCypherRegexTest { + + + @ParameterizedTest(name = "LIKE \"{0}\" -> regex \"{1}\"") + @CsvSource({ + // contains / starts / ends + "'%Ota%', '^.*\\QOta\\E.*$'", + "'Ota%', '^\\QOta\\E.*$'", + "'%Ota', '^.*\\QOta\\E$'", + // exact (no wildcards) + "'Ota', '^\\QOta\\E$'", + // single-char wildcard + "'Ot_', '^\\QOt\\E.$'", + // mixed case with both _ and % + "'_%ta%', '^..*\\Qta\\E.*$'" + }) + @DisplayName("Converts SQL LIKE to anchored Cypher regex") + void shouldConvertSqlLikeToAnchoredRegex(String like, String expectedRegex) { + String actual = LikeToCypherRegex.INSTANCE.toCypherRegex(like); + assertThat(actual).isEqualTo(expectedRegex); + } + + @Test + @DisplayName("Escapes regex metacharacters in literals") + void shouldEscapeRegexMetacharacters() { + // Input contains regex metas: . ^ $ ( ) [ ] { } + ? * | \ + String like = "%a.^$()[]{}+?*|\\b%"; + String regex = LikeToCypherRegex.INSTANCE.toCypherRegex(like); + + assertThat(regex) + .startsWith("^.*") + .endsWith(".*$") + // The literal run should be quoted as one block + .contains("\\Qa.^$()[]{}+?*|\\b\\E"); + } + + @Test + @DisplayName("Returns never-matching regex for null") + void shouldReturnNeverMatchingForNull() { + String regex = LikeToCypherRegex.INSTANCE.toCypherRegex(null); + assertThat(regex).isEqualTo("(?!)"); + } + + @Test + @DisplayName("Handles empty string as exact empty match") + void shouldHandleEmptyString() { + String regex = LikeToCypherRegex.INSTANCE.toCypherRegex(""); + assertThat(regex).isEqualTo("^$"); // not "^\\Q\\E$" + } + + @Test + @DisplayName("Handles only wildcards") + void shouldHandleOnlyWildcards() { + assertThat(LikeToCypherRegex.INSTANCE.toCypherRegex("%")).isEqualTo("^.*$"); + assertThat(LikeToCypherRegex.INSTANCE.toCypherRegex("%%")).isEqualTo("^.*.*$"); + assertThat(LikeToCypherRegex.INSTANCE.toCypherRegex("_")).isEqualTo("^.$"); + assertThat(LikeToCypherRegex.INSTANCE.toCypherRegex("__")).isEqualTo("^..$"); + } +} \ No newline at end of file From 40ca408a44bfa4e6b12c8bff24698efdd7828a27 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Tue, 12 Aug 2025 17:08:55 +0100 Subject: [PATCH 32/68] feat: update orientdb query Signed-off-by: Otavio Santana --- jnosql-orientdb/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jnosql-orientdb/pom.xml b/jnosql-orientdb/pom.xml index a9aa1964a..4662c2b20 100644 --- a/jnosql-orientdb/pom.xml +++ b/jnosql-orientdb/pom.xml @@ -35,7 +35,7 @@ com.orientechnologies orientdb-graphdb - 3.2.42 + 3.2.43 ${project.groupId} From 91044b526357121089a6683f897da361f5bd62e5 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Tue, 12 Aug 2025 17:11:18 +0100 Subject: [PATCH 33/68] docs: update changelog version on orientdb version Signed-off-by: Otavio Santana --- CHANGELOG.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 8a4edfc49..0ac6bc7ac 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -14,6 +14,7 @@ and this project adheres to https://semver.org/spec/v2.0.0.html[Semantic Version - Update Apache Cassandra driver to 4.19.0 - Update Couchbase driver to 3.9.0 - Update Neo4J driver to 5.28.9 +- Update OrientDB driver to 3.2.43 === Added From a2dfec102622897362d6d261480ec3e8e4dd0b19 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Tue, 12 Aug 2025 17:13:37 +0100 Subject: [PATCH 34/68] feat: update and include new conditions on orientedb Signed-off-by: Otavio Santana --- .../orientdb/communication/QueryOSQLConverter.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/jnosql-orientdb/src/main/java/org/eclipse/jnosql/databases/orientdb/communication/QueryOSQLConverter.java b/jnosql-orientdb/src/main/java/org/eclipse/jnosql/databases/orientdb/communication/QueryOSQLConverter.java index 09a4ceb56..95e0a754e 100644 --- a/jnosql-orientdb/src/main/java/org/eclipse/jnosql/databases/orientdb/communication/QueryOSQLConverter.java +++ b/jnosql-orientdb/src/main/java/org/eclipse/jnosql/databases/orientdb/communication/QueryOSQLConverter.java @@ -21,6 +21,7 @@ import jakarta.data.Sort; import org.eclipse.jnosql.communication.TypeReference; import org.eclipse.jnosql.communication.ValueUtil; +import org.eclipse.jnosql.communication.driver.StringMatch; import org.eclipse.jnosql.communication.semistructured.CriteriaCondition; import org.eclipse.jnosql.communication.semistructured.Element; import org.eclipse.jnosql.communication.semistructured.SelectQuery; @@ -98,6 +99,16 @@ private static void definesCondition(CriteriaCondition condition, StringBuilder case LIKE: appendCondition(query, params, document, LIKE, ids); return; + case STARTS_WITH: + appendCondition(query, params, Element.of(document.name(), StringMatch.STARTS_WITH.format(document.get(String.class))), LIKE, ids); + return; + case CONTAINS: + appendCondition(query, params, Element.of(document.name(), StringMatch.CONTAINS.format(document.get(String.class))), LIKE, ids); + return; + case ENDS_WITH: + appendCondition(query, params, Element.of(document.name(), StringMatch.ENDS_WITH.format(document.get(String.class))), LIKE, ids); + return; + case AND: for (CriteriaCondition dc : document.get(new TypeReference>() { })) { From a8fa11760ab6e607a0bd39ba9f3f620ea86a9e19 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Tue, 12 Aug 2025 17:25:06 +0100 Subject: [PATCH 35/68] feat: update module Signed-off-by: Otavio Santana --- .../DefaultSolrDocumentManagerTest.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/jnosql-solr/src/test/java/org/eclipse/jnosql/databases/solr/communication/DefaultSolrDocumentManagerTest.java b/jnosql-solr/src/test/java/org/eclipse/jnosql/databases/solr/communication/DefaultSolrDocumentManagerTest.java index 7532d7192..8c731ec29 100644 --- a/jnosql-solr/src/test/java/org/eclipse/jnosql/databases/solr/communication/DefaultSolrDocumentManagerTest.java +++ b/jnosql-solr/src/test/java/org/eclipse/jnosql/databases/solr/communication/DefaultSolrDocumentManagerTest.java @@ -406,13 +406,6 @@ void shouldReturnErrorWhenSaveSubDocument() { } - @Test - void shouldSaveSubDocument2() { - var entity = getEntity(); - entity.add(Element.of("phones", asList(Element.of("mobile", "1231231"), Element.of("mobile2", "1231231")))); - Assertions.assertThrows(SolrException.class, () -> entityManager.insert(entity)); - } - @Test void shouldCreateDate() { Date date = new Date(); @@ -435,11 +428,6 @@ void shouldCreateDate() { assertEquals(now, documentEntity.find("date").get().get(LocalDate.class)); } - @Test - void shouldRetrieveListSubdocumentList() { - Assertions.assertThrows(SolrException.class, () -> entityManager.insert(createSubdocumentList())); - } - @Test void shouldCount() { var entity = entityManager.insert(getEntity()); From d0a80d983ccc882415b0fcabed9170527f6c5a7f Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 14 Aug 2025 19:00:54 +0100 Subject: [PATCH 36/68] chore: amazon aws to version 2.32.21 Signed-off-by: Otavio Santana --- jnosql-dynamodb/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jnosql-dynamodb/pom.xml b/jnosql-dynamodb/pom.xml index f29c38261..160a4accb 100644 --- a/jnosql-dynamodb/pom.xml +++ b/jnosql-dynamodb/pom.xml @@ -23,7 +23,7 @@ The Eclipse JNoSQL layer implementation AWS DynamoDB - 2.31.47 + 2.32.21 From d51ce56c42e98b26258075fdf4b32d0d5101e65e Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 14 Aug 2025 19:01:52 +0100 Subject: [PATCH 37/68] ES version to 8.19.1 Signed-off-by: Otavio Santana --- jnosql-elasticsearch/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jnosql-elasticsearch/pom.xml b/jnosql-elasticsearch/pom.xml index 3ab913661..1c590801f 100644 --- a/jnosql-elasticsearch/pom.xml +++ b/jnosql-elasticsearch/pom.xml @@ -29,7 +29,7 @@ The Eclipse JNoSQL layer to Elasticsearch - 8.17.4 + 8.19.1 From c38d7adaf4d28c549aa043893ae7689be84be460 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 14 Aug 2025 19:02:22 +0100 Subject: [PATCH 38/68] docs: update documentation on changelog Signed-off-by: Otavio Santana --- CHANGELOG.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 0ac6bc7ac..13349421a 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -15,6 +15,7 @@ and this project adheres to https://semver.org/spec/v2.0.0.html[Semantic Version - Update Couchbase driver to 3.9.0 - Update Neo4J driver to 5.28.9 - Update OrientDB driver to 3.2.43 +- Update Elasticsearch driver to 8.19.1 === Added From fdf8774d738f02f6ce5f4df472142b9892ed22e8 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 14 Aug 2025 19:03:15 +0100 Subject: [PATCH 39/68] chore: update apache hbase to version 2.6.3 Signed-off-by: Otavio Santana --- jnosql-hbase/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jnosql-hbase/pom.xml b/jnosql-hbase/pom.xml index ed3d8ff1a..04b4be1b5 100644 --- a/jnosql-hbase/pom.xml +++ b/jnosql-hbase/pom.xml @@ -40,7 +40,7 @@ org.apache.hbase hbase-client - 2.6.0 + 2.6.3 From 6bf0eacb0909e47263a537f2087ecf09f51f0cf9 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 14 Aug 2025 19:03:42 +0100 Subject: [PATCH 40/68] docs: update hbase version on documentation Signed-off-by: Otavio Santana --- CHANGELOG.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 13349421a..8fa693976 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -16,6 +16,7 @@ and this project adheres to https://semver.org/spec/v2.0.0.html[Semantic Version - Update Neo4J driver to 5.28.9 - Update OrientDB driver to 3.2.43 - Update Elasticsearch driver to 8.19.1 +- Update Apache Hbase to version 2.6.3 === Added From 2f58469872fab60cb18b03d435f86d4af54b6e12 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 14 Aug 2025 19:06:22 +0100 Subject: [PATCH 41/68] chore: update jedis to version 6.1.0 Signed-off-by: Otavio Santana --- jnosql-redis/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jnosql-redis/pom.xml b/jnosql-redis/pom.xml index 39b92a9da..458da9a05 100644 --- a/jnosql-redis/pom.xml +++ b/jnosql-redis/pom.xml @@ -38,7 +38,7 @@ redis.clients jedis - 6.0.0 + 6.1.0 ${project.groupId} From 8b5b9a653d1112f120124644cd3ccea8fc3eb4c0 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 14 Aug 2025 19:06:43 +0100 Subject: [PATCH 42/68] docs: update maven driver to 6.1.0 Signed-off-by: Otavio Santana --- CHANGELOG.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 8fa693976..c48070869 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -17,6 +17,7 @@ and this project adheres to https://semver.org/spec/v2.0.0.html[Semantic Version - Update OrientDB driver to 3.2.43 - Update Elasticsearch driver to 8.19.1 - Update Apache Hbase to version 2.6.3 +- Update Jedis version to 6.1.0 === Added From 37963497f3637bb24744fe7c3ef8cb888153b5bb Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 14 Aug 2025 19:07:55 +0100 Subject: [PATCH 43/68] chore: update apache tinkerpop 3.7.4 Signed-off-by: Otavio Santana --- jnosql-tinkerpop/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jnosql-tinkerpop/pom.xml b/jnosql-tinkerpop/pom.xml index e83229ed2..d9128c0aa 100644 --- a/jnosql-tinkerpop/pom.xml +++ b/jnosql-tinkerpop/pom.xml @@ -27,7 +27,7 @@ JNoSQL Apache Tinkerpop Driver - 3.7.3 + 3.7.4 0.9-3.4.0 4.9.1 From 9e14b07fe4c5ae8c9b16e713f138b12d366c8fe7 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 14 Aug 2025 19:08:24 +0100 Subject: [PATCH 44/68] chore: update apache tinkerpop to version 3.7.4 Signed-off-by: Otavio Santana --- CHANGELOG.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index c48070869..e454d063a 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -18,6 +18,7 @@ and this project adheres to https://semver.org/spec/v2.0.0.html[Semantic Version - Update Elasticsearch driver to 8.19.1 - Update Apache Hbase to version 2.6.3 - Update Jedis version to 6.1.0 +- Update Apache Tinkerpop core to 3.7.4 === Added From b63809178ce0d71b95843ca2027e95377907eec6 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 14 Aug 2025 19:17:49 +0100 Subject: [PATCH 45/68] feat: create like to regex Signed-off-by: Otavio Santana --- .../tinkerpop/communication/LikeToRegex.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/LikeToRegex.java diff --git a/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/LikeToRegex.java b/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/LikeToRegex.java new file mode 100644 index 000000000..ddfc4a9d9 --- /dev/null +++ b/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/LikeToRegex.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Otavio Santana + */ +package org.eclipse.jnosql.databases.tinkerpop.communication; + +import java.util.regex.Pattern; + +public enum LikeToRegex { + INSTANCE; + + + private static String LikeToRegex(String likePattern) { + if (likePattern == null) { + return "a^"; + } // match nothing + StringBuilder sb = new StringBuilder("^"); + for (char c : likePattern.toCharArray()) { + switch (c) { + case '%': sb.append(".*"); break; + case '_': sb.append('.'); break; + default: sb.append(Pattern.quote(String.valueOf(c))); + } + } + sb.append('$'); + return sb.toString(); + } + +} From 556422324881759f9d19aaa3f989b6a839fb8fe2 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 14 Aug 2025 19:25:21 +0100 Subject: [PATCH 46/68] style: update document query conversor Signed-off-by: Otavio Santana --- .../communication/DocumentQueryConversor.java | 13 ++++--- .../tinkerpop/communication/LikeToRegex.java | 36 ++++++++++++------- .../communication/TraversalExecutor.java | 15 ++++++++ 3 files changed, 48 insertions(+), 16 deletions(-) diff --git a/jnosql-mongodb/src/main/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConversor.java b/jnosql-mongodb/src/main/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConversor.java index bea807b9a..b125cb031 100644 --- a/jnosql-mongodb/src/main/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConversor.java +++ b/jnosql-mongodb/src/main/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConversor.java @@ -82,16 +82,21 @@ public static Bson convert(CriteriaCondition condition) { }; } - static String prepareRegexValue(String likePattern) { + static String prepareRegexValue(String likePattern) { if (likePattern == null) { return "(?!)"; // never matches } StringBuilder sb = new StringBuilder("^"); for (char c : likePattern.toCharArray()) { switch (c) { - case '%': sb.append(".*"); break; // zero or more - case '_': sb.append('.'); break; // exactly one - default: sb.append(Pattern.quote(String.valueOf(c))); + case '%': + sb.append(".*"); + break; + case '_': + sb.append('.'); + break; + default: + sb.append(Pattern.quote(String.valueOf(c))); } } sb.append('$'); diff --git a/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/LikeToRegex.java b/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/LikeToRegex.java index ddfc4a9d9..bb597d136 100644 --- a/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/LikeToRegex.java +++ b/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/LikeToRegex.java @@ -20,20 +20,32 @@ public enum LikeToRegex { INSTANCE; - private static String LikeToRegex(String likePattern) { - if (likePattern == null) { - return "a^"; - } // match nothing - StringBuilder sb = new StringBuilder("^"); - for (char c : likePattern.toCharArray()) { - switch (c) { - case '%': sb.append(".*"); break; - case '_': sb.append('.'); break; - default: sb.append(Pattern.quote(String.valueOf(c))); + /** + * Converts like pattern to regex pattern. + * @param text the like pattern to convert + * @return the regex pattern + */ + private static String LikeToRegex(Object text) { + String like = text== null? null: text.toString(); + if (like == null) { + return "(?!)"; + } + StringBuilder rx = new StringBuilder("^"); + StringBuilder lit = new StringBuilder(); + for (int i = 0; i < like.length(); i++) { + char c = like.charAt(i); + if (c == '%' || c == '_') { + if (!lit.isEmpty()) { rx.append(java.util.regex.Pattern.quote(lit.toString())); lit.setLength(0); } + rx.append(c == '%' ? ".*" : "."); + } else { + lit.append(c); } } - sb.append('$'); - return sb.toString(); + if (!lit.isEmpty()) { + rx.append(java.util.regex.Pattern.quote(lit.toString())); + } + rx.append('$'); + return rx.toString(); } } diff --git a/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/TraversalExecutor.java b/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/TraversalExecutor.java index cf1085151..7a15f0246 100644 --- a/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/TraversalExecutor.java +++ b/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/TraversalExecutor.java @@ -15,6 +15,7 @@ package org.eclipse.jnosql.databases.tinkerpop.communication; import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.TextP; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; import org.apache.tinkerpop.gremlin.structure.Vertex; @@ -41,6 +42,19 @@ static GraphTraversal getPredicate(CriteriaCondition condition) case EQUALS -> { return __.has(name, P.eq(value)); } + case LIKE -> { + TextP. + return __.has(name, P.test(v -> v instanceof String && ((String) v).matches(regex))); + } + case ENDS_WITH -> { + return __.has(name, TextP.endingWith(value == null ? "" : value.toString())); + } + case STARTS_WITH -> { + __.has(name, TextP.startingWith(value == null ? "" : value.toString())); + } + case CONTAINS -> { + return __.has(name, TextP.containing(value == null ? "" : value.toString())); + } case GREATER_THAN -> { return __.has(name, P.gt(value)); } @@ -79,6 +93,7 @@ static GraphTraversal getPredicate(CriteriaCondition condition) .reduce(GraphTraversal::or) .orElseThrow(() -> new UnsupportedOperationException("There is an inconsistency at the OR operator")); } + default -> throw new UnsupportedOperationException("There is not support to the type " + operator + " in graph"); } From a70dba7feb09e910144e0efc8ee42edbbb73ea9d Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 14 Aug 2025 19:37:47 +0100 Subject: [PATCH 47/68] test: update on document query converter Signed-off-by: Otavio Santana --- ...t.java => DocumentQueryConverterTest.java} | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) rename jnosql-mongodb/src/test/java/org/eclipse/jnosql/databases/mongodb/communication/{DocumentQueryConversorTest.java => DocumentQueryConverterTest.java} (68%) diff --git a/jnosql-mongodb/src/test/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConversorTest.java b/jnosql-mongodb/src/test/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConverterTest.java similarity index 68% rename from jnosql-mongodb/src/test/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConversorTest.java rename to jnosql-mongodb/src/test/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConverterTest.java index 112d331ed..f4336bd40 100644 --- a/jnosql-mongodb/src/test/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConversorTest.java +++ b/jnosql-mongodb/src/test/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConverterTest.java @@ -20,30 +20,30 @@ import static org.assertj.core.api.Assertions.assertThat; -class DocumentQueryConversorTest { +class DocumentQueryConverterTest { @ParameterizedTest @CsvSource(textBlock = """ - Max_;^Max.{1} - Max%;^Max.{1,} - M_x;^M.{1}x - M%x;^M.{1,}x - _ax;^.{1}ax - %ax;^.{1,}ax + Max_;^\\QM\\E\\Qa\\E\\Qx\\E.$ + Max%;^\\QM\\E\\Qa\\E\\Qx\\E.*$ + M_x;^\\QM\\E.\\Qx\\E$ + M%x;^\\QM\\E.*\\Qx\\E$ + _ax;^.\\Qa\\E\\Qx\\E$ + %ax;^.*\\Qa\\E\\Qx\\E$ ;^$ """, delimiterString = ";") void shouldPrepareRegexValueSupportedByMongoDB(String rawValue, String expectedValue) { assertThat(DocumentQueryConversor.prepareRegexValue(rawValue)) .as("The value should be prepared to be used in a MongoDB regex query: " + - "the '_' character should matches any single character, and " + - "the '%' character should matches any sequence of characters.") + "the '_' character should match any single character, and " + + "the '%' character should match any sequence of characters.") .isEqualTo(expectedValue); } @Test - void shouldReturnEmptyRegexWhenRawValueIsNull() { + void shouldReturnNeverMatchingRegexWhenRawValueIsNull() { assertThat(DocumentQueryConversor.prepareRegexValue(null)) - .as("should return an empty regex when the raw value is null") - .isEqualTo("^$"); + .as("should return a never-matching regex when the raw value is null") + .isEqualTo("(?!)"); } } \ No newline at end of file From 711516e759baf6167528c29bf6fd35f824300f03 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 14 Aug 2025 19:38:35 +0100 Subject: [PATCH 48/68] feat: update converter Signed-off-by: Otavio Santana --- .../mongodb/communication/DocumentQueryConverterTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/jnosql-mongodb/src/test/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConverterTest.java b/jnosql-mongodb/src/test/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConverterTest.java index f4336bd40..f95cd9c20 100644 --- a/jnosql-mongodb/src/test/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConverterTest.java +++ b/jnosql-mongodb/src/test/java/org/eclipse/jnosql/databases/mongodb/communication/DocumentQueryConverterTest.java @@ -30,7 +30,6 @@ class DocumentQueryConverterTest { M%x;^\\QM\\E.*\\Qx\\E$ _ax;^.\\Qa\\E\\Qx\\E$ %ax;^.*\\Qa\\E\\Qx\\E$ - ;^$ """, delimiterString = ";") void shouldPrepareRegexValueSupportedByMongoDB(String rawValue, String expectedValue) { assertThat(DocumentQueryConversor.prepareRegexValue(rawValue)) From 269ff5be1c79c77bcf465bc2958660130286395c Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 14 Aug 2025 19:40:17 +0100 Subject: [PATCH 49/68] feat: update traversal on apache tinkerpop Signed-off-by: Otavio Santana --- .../databases/tinkerpop/communication/TraversalExecutor.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/TraversalExecutor.java b/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/TraversalExecutor.java index 7a15f0246..8ca844905 100644 --- a/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/TraversalExecutor.java +++ b/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/TraversalExecutor.java @@ -43,14 +43,13 @@ static GraphTraversal getPredicate(CriteriaCondition condition) return __.has(name, P.eq(value)); } case LIKE -> { - TextP. - return __.has(name, P.test(v -> v instanceof String && ((String) v).matches(regex))); + return __.has(name, TextP.regex(value == null ? "" : value.toString())); } case ENDS_WITH -> { return __.has(name, TextP.endingWith(value == null ? "" : value.toString())); } case STARTS_WITH -> { - __.has(name, TextP.startingWith(value == null ? "" : value.toString())); + return __.has(name, TextP.startingWith(value == null ? "" : value.toString())); } case CONTAINS -> { return __.has(name, TextP.containing(value == null ? "" : value.toString())); From e65c520d72ac1c56704472a435f6a00737b5ec3a Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 14 Aug 2025 19:42:13 +0100 Subject: [PATCH 50/68] feat: udpate traversal convertor Signed-off-by: Otavio Santana --- .../databases/tinkerpop/communication/LikeToRegex.java | 8 +++++--- .../tinkerpop/communication/TraversalExecutor.java | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/LikeToRegex.java b/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/LikeToRegex.java index bb597d136..470ca9ccc 100644 --- a/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/LikeToRegex.java +++ b/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/LikeToRegex.java @@ -14,9 +14,11 @@ */ package org.eclipse.jnosql.databases.tinkerpop.communication; -import java.util.regex.Pattern; -public enum LikeToRegex { +/** + * The like to regex converter + */ +enum LikeToRegex { INSTANCE; @@ -25,7 +27,7 @@ public enum LikeToRegex { * @param text the like pattern to convert * @return the regex pattern */ - private static String LikeToRegex(Object text) { + String likeToRegex(Object text) { String like = text== null? null: text.toString(); if (like == null) { return "(?!)"; diff --git a/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/TraversalExecutor.java b/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/TraversalExecutor.java index 8ca844905..1f7f36676 100644 --- a/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/TraversalExecutor.java +++ b/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/TraversalExecutor.java @@ -43,7 +43,7 @@ static GraphTraversal getPredicate(CriteriaCondition condition) return __.has(name, P.eq(value)); } case LIKE -> { - return __.has(name, TextP.regex(value == null ? "" : value.toString())); + return __.has(name, TextP.regex(LikeToRegex.INSTANCE.likeToRegex(value))); } case ENDS_WITH -> { return __.has(name, TextP.endingWith(value == null ? "" : value.toString())); From 67ef67e3ea9f3997da2d7f18fbbf394b32f93e40 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Fri, 15 Aug 2025 08:07:06 +0100 Subject: [PATCH 51/68] test: include query on tinkerpop Signed-off-by: Otavio Santana --- ...aultTinkerpopGraphDatabaseManagerTest.java | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/jnosql-tinkerpop/src/test/java/org/eclipse/jnosql/databases/tinkerpop/communication/DefaultTinkerpopGraphDatabaseManagerTest.java b/jnosql-tinkerpop/src/test/java/org/eclipse/jnosql/databases/tinkerpop/communication/DefaultTinkerpopGraphDatabaseManagerTest.java index 6e7c5e5ee..0e62930c7 100644 --- a/jnosql-tinkerpop/src/test/java/org/eclipse/jnosql/databases/tinkerpop/communication/DefaultTinkerpopGraphDatabaseManagerTest.java +++ b/jnosql-tinkerpop/src/test/java/org/eclipse/jnosql/databases/tinkerpop/communication/DefaultTinkerpopGraphDatabaseManagerTest.java @@ -20,14 +20,17 @@ import org.assertj.core.api.SoftAssertions; import org.eclipse.jnosql.communication.graph.CommunicationEdge; import org.eclipse.jnosql.communication.semistructured.CommunicationEntity; +import org.eclipse.jnosql.communication.semistructured.CriteriaCondition; import org.eclipse.jnosql.communication.semistructured.DeleteQuery; import org.eclipse.jnosql.communication.semistructured.Element; import org.eclipse.jnosql.communication.semistructured.Elements; import org.eclipse.jnosql.communication.semistructured.SelectQuery; +import org.eclipse.jnosql.mapping.semistructured.MappingQuery; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.time.Duration; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -488,6 +491,68 @@ void shouldFindEdgeById() { assertEquals(edge.target().find("_id").orElseThrow().get(), foundEdge.get().target().find("_id").orElseThrow().get()); } + @Test + void shouldFindContains() { + var entity = getEntity(); + + entityManager.insert(entity); + var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.contains(Element.of("name", + "lia")), COLLECTION_NAME, Collections.emptyList()); + + var result = entityManager.select(query).toList(); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(result).hasSize(1); + softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana"); + }); + } + + @Test + void shouldStartsWith() { + var entity = getEntity(); + + entityManager.insert(entity); + var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.startsWith(Element.of("name", + "Pol")), COLLECTION_NAME, Collections.emptyList()); + + var result = entityManager.select(query).toList(); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(result).hasSize(1); + softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana"); + }); + } + + @Test + void shouldEndsWith() { + var entity = getEntity(); + + entityManager.insert(entity); + var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.endsWith(Element.of("name", + "ana")), COLLECTION_NAME, Collections.emptyList()); + + var result = entityManager.select(query).toList(); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(result).hasSize(1); + softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana"); + }); + } + + @Test + void shouldFindDocumentLike() { + DeleteQuery deleteQuery = delete().from(COLLECTION_NAME).where("type").eq("V").build(); + entityManager.delete(deleteQuery); + Iterable entitiesSaved = entityManager.insert(getEntitiesWithValues()); + List entities = StreamSupport.stream(entitiesSaved.spliterator(), false).toList(); + + var query = select().from(COLLECTION_NAME) + .where("name").like("Lu%") + .and("type").eq("V") + .build(); + + List entitiesFound = entityManager.select(query).collect(Collectors.toList()); + assertEquals(2, entitiesFound.size()); + assertThat(entitiesFound).contains(entities.get(0), entities.get(2)); + } + private CommunicationEntity getEntity() { CommunicationEntity entity = CommunicationEntity.of(COLLECTION_NAME); Map map = new HashMap<>(); From 4aa16d81fa4ad6b1f4fe1ad3b24de7b1ad72f0b7 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Fri, 15 Aug 2025 08:14:27 +0100 Subject: [PATCH 52/68] test: include like condition Signed-off-by: Otavio Santana --- .../OracleNoSQLDocumentManagerTest.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSQLDocumentManagerTest.java b/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSQLDocumentManagerTest.java index 7478e32e9..5ccf73efc 100644 --- a/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSQLDocumentManagerTest.java +++ b/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSQLDocumentManagerTest.java @@ -17,6 +17,7 @@ import org.assertj.core.api.SoftAssertions; import org.eclipse.jnosql.communication.TypeReference; import org.eclipse.jnosql.communication.semistructured.CommunicationEntity; +import org.eclipse.jnosql.communication.semistructured.DeleteQuery; import org.eclipse.jnosql.communication.semistructured.Element; import org.eclipse.jnosql.communication.semistructured.Elements; import org.junit.jupiter.api.Assertions; @@ -605,6 +606,24 @@ void shouldDoQueryUsingEnumAsParameter() { }); } + @Test + void shouldFindDocumentLike() { + DeleteQuery deleteQuery = delete().from(COLLECTION_NAME).where("type").eq("V").build(); + entityManager.delete(deleteQuery); + Iterable entitiesSaved = entityManager.insert(getEntitiesWithValues()); + List entities = StreamSupport.stream(entitiesSaved.spliterator(), false).toList(); + + var query = select().from(COLLECTION_NAME) + .where("name").like("Lu%") + .and("type").eq("V") + .build(); + + List entitiesFound = entityManager.select(query).collect(Collectors.toList()); + assertEquals(2, entitiesFound.size()); + assertThat(entitiesFound).contains(entities.get(0), entities.get(2)); + } + + private CommunicationEntity createDocumentList() { var entity = CommunicationEntity.of("AppointmentBook"); entity.add(Element.of("_id", new Random().nextInt())); From 7b16d093fa72d85981663e91aa772f5bf2dafb71 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Fri, 15 Aug 2025 08:15:02 +0100 Subject: [PATCH 53/68] test: include oracle nosql with like and conditions Signed-off-by: Otavio Santana --- .../OracleNoSQLDocumentManagerTest.java | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSQLDocumentManagerTest.java b/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSQLDocumentManagerTest.java index 5ccf73efc..517390a16 100644 --- a/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSQLDocumentManagerTest.java +++ b/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSQLDocumentManagerTest.java @@ -17,9 +17,11 @@ import org.assertj.core.api.SoftAssertions; import org.eclipse.jnosql.communication.TypeReference; import org.eclipse.jnosql.communication.semistructured.CommunicationEntity; +import org.eclipse.jnosql.communication.semistructured.CriteriaCondition; import org.eclipse.jnosql.communication.semistructured.DeleteQuery; import org.eclipse.jnosql.communication.semistructured.Element; import org.eclipse.jnosql.communication.semistructured.Elements; +import org.eclipse.jnosql.mapping.semistructured.MappingQuery; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -623,6 +625,52 @@ void shouldFindDocumentLike() { assertThat(entitiesFound).contains(entities.get(0), entities.get(2)); } + @Test + void shouldFindContains() { + var entity = getEntity(); + + entityManager.insert(entity); + var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.contains(Element.of("name", + "lia")), COLLECTION_NAME, Collections.emptyList()); + + var result = entityManager.select(query).toList(); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(result).hasSize(1); + softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana"); + }); + } + + @Test + void shouldStartsWith() { + var entity = getEntity(); + + entityManager.insert(entity); + var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.startsWith(Element.of("name", + "Pol")), COLLECTION_NAME, Collections.emptyList()); + + var result = entityManager.select(query).toList(); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(result).hasSize(1); + softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana"); + }); + } + + @Test + void shouldEndsWith() { + var entity = getEntity(); + + entityManager.insert(entity); + var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.endsWith(Element.of("name", + "ana")), COLLECTION_NAME, Collections.emptyList()); + + var result = entityManager.select(query).toList(); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(result).hasSize(1); + softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana"); + }); + } + + private CommunicationEntity createDocumentList() { var entity = CommunicationEntity.of("AppointmentBook"); From a1da2e1daf8f9d4707fb03a980d2a55fca9d22f2 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Fri, 15 Aug 2025 08:20:42 +0100 Subject: [PATCH 54/68] chore: generate initial structure to ocnverter of Oracle nosql Signed-off-by: Otavio Santana --- .../communication/AbstractQueryBuilder.java | 4 ++-- .../OracleNoSqlLikeConverter.java | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java diff --git a/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/AbstractQueryBuilder.java b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/AbstractQueryBuilder.java index d731cf0b7..297753b7d 100644 --- a/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/AbstractQueryBuilder.java +++ b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/AbstractQueryBuilder.java @@ -64,9 +64,9 @@ protected void condition(CriteriaCondition condition, StringBuilder query, List< case GREATER_EQUALS_THAN: predicate(query, " >= ", document, params); return; -/* case LIKE: + case LIKE: predicate(query, " LIKE ", document, params); - return;*/ + return; case NOT: query.append(" NOT "); condition(document.get(CriteriaCondition.class), query, params, ids); diff --git a/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java new file mode 100644 index 000000000..8a2e1e3d4 --- /dev/null +++ b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Otavio Santana + */ +package org.eclipse.jnosql.databases.oracle.communication; + +enum OracleNoSqlLikeConverter { +} From 8291a2e888b05cce5ceadfdfb0d543227a7a94ca Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Fri, 15 Aug 2025 08:22:36 +0100 Subject: [PATCH 55/68] feat: convert nosql Signed-off-by: Otavio Santana --- .../OracleNoSqlLikeConverter.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java index 8a2e1e3d4..cf25cbcd7 100644 --- a/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java +++ b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java @@ -14,5 +14,36 @@ */ package org.eclipse.jnosql.databases.oracle.communication; +import java.util.regex.Pattern; + enum OracleNoSqlLikeConverter { + INSTANCE; + + static String convert(Object value) { + + String like = value == null ? null : value.toString(); + + if (like == null) { + return ""; + } + StringBuilder out = new StringBuilder(like.length()); + StringBuilder literal = new StringBuilder(); + + for (int i = 0; i < like.length(); i++) { + char c = like.charAt(i); + if (c == '%' || c == '_') { + if (!literal.isEmpty()) { + out.append(Pattern.quote(literal.toString())); + literal.setLength(0); + } + out.append(c == '%' ? ".*" : "."); + } else { + literal.append(c); + } + } + if (!literal.isEmpty()) { + out.append(Pattern.quote(literal.toString())); + } + return out.toString(); + } } From 6768888826ba8f61c47d5087f0573da8ddc9cba8 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Fri, 15 Aug 2025 08:25:14 +0100 Subject: [PATCH 56/68] feat: update oracle nosql communication Signed-off-by: Otavio Santana --- .../OracleNoSqlLikeConverterTest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java diff --git a/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java b/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java new file mode 100644 index 000000000..9adca6f51 --- /dev/null +++ b/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Otavio Santana + */ +package org.eclipse.jnosql.databases.oracle.communication; + +import static org.junit.jupiter.api.Assertions.*; + +class OracleNoSqlLikeConverterTest { + +} \ No newline at end of file From 395e10876654413505ec8052bfe8f4ab0e9b8246 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Fri, 15 Aug 2025 08:33:46 +0100 Subject: [PATCH 57/68] test: generate scenario on oracle nosql Signed-off-by: Otavio Santana --- .../OracleNoSqlLikeConverterTest.java | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java b/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java index 9adca6f51..5f657142e 100644 --- a/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java +++ b/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java @@ -14,8 +14,41 @@ */ package org.eclipse.jnosql.databases.oracle.communication; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.assertj.core.api.Assertions.assertThat; class OracleNoSqlLikeConverterTest { + @ParameterizedTest(name = "LIKE \"{0}\" -> pattern \"{1}\"") + @CsvSource(textBlock = """ + %Ota%;.*\\QOta\\E.* + Ota%;\\QOta\\E.* + %Ota;.*\\QOta\\E + Ota;\\QOta\\E + Ot_;\\QOt\\E. + _ta;.\\Qta\\E + %t_a%;.*\\Qt\\E.\\Qa\\E.* + .+;\\Q.+\\E + """, delimiter = ';') + @DisplayName("Converts SQL LIKE to Oracle NoSQL regex_like pattern (%, _ and literal quoting)") + void shouldConvertSqlLikeToOracleNoSqlRegex(String like, String expected) { + String actual = OracleNoSqlLikeConverter.convert(like); + assertThat(actual).isEqualTo(expected); + } + + @Test + @DisplayName("Returns empty string for null input") + void shouldReturnEmptyForNull() { + assertThat(OracleNoSqlLikeConverter.convert(null)).isEqualTo(""); + } + + @Test + @DisplayName("Returns empty string for empty input") + void shouldReturnEmptyForEmptyString() { + assertThat(OracleNoSqlLikeConverter.convert("")).isEqualTo(""); + } } \ No newline at end of file From d8a97f91fb20843401aeb439b37703343b8cd5ab Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Fri, 15 Aug 2025 09:27:14 +0100 Subject: [PATCH 58/68] feat: update oracle nosql converter Signed-off-by: Otavio Santana --- .../OracleNoSqlLikeConverter.java | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java index cf25cbcd7..ab47a45ba 100644 --- a/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java +++ b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java @@ -14,36 +14,41 @@ */ package org.eclipse.jnosql.databases.oracle.communication; +import java.util.Set; import java.util.regex.Pattern; enum OracleNoSqlLikeConverter { INSTANCE; - static String convert(Object value) { - - String like = value == null ? null : value.toString(); + // Regex metacharacters that must be escaped for Oracle NoSQL regex_like + private static final Set META = Set.of( + '.', '^', '$', '*', '+', '?', '(', ')', '[', ']', '{', '}', '\\', '|' + ); - if (like == null) { - return ""; - } + /** + * SQL LIKE (%, _) -> Oracle NoSQL regex_like pattern. + * Examples: + * "Lu%" -> "Lu.*" + * "%Lu" -> ".*Lu" + * "%Lu%" -> ".*Lu.*" + * "Lu" -> "Lu" // exact match equivalent in regex_like + * "a.c" -> "a\\.c" // '.' escaped + */ + static String convert(Object value) { + if (value == null) return ""; // let caller decide behavior for empty + String like = value.toString(); StringBuilder out = new StringBuilder(like.length()); - StringBuilder literal = new StringBuilder(); for (int i = 0; i < like.length(); i++) { char c = like.charAt(i); - if (c == '%' || c == '_') { - if (!literal.isEmpty()) { - out.append(Pattern.quote(literal.toString())); - literal.setLength(0); - } - out.append(c == '%' ? ".*" : "."); - } else { - literal.append(c); + switch (c) { + case '%': out.append(".*"); break; // zero or more + case '_': out.append('.'); break; // exactly one + default: + if (META.contains(c)) out.append('\\'); + out.append(c); } } - if (!literal.isEmpty()) { - out.append(Pattern.quote(literal.toString())); - } return out.toString(); } } From a16349d876c234ead679d68f4955a1e83daeae02 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Fri, 15 Aug 2025 09:27:57 +0100 Subject: [PATCH 59/68] test: update oracle nosql to use the instance method Signed-off-by: Otavio Santana --- .../oracle/communication/OracleNoSqlLikeConverterTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java b/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java index 5f657142e..afcc28ad8 100644 --- a/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java +++ b/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java @@ -36,19 +36,19 @@ class OracleNoSqlLikeConverterTest { """, delimiter = ';') @DisplayName("Converts SQL LIKE to Oracle NoSQL regex_like pattern (%, _ and literal quoting)") void shouldConvertSqlLikeToOracleNoSqlRegex(String like, String expected) { - String actual = OracleNoSqlLikeConverter.convert(like); + String actual = OracleNoSqlLikeConverter.INSTANCE.convert(like); assertThat(actual).isEqualTo(expected); } @Test @DisplayName("Returns empty string for null input") void shouldReturnEmptyForNull() { - assertThat(OracleNoSqlLikeConverter.convert(null)).isEqualTo(""); + assertThat(OracleNoSqlLikeConverter.INSTANCE.convert(null)).isEqualTo(""); } @Test @DisplayName("Returns empty string for empty input") void shouldReturnEmptyForEmptyString() { - assertThat(OracleNoSqlLikeConverter.convert("")).isEqualTo(""); + assertThat(OracleNoSqlLikeConverter.INSTANCE.convert("")).isEqualTo(""); } } \ No newline at end of file From 437c928e2ed89eee3bfa58dbb6e0837540a6c4c2 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Fri, 15 Aug 2025 10:54:33 +0100 Subject: [PATCH 60/68] chore: update query builder to support like and other keyworlds Signed-off-by: Otavio Santana --- .../oracle/communication/AbstractQueryBuilder.java | 13 ++++++++++++- .../OracleNoSQLDocumentManagerTest.java | 12 ++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/AbstractQueryBuilder.java b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/AbstractQueryBuilder.java index 297753b7d..7a0f98e9a 100644 --- a/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/AbstractQueryBuilder.java +++ b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/AbstractQueryBuilder.java @@ -65,7 +65,10 @@ protected void condition(CriteriaCondition condition, StringBuilder query, List< predicate(query, " >= ", document, params); return; case LIKE: - predicate(query, " LIKE ", document, params); + case CONTAINS: + case STARTS_WITH: + case ENDS_WITH: + predicateLike(query, document, params); return; case NOT: query.append(" NOT "); @@ -134,6 +137,14 @@ protected void predicate(StringBuilder query, params.add(fieldValue); } + protected void predicateLike(StringBuilder query, + Element document, + List params) { + String name = identifierOf(document.name()); + Object value = OracleNoSqlLikeConverter.INSTANCE.convert(document.get()); + query.append("regex_like(").append(name).append(", \"").append(value).append("\")"); + } + protected String identifierOf(String name) { return ' ' + table + "." + JSON_FIELD + "." + name + ' '; } diff --git a/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSQLDocumentManagerTest.java b/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSQLDocumentManagerTest.java index 517390a16..307d1663f 100644 --- a/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSQLDocumentManagerTest.java +++ b/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSQLDocumentManagerTest.java @@ -621,8 +621,16 @@ void shouldFindDocumentLike() { .build(); List entitiesFound = entityManager.select(query).collect(Collectors.toList()); - assertEquals(2, entitiesFound.size()); - assertThat(entitiesFound).contains(entities.get(0), entities.get(2)); + + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(entitiesFound).hasSize(2); + var names = entitiesFound.stream() + .flatMap(d -> d.find("name").stream()) + .map(d -> d.get(String.class)) + .toList(); + soft.assertThat(names).contains("Lucas", "Luna"); + + }); } @Test From f6a4d374b552bd30cbeaf4aac7c28a78b593d748 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Fri, 15 Aug 2025 10:59:54 +0100 Subject: [PATCH 61/68] feat: udpate on oracle nosql Signed-off-by: Otavio Santana --- .../OracleNoSqlLikeConverter.java | 3 +- .../OracleNoSqlLikeConverterTest.java | 42 ++++++++++++++----- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java index ab47a45ba..620f6675b 100644 --- a/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java +++ b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java @@ -20,7 +20,6 @@ enum OracleNoSqlLikeConverter { INSTANCE; - // Regex metacharacters that must be escaped for Oracle NoSQL regex_like private static final Set META = Set.of( '.', '^', '$', '*', '+', '?', '(', ')', '[', ']', '{', '}', '\\', '|' ); @@ -34,7 +33,7 @@ enum OracleNoSqlLikeConverter { * "Lu" -> "Lu" // exact match equivalent in regex_like * "a.c" -> "a\\.c" // '.' escaped */ - static String convert(Object value) { + String convert(Object value) { if (value == null) return ""; // let caller decide behavior for empty String like = value.toString(); StringBuilder out = new StringBuilder(like.length()); diff --git a/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java b/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java index afcc28ad8..dd0e26df9 100644 --- a/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java +++ b/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java @@ -17,29 +17,49 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.params.provider.Arguments.arguments; class OracleNoSqlLikeConverterTest { + @ParameterizedTest(name = "LIKE \"{0}\" -> pattern \"{1}\"") - @CsvSource(textBlock = """ - %Ota%;.*\\QOta\\E.* - Ota%;\\QOta\\E.* - %Ota;.*\\QOta\\E - Ota;\\QOta\\E - Ot_;\\QOt\\E. - _ta;.\\Qta\\E - %t_a%;.*\\Qt\\E.\\Qa\\E.* - .+;\\Q.+\\E - """, delimiter = ';') - @DisplayName("Converts SQL LIKE to Oracle NoSQL regex_like pattern (%, _ and literal quoting)") + @MethodSource("cases") + @DisplayName("Converts SQL LIKE to Oracle NoSQL regex_like pattern (no anchors)") void shouldConvertSqlLikeToOracleNoSqlRegex(String like, String expected) { String actual = OracleNoSqlLikeConverter.INSTANCE.convert(like); assertThat(actual).isEqualTo(expected); } + static Stream cases() { + return Stream.of( + // starts / ends / contains / exact + arguments("Lu%", "Lu.*"), + arguments("%Lu", ".*Lu"), + arguments("%Lu%", ".*Lu.*"), + arguments("Lu", "Lu"), + + // single-char wildcard + arguments("Ot_", "Ot."), + arguments("_ta", ".ta"), + + // escaping of regex metacharacters + arguments("%a.c%", ".*a\\.c.*"), + arguments("100% match", "100.* match"), + + // edge cases + arguments("", ""), // empty LIKE -> empty pattern + arguments("%%", ".*.*"), // only wildcards + arguments("__", "..") + ); + } + @Test @DisplayName("Returns empty string for null input") void shouldReturnEmptyForNull() { From 0e1788955f8bb602213dd3939e1b0e842fdb2472 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Fri, 15 Aug 2025 20:24:35 +0100 Subject: [PATCH 62/68] feat: include start regex conditions Signed-off-by: Otavio Santana --- .../OracleNoSqlLikeConverter.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java index 620f6675b..073efdeab 100644 --- a/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java +++ b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java @@ -50,4 +50,29 @@ String convert(Object value) { } return out.toString(); } + + /** Contains: equivalent to SQL LIKE %term% */ + String contains(String term) { + return ".*" + escape(term) + ".*"; + } + + /** Starts with: equivalent to SQL LIKE term% */ + String startsWith(String term) { + return escape(term) + ".*"; + } + + /** Ends with: equivalent to SQL LIKE %term */ + String endsWith(String term) { + return ".*" + escape(term); + } + + + private String escape(String s) { + StringBuilder out = new StringBuilder(s.length()); + for (char c : s.toCharArray()) { + if (META.contains(c)) out.append('\\'); + out.append(c); + } + return out.toString(); + } } From 76365464f1e4f3f661b72a6732af1754575efca7 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Fri, 15 Aug 2025 20:25:16 +0100 Subject: [PATCH 63/68] style: remove imports onOracleNoSQLLikeConverter Signed-off-by: Otavio Santana --- .../databases/oracle/communication/OracleNoSqlLikeConverter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java index 073efdeab..e0f201bdc 100644 --- a/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java +++ b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverter.java @@ -15,7 +15,6 @@ package org.eclipse.jnosql.databases.oracle.communication; import java.util.Set; -import java.util.regex.Pattern; enum OracleNoSqlLikeConverter { INSTANCE; From bf5863aa737be89200016293ae1149cba7fb826d Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 16 Aug 2025 06:32:59 +0100 Subject: [PATCH 64/68] test: update scenarios with oracle NoSQL Like converter Signed-off-by: Otavio Santana --- .../OracleNoSqlLikeConverterTest.java | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java b/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java index dd0e26df9..29e445b79 100644 --- a/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java +++ b/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSqlLikeConverterTest.java @@ -71,4 +71,77 @@ void shouldReturnEmptyForNull() { void shouldReturnEmptyForEmptyString() { assertThat(OracleNoSqlLikeConverter.INSTANCE.convert("")).isEqualTo(""); } + + @ParameterizedTest(name = "contains(\"{0}\") -> \"{1}\"") + @MethodSource("containsCases") + @DisplayName("contains(term) escapes meta and wraps with .* … .*") + void shouldContains(String term, String expected) { + String actual = OracleNoSqlLikeConverter.INSTANCE.contains(term); + assertThat(actual).isEqualTo(expected); + } + + static Stream containsCases() { + return Stream.of( + arguments("Lu", ".*Lu.*"), + arguments("a.c", ".*a\\.c.*"), + arguments("price$", ".*price\\$.*"), + arguments("(hello)", ".*\\(hello\\).*"), + arguments("", ".*.*") + ); + } + + @ParameterizedTest(name = "startsWith(\"{0}\") -> \"{1}\"") + @MethodSource("startsWithCases") + @DisplayName("startsWith(term) escapes meta and appends .*") + void shouldStartsWith(String term, String expected) { + String actual = OracleNoSqlLikeConverter.INSTANCE.startsWith(term); + assertThat(actual).isEqualTo(expected); + } + + static Stream startsWithCases() { + return Stream.of( + arguments("Lu", "Lu.*"), + arguments("a.c", "a\\.c.*"), + arguments("price$", "price\\$.*"), + arguments("(hello)", "\\(hello\\).*"), + arguments("", ".*") + ); + } + + + @ParameterizedTest(name = "endsWith(\"{0}\") -> \"{1}\"") + @MethodSource("endsWithCases") + @DisplayName("endsWith(term) escapes meta and prefixes .*") + void shouldEndsWith(String term, String expected) { + String actual = OracleNoSqlLikeConverter.INSTANCE.endsWith(term); + assertThat(actual).isEqualTo(expected); + } + + static Stream endsWithCases() { + return Stream.of( + arguments("Lu", ".*Lu"), + arguments("a.c", ".*a\\.c"), + arguments("price$", ".*price\\$"), + arguments("(hello)", ".*\\(hello\\)"), + arguments("", ".*") + ); + } + + @Test + @DisplayName("All regex metacharacters are escaped in contains/startsWith/endsWith") + void escapesAllMetaCharacters() { + String term = ".^$*+?()[]{}\\|"; + // Expected escaped chunk: \.\^\$\*\+\?\(\)\[\]\{\}\\\| + String escaped = "\\.\\^\\$\\*\\+\\?\\(\\)\\[\\]\\{\\}\\\\\\|"; + + assertThat(OracleNoSqlLikeConverter.INSTANCE.contains(term)) + .isEqualTo(".*" + escaped + ".*"); + + assertThat(OracleNoSqlLikeConverter.INSTANCE.startsWith(term)) + .isEqualTo(escaped + ".*"); + + assertThat(OracleNoSqlLikeConverter.INSTANCE.endsWith(term)) + .isEqualTo(".*" + escaped); + } + } \ No newline at end of file From 7768d3498d6c62a1fa03d666b7e1d2302f80f83b Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 16 Aug 2025 06:42:22 +0100 Subject: [PATCH 65/68] feat: update abstract query builder Signed-off-by: Otavio Santana --- .../communication/AbstractQueryBuilder.java | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/AbstractQueryBuilder.java b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/AbstractQueryBuilder.java index 7a0f98e9a..a1a6f0f16 100644 --- a/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/AbstractQueryBuilder.java +++ b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/AbstractQueryBuilder.java @@ -65,10 +65,16 @@ protected void condition(CriteriaCondition condition, StringBuilder query, List< predicate(query, " >= ", document, params); return; case LIKE: + predicateLike(query, document); + return; case CONTAINS: + predicateContains(query, document); + return; case STARTS_WITH: + predicateStartsWith(query, document); + return; case ENDS_WITH: - predicateLike(query, document, params); + predicateEndsWith(query, document); return; case NOT: query.append(" NOT "); @@ -138,13 +144,33 @@ protected void predicate(StringBuilder query, } protected void predicateLike(StringBuilder query, - Element document, - List params) { + Element document) { String name = identifierOf(document.name()); Object value = OracleNoSqlLikeConverter.INSTANCE.convert(document.get()); query.append("regex_like(").append(name).append(", \"").append(value).append("\")"); } + protected void predicateStartsWith(StringBuilder query, + Element document) { + String name = identifierOf(document.name()); + var value = document.get() == null ? "" : document.get(String.class); + query.append("regex_like(").append(name).append(", \"").append(value).append("*").append("\")"); + } + + protected void predicateEndsWith(StringBuilder query, + Element document) { + String name = identifierOf(document.name()); + var value = document.get() == null ? "" : document.get(String.class); + query.append("regex_like(").append(name).append(", \"").append("*").append(value).append("\")"); + } + + protected void predicateContains(StringBuilder query, + Element document) { + String name = identifierOf(document.name()); + var value = document.get() == null ? "" : document.get(String.class); + query.append("regex_like(").append(name).append(", \"").append("*").append(value).append("*").append("\")"); + } + protected String identifierOf(String name) { return ' ' + table + "." + JSON_FIELD + "." + name + ' '; } From 816443f3bb32b1c3ba3f86168d0362740840e9c5 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 16 Aug 2025 06:44:38 +0100 Subject: [PATCH 66/68] feat: update implementation of abstractquery builder Signed-off-by: Otavio Santana --- .../oracle/communication/AbstractQueryBuilder.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/AbstractQueryBuilder.java b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/AbstractQueryBuilder.java index a1a6f0f16..debd127a9 100644 --- a/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/AbstractQueryBuilder.java +++ b/jnosql-oracle-nosql/src/main/java/org/eclipse/jnosql/databases/oracle/communication/AbstractQueryBuilder.java @@ -154,21 +154,24 @@ protected void predicateStartsWith(StringBuilder query, Element document) { String name = identifierOf(document.name()); var value = document.get() == null ? "" : document.get(String.class); - query.append("regex_like(").append(name).append(", \"").append(value).append("*").append("\")"); + query.append("regex_like(").append(name).append(", \"").append(OracleNoSqlLikeConverter.INSTANCE.startsWith(value)).append( + "\")"); } protected void predicateEndsWith(StringBuilder query, Element document) { String name = identifierOf(document.name()); var value = document.get() == null ? "" : document.get(String.class); - query.append("regex_like(").append(name).append(", \"").append("*").append(value).append("\")"); + query.append("regex_like(").append(name).append(", \"").append(OracleNoSqlLikeConverter.INSTANCE.endsWith(value)).append( + "\")"); } protected void predicateContains(StringBuilder query, Element document) { String name = identifierOf(document.name()); var value = document.get() == null ? "" : document.get(String.class); - query.append("regex_like(").append(name).append(", \"").append("*").append(value).append("*").append("\")"); + query.append("regex_like(").append(name).append(", \"").append(OracleNoSqlLikeConverter.INSTANCE.contains(value)).append( + "\")"); } protected String identifierOf(String name) { From 06757436cbf5d773f755fd4696bddbe47039e61f Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 16 Aug 2025 06:45:11 +0100 Subject: [PATCH 67/68] feat: include oracle nosql test Signed-off-by: Otavio Santana --- .../oracle/communication/OracleNoSQLDocumentManagerTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSQLDocumentManagerTest.java b/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSQLDocumentManagerTest.java index 307d1663f..4824522ed 100644 --- a/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSQLDocumentManagerTest.java +++ b/jnosql-oracle-nosql/src/test/java/org/eclipse/jnosql/databases/oracle/communication/OracleNoSQLDocumentManagerTest.java @@ -678,8 +678,6 @@ void shouldEndsWith() { }); } - - private CommunicationEntity createDocumentList() { var entity = CommunicationEntity.of("AppointmentBook"); entity.add(Element.of("_id", new Random().nextInt())); From 20ef418bca2b5bfde6c0fe3ab59ff6c46d7db447 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 16 Aug 2025 06:53:54 +0100 Subject: [PATCH 68/68] style: update on like to regex Signed-off-by: Otavio Santana --- .../databases/tinkerpop/communication/LikeToRegex.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/LikeToRegex.java b/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/LikeToRegex.java index 470ca9ccc..6fb1e5d08 100644 --- a/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/LikeToRegex.java +++ b/jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/LikeToRegex.java @@ -24,11 +24,12 @@ enum LikeToRegex { /** * Converts like pattern to regex pattern. + * * @param text the like pattern to convert * @return the regex pattern */ String likeToRegex(Object text) { - String like = text== null? null: text.toString(); + String like = text == null ? null : text.toString(); if (like == null) { return "(?!)"; } @@ -37,7 +38,10 @@ String likeToRegex(Object text) { for (int i = 0; i < like.length(); i++) { char c = like.charAt(i); if (c == '%' || c == '_') { - if (!lit.isEmpty()) { rx.append(java.util.regex.Pattern.quote(lit.toString())); lit.setLength(0); } + if (!lit.isEmpty()) { + rx.append(java.util.regex.Pattern.quote(lit.toString())); + lit.setLength(0); + } rx.append(c == '%' ? ".*" : "."); } else { lit.append(c);