Skip to content

Commit 0a7cd8f

Browse files
authored
Merge pull request #334 from eclipse-jnosql/include-support-bp
Include to support the new terms on Eclipse JNosQL [contains, endswith, startwith]
2 parents 731d1f4 + cd2d32e commit 0a7cd8f

File tree

33 files changed

+1130
-35
lines changed

33 files changed

+1130
-35
lines changed

CHANGELOG.adoc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,22 @@ and this project adheres to https://semver.org/spec/v2.0.0.html[Semantic Version
88

99
== [Unreleased]
1010

11+
=== Changed
12+
13+
- Update ArangoDB driver to 7.22.0
14+
- Update Apache Cassandra driver to 4.19.0
15+
- Update Couchbase driver to 3.9.0
16+
- Update Neo4J driver to 5.28.9
17+
- Update OrientDB driver to 3.2.43
18+
- Update Elasticsearch driver to 8.19.1
19+
- Update Apache Hbase to version 2.6.3
20+
- Update Jedis version to 6.1.0
21+
- Update Apache Tinkerpop core to 3.7.4
22+
23+
=== Added
24+
25+
- Include support to Contains, StartsWith, EndsWith for NoSQL databases
26+
1127
== [1.1.9] - 2025-07-30
1228

1329
=== Changed

jnosql-arangodb/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
<description>The Eclipse JNoSQL layer to ArangoDB</description>
3030

3131
<properties>
32-
<arango.driver>7.21.0</arango.driver>
32+
<arango.driver>7.22.0</arango.driver>
3333
</properties>
3434

3535
<dependencies>

jnosql-arangodb/src/main/java/org/eclipse/jnosql/databases/arangodb/communication/QueryAQLConverter.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import jakarta.data.Sort;
2020
import org.eclipse.jnosql.communication.TypeReference;
2121
import org.eclipse.jnosql.communication.ValueUtil;
22+
import org.eclipse.jnosql.communication.driver.StringMatch;
2223
import org.eclipse.jnosql.communication.semistructured.CriteriaCondition;
2324
import org.eclipse.jnosql.communication.semistructured.DeleteQuery;
2425
import org.eclipse.jnosql.communication.semistructured.Element;
@@ -153,6 +154,15 @@ private static void definesCondition(CriteriaCondition condition,
153154
case LIKE:
154155
appendCondition(aql, params, entity, document, LIKE);
155156
return;
157+
case CONTAINS:
158+
appendCondition(aql, params, entity, Element.of(document.name(), StringMatch.CONTAINS.format(document.get(String.class))), LIKE);
159+
return;
160+
case STARTS_WITH:
161+
appendCondition(aql, params, entity, Element.of(document.name(), StringMatch.STARTS_WITH.format(document.get(String.class))), LIKE);
162+
return;
163+
case ENDS_WITH:
164+
appendCondition(aql, params, entity, Element.of(document.name(), StringMatch.ENDS_WITH.format(document.get(String.class))), LIKE);
165+
return;
156166
case AND:
157167

158168
for (CriteriaCondition dc : document.get(new TypeReference<List<CriteriaCondition>>() {

jnosql-arangodb/src/test/java/org/eclipse/jnosql/databases/arangodb/communication/ArangoDBDocumentManagerTest.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,20 @@
1919
import org.assertj.core.api.SoftAssertions;
2020
import org.eclipse.jnosql.communication.TypeReference;
2121
import org.eclipse.jnosql.communication.semistructured.CommunicationEntity;
22+
import org.eclipse.jnosql.communication.semistructured.CriteriaCondition;
2223
import org.eclipse.jnosql.communication.semistructured.DeleteQuery;
2324
import org.eclipse.jnosql.communication.semistructured.Element;
2425
import org.eclipse.jnosql.communication.semistructured.Elements;
2526
import org.eclipse.jnosql.communication.semistructured.SelectQuery;
27+
import org.eclipse.jnosql.mapping.semistructured.MappingQuery;
2628
import org.junit.jupiter.api.AfterEach;
2729
import org.junit.jupiter.api.BeforeEach;
2830
import org.junit.jupiter.api.Test;
2931
import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
3032

3133
import java.util.ArrayList;
3234
import java.util.Arrays;
35+
import java.util.Collections;
3336
import java.util.HashMap;
3437
import java.util.List;
3538
import java.util.Map;
@@ -404,6 +407,51 @@ void shouldFindBetween2() {
404407
});
405408
}
406409

410+
@Test
411+
void shouldFindContains() {
412+
var entity = getEntity();
413+
414+
entityManager.insert(entity);
415+
var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.contains(Element.of("name",
416+
"lia")), COLLECTION_NAME, Collections.emptyList());
417+
418+
var result = entityManager.select(query).toList();
419+
SoftAssertions.assertSoftly(softly -> {
420+
softly.assertThat(result).hasSize(1);
421+
softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana");
422+
});
423+
}
424+
425+
@Test
426+
void shouldStartsWith() {
427+
var entity = getEntity();
428+
429+
entityManager.insert(entity);
430+
var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.startsWith(Element.of("name",
431+
"Pol")), COLLECTION_NAME, Collections.emptyList());
432+
433+
var result = entityManager.select(query).toList();
434+
SoftAssertions.assertSoftly(softly -> {
435+
softly.assertThat(result).hasSize(1);
436+
softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana");
437+
});
438+
}
439+
440+
@Test
441+
void shouldEndsWith() {
442+
var entity = getEntity();
443+
444+
entityManager.insert(entity);
445+
var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.endsWith(Element.of("name",
446+
"ana")), COLLECTION_NAME, Collections.emptyList());
447+
448+
var result = entityManager.select(query).toList();
449+
SoftAssertions.assertSoftly(softly -> {
450+
softly.assertThat(result).hasSize(1);
451+
softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana");
452+
});
453+
}
454+
407455
private CommunicationEntity getEntity() {
408456
CommunicationEntity entity = CommunicationEntity.of(COLLECTION_NAME);
409457
Map<String, Object> map = new HashMap<>();

jnosql-cassandra/pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
<description>The Eclipse JNoSQL layer to Cassandra</description>
3030

3131
<properties>
32-
<casandra.driver.version>4.17.0</casandra.driver.version>
32+
<casandra.driver.version>4.19.0</casandra.driver.version>
3333
</properties>
3434
<dependencies>
3535
<dependency>
@@ -42,12 +42,12 @@
4242
<version>${project.version}</version>
4343
</dependency>
4444
<dependency>
45-
<groupId>com.datastax.oss</groupId>
45+
<groupId>org.apache.cassandra</groupId>
4646
<artifactId>java-driver-core</artifactId>
4747
<version>${casandra.driver.version}</version>
4848
</dependency>
4949
<dependency>
50-
<groupId>com.datastax.oss</groupId>
50+
<groupId>org.apache.cassandra</groupId>
5151
<artifactId>java-driver-query-builder</artifactId>
5252
<version>${casandra.driver.version}</version>
5353
</dependency>

jnosql-couchbase/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
<dependency>
5050
<groupId>com.couchbase.client</groupId>
5151
<artifactId>java-client</artifactId>
52-
<version>3.8.3</version>
52+
<version>3.9.0</version>
5353
</dependency>
5454
<dependency>
5555
<groupId>org.testcontainers</groupId>

jnosql-couchbase/src/main/java/org/eclipse/jnosql/databases/couchbase/communication/N1QLBuilder.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.couchbase.client.java.json.JsonObject;
1818
import jakarta.data.Direction;
1919
import org.eclipse.jnosql.communication.TypeReference;
20+
import org.eclipse.jnosql.communication.driver.StringMatch;
2021
import org.eclipse.jnosql.communication.semistructured.CriteriaCondition;
2122
import org.eclipse.jnosql.communication.semistructured.Element;
2223
import org.eclipse.jnosql.communication.semistructured.SelectQuery;
@@ -113,6 +114,15 @@ private void condition(CriteriaCondition condition, StringBuilder n1ql, JsonObje
113114
case LIKE:
114115
predicate(n1ql, " LIKE ", document, params);
115116
return;
117+
case CONTAINS:
118+
predicate(n1ql, " LIKE ", Element.of(document.name(), StringMatch.CONTAINS.format(document.get(String.class))), params);
119+
return;
120+
case STARTS_WITH:
121+
predicate(n1ql, " LIKE ", Element.of(document.name(), StringMatch.STARTS_WITH.format(document.get(String.class))), params);
122+
return;
123+
case ENDS_WITH:
124+
predicate(n1ql, " LIKE ", Element.of(document.name(), StringMatch.ENDS_WITH.format(document.get(String.class))), params);
125+
return;
116126
case NOT:
117127
n1ql.append(" NOT ");
118128
condition(document.get(CriteriaCondition.class), n1ql, params, ids);

jnosql-couchbase/src/test/java/org/eclipse/jnosql/databases/couchbase/communication/CouchbaseDocumentManagerTest.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,19 @@
2222
import org.eclipse.jnosql.communication.TypeReference;
2323
import org.eclipse.jnosql.communication.keyvalue.BucketManager;
2424
import org.eclipse.jnosql.communication.semistructured.CommunicationEntity;
25+
import org.eclipse.jnosql.communication.semistructured.CriteriaCondition;
2526
import org.eclipse.jnosql.communication.semistructured.DeleteQuery;
2627
import org.eclipse.jnosql.communication.semistructured.Element;
2728
import org.eclipse.jnosql.communication.semistructured.Elements;
2829
import org.eclipse.jnosql.communication.semistructured.SelectQuery;
30+
import org.eclipse.jnosql.mapping.semistructured.MappingQuery;
2931
import org.junit.jupiter.api.AfterEach;
3032
import org.junit.jupiter.api.BeforeEach;
3133
import org.junit.jupiter.api.Test;
3234
import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
3335

3436
import java.util.ArrayList;
37+
import java.util.Collections;
3538
import java.util.HashMap;
3639
import java.util.HashSet;
3740
import java.util.List;
@@ -210,6 +213,51 @@ void shouldCount() {
210213
assertTrue(counted > 0);
211214
}
212215

216+
@Test
217+
void shouldFindContains() {
218+
var entity = getEntity();
219+
220+
entityManager.insert(entity);
221+
var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.contains(Element.of("name",
222+
"lia")), COLLECTION_PERSON_NAME, Collections.emptyList());
223+
224+
var result = entityManager.select(query).toList();
225+
SoftAssertions.assertSoftly(softly -> {
226+
softly.assertThat(result).hasSize(1);
227+
softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana");
228+
});
229+
}
230+
231+
@Test
232+
void shouldStartsWith() {
233+
var entity = getEntity();
234+
235+
entityManager.insert(entity);
236+
var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.startsWith(Element.of("name",
237+
"Pol")), COLLECTION_PERSON_NAME, Collections.emptyList());
238+
239+
var result = entityManager.select(query).toList();
240+
SoftAssertions.assertSoftly(softly -> {
241+
softly.assertThat(result).hasSize(1);
242+
softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana");
243+
});
244+
}
245+
246+
@Test
247+
void shouldEndsWith() {
248+
var entity = getEntity();
249+
250+
entityManager.insert(entity);
251+
var query = new MappingQuery(Collections.emptyList(), 0L, 0L, CriteriaCondition.endsWith(Element.of("name",
252+
"ana")), COLLECTION_PERSON_NAME, Collections.emptyList());
253+
254+
var result = entityManager.select(query).toList();
255+
SoftAssertions.assertSoftly(softly -> {
256+
softly.assertThat(result).hasSize(1);
257+
softly.assertThat(result.get(0).find("name").orElseThrow().get(String.class)).isEqualTo("Poliana");
258+
});
259+
}
260+
213261
private CommunicationEntity createSubdocumentList() {
214262
CommunicationEntity entity = CommunicationEntity.of(COLLECTION_APP_NAME);
215263
entity.add(Element.of("_id", "ids"));
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
2+
/*
3+
* Copyright (c) 2025 Contributors to the Eclipse Foundation
4+
* All rights reserved. This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License v1.0
6+
* and Apache License v2.0 which accompanies this distribution.
7+
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
8+
* and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php.
9+
*
10+
* You may elect to redistribute this code under either of these licenses.
11+
*
12+
* Contributors:
13+
*
14+
* Otavio Santana
15+
*/
16+
package org.eclipse.jnosql.communication.driver;
17+
18+
import java.util.Objects;
19+
20+
21+
/**
22+
* Represents strategies for matching string values in database queries,
23+
* typically for SQL {@code LIKE} clauses or NoSQL regex-like searches.
24+
* <p>
25+
* Each constant defines a specific way to wrap the given value
26+
* with wildcard symbols ({@code %}) to produce a matching pattern.
27+
* </p>
28+
* <p>
29+
* Example usage:
30+
* <pre>{@code
31+
* String pattern = StringMatch.CONTAINS.format("Ota"); // "%Ota%"
32+
* }</pre>
33+
*/
34+
public enum StringMatch {
35+
36+
/**
37+
* Exact match.
38+
* <p>
39+
* The given value will be used as-is, without adding any wildcards.
40+
* For SQL, this corresponds to {@code column = 'value'}.
41+
* </p>
42+
*/
43+
DEFAULT {
44+
@Override
45+
public String apply(String value) {
46+
return value;
47+
}
48+
},
49+
50+
/**
51+
* Contains match.
52+
* <p>
53+
* The given value will be wrapped with wildcards on both sides:
54+
* {@code %value%}. For SQL, this corresponds to
55+
* {@code column LIKE '%value%'}.
56+
* </p>
57+
*/
58+
CONTAINS {
59+
@Override
60+
public String apply(String value) {
61+
return "%" + value + "%";
62+
}
63+
},
64+
65+
/**
66+
* Starts-with match.
67+
* <p>
68+
* The given value will be followed by a wildcard:
69+
* {@code value%}. For SQL, this corresponds to
70+
* {@code column LIKE 'value%'}.
71+
* </p>
72+
*/
73+
STARTS_WITH {
74+
@Override
75+
public String apply(String value) {
76+
return value + "%";
77+
}
78+
},
79+
80+
/**
81+
* Ends-with match.
82+
* <p>
83+
* The given value will be preceded by a wildcard:
84+
* {@code %value}. For SQL, this corresponds to
85+
* {@code column LIKE '%value'}.
86+
* </p>
87+
*/
88+
ENDS_WITH {
89+
@Override
90+
public String apply(String value) {
91+
return "%" + value;
92+
}
93+
};
94+
95+
/**
96+
* Applies the match strategy to the given value, producing a pattern string.
97+
*
98+
* @param value the value to be transformed into a pattern
99+
* @return the pattern string, with wildcards applied according to the match strategy
100+
*/
101+
abstract String apply(String value);
102+
103+
/**
104+
* Formats the given value by applying the match strategy.
105+
* <p>
106+
* This method ensures the value is not {@code null} before applying the strategy.
107+
* </p>
108+
*
109+
* @param value the value to be transformed into a pattern
110+
* @return the pattern string, with wildcards applied according to the match strategy
111+
* @throws NullPointerException if {@code value} is {@code null}
112+
*/
113+
public String format(String value) {
114+
Objects.requireNonNull(value, "value cannot be null");
115+
return apply(value);
116+
}
117+
118+
}

0 commit comments

Comments
 (0)