diff --git a/driver-core/src/main/com/mongodb/client/model/search/SearchConstructibleBsonElement.java b/driver-core/src/main/com/mongodb/client/model/search/SearchConstructibleBsonElement.java index c5a7e03a40..b16f465157 100644 --- a/driver-core/src/main/com/mongodb/client/model/search/SearchConstructibleBsonElement.java +++ b/driver-core/src/main/com/mongodb/client/model/search/SearchConstructibleBsonElement.java @@ -31,7 +31,7 @@ final class SearchConstructibleBsonElement extends AbstractConstructibleBsonElement implements MustCompoundSearchOperator, MustNotCompoundSearchOperator, ShouldCompoundSearchOperator, FilterCompoundSearchOperator, ExistsSearchOperator, TextSearchOperator, AutocompleteSearchOperator, - NumberNearSearchOperator, DateNearSearchOperator, GeoNearSearchOperator, RegexSearchOperator, QueryStringSearchOperator, + NumberNearSearchOperator, DateNearSearchOperator, GeoNearSearchOperator, RegexSearchOperator, QueryStringSearchOperator, WildcardSearchOperator, ValueBoostSearchScore, PathBoostSearchScore, ConstantSearchScore, FunctionSearchScore, GaussSearchScoreExpression, PathSearchScoreExpression, FacetSearchCollector, diff --git a/driver-core/src/main/com/mongodb/client/model/search/SearchOperator.java b/driver-core/src/main/com/mongodb/client/model/search/SearchOperator.java index 0f7f89c732..7c0edeafd9 100644 --- a/driver-core/src/main/com/mongodb/client/model/search/SearchOperator.java +++ b/driver-core/src/main/com/mongodb/client/model/search/SearchOperator.java @@ -339,6 +339,36 @@ static PhraseSearchOperator phrase(final Iterable paths, f .append("query", queryIterator.hasNext() ? queries : firstQuery)); } + /** + * Returns a {@link SearchOperator} that performs a search using a special characters in the search string that can match any character. + * + * @param query The string to search for. + * @param path The indexed field to be searched. + * @return The requested {@link SearchOperator}. + * @mongodb.atlas.manual atlas-search/wildcard/ wildcard operator + */ + static WildcardSearchOperator wildcard(final String query, final SearchPath path) { + return wildcard(singleton(notNull("query", query)), singleton(notNull("path", path))); + } + + /** + * Returns a {@link SearchOperator} that performs a search using a special characters in the search string that can match any character. + * + * @param queries The non-empty strings to search for. + * @param paths The non-empty index fields to be searched. + * @return The requested {@link SearchOperator}. + * @mongodb.atlas.manual atlas-search/wildcard/ wildcard operator + */ + static WildcardSearchOperator wildcard(final Iterable queries, final Iterable paths) { + Iterator queryIterator = notNull("queries", queries).iterator(); + isTrueArgument("queries must not be empty", queryIterator.hasNext()); + String firstQuery = queryIterator.next(); + Iterator pathIterator = notNull("paths", paths).iterator(); + isTrueArgument("paths must not be empty", pathIterator.hasNext()); + return new SearchConstructibleBsonElement("wildcard", new Document("query", queryIterator.hasNext() ? queries : firstQuery) + .append("path", combineToBsonValue(pathIterator, false))); + } + /** * Returns a {@link SearchOperator} that performs a search using a regular expression. * diff --git a/driver-core/src/main/com/mongodb/client/model/search/WildcardSearchOperator.java b/driver-core/src/main/com/mongodb/client/model/search/WildcardSearchOperator.java new file mode 100644 index 0000000000..651d9ffa57 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/search/WildcardSearchOperator.java @@ -0,0 +1,32 @@ +/* + * Copyright 2008-present MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mongodb.client.model.search; + +import com.mongodb.annotations.Beta; +import com.mongodb.annotations.Reason; +import com.mongodb.annotations.Sealed; + +/** + * @see SearchOperator#wildcard(String, SearchPath) + * @see SearchOperator#wildcard(Iterable, Iterable) + * @since 4.7 + */ +@Sealed +@Beta(Reason.CLIENT) +public interface WildcardSearchOperator extends SearchOperator { + @Override + WildcardSearchOperator score(SearchScore modifier); +} diff --git a/driver-core/src/test/functional/com/mongodb/client/model/search/AggregatesSearchIntegrationTest.java b/driver-core/src/test/functional/com/mongodb/client/model/search/AggregatesSearchIntegrationTest.java index 5926fbd7bf..fec1b7586c 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/search/AggregatesSearchIntegrationTest.java +++ b/driver-core/src/test/functional/com/mongodb/client/model/search/AggregatesSearchIntegrationTest.java @@ -86,6 +86,7 @@ import static com.mongodb.client.model.search.SearchOperator.regex; import static com.mongodb.client.model.search.SearchOperator.phrase; import static com.mongodb.client.model.search.SearchOperator.text; +import static com.mongodb.client.model.search.SearchOperator.wildcard; import static com.mongodb.client.model.search.SearchOptions.searchOptions; import static com.mongodb.client.model.search.SearchPath.fieldPath; import static com.mongodb.client.model.search.SearchPath.wildcardPath; @@ -614,7 +615,8 @@ private static Stream searchAndSearchMetaArgs() { near(Instant.ofEpochMilli(1), Duration.ofMillis(3), fieldPath("fieldName9")), phrase(fieldPath("fieldName10"), "term6"), regex(fieldPath("fieldName11"), "term7"), - queryString(fieldPath("fieldName12"), "term8") + queryString(fieldPath("fieldName12"), "term8"), + wildcard(asList("term10", "term11"), asList(wildcardPath("wildc*rd"), fieldPath("fieldName14"))) )) .minimumShouldMatch(1) .mustNot(singleton( diff --git a/driver-core/src/test/unit/com/mongodb/client/model/search/SearchOperatorTest.java b/driver-core/src/test/unit/com/mongodb/client/model/search/SearchOperatorTest.java index 0221d20aa1..a986b5a558 100644 --- a/driver-core/src/test/unit/com/mongodb/client/model/search/SearchOperatorTest.java +++ b/driver-core/src/test/unit/com/mongodb/client/model/search/SearchOperatorTest.java @@ -581,6 +581,48 @@ void near() { ); } + @Test + void wildcard() { + assertAll( + () -> assertThrows(IllegalArgumentException.class, () -> + // queries must not be empty + SearchOperator.wildcard(emptyList(), singleton(fieldPath("fieldName"))) + ), + () -> assertThrows(IllegalArgumentException.class, () -> + // paths must not be empty + SearchOperator.wildcard(singleton("term"), emptyList()) + ), + () -> assertEquals( + new BsonDocument("wildcard", + new BsonDocument("query", new BsonString("term")) + .append("path", fieldPath("fieldName").toBsonValue()) + ), + SearchOperator.wildcard( + "term", + fieldPath("fieldName")) + .toBsonDocument() + ), + () -> assertEquals( + new BsonDocument("wildcard", + new BsonDocument("query", new BsonArray(asList( + new BsonString("term1"), + new BsonString("term2")))) + .append("path", new BsonArray(asList( + fieldPath("fieldName").toBsonValue(), + wildcardPath("wildc*rd").toBsonValue()))) + ), + SearchOperator.wildcard( + asList( + "term1", + "term2"), + asList( + fieldPath("fieldName"), + wildcardPath("wildc*rd"))) + .toBsonDocument() + ) + ); + } + @Test void queryString() { assertAll( diff --git a/driver-scala/src/main/scala/org/mongodb/scala/model/search/SearchOperator.scala b/driver-scala/src/main/scala/org/mongodb/scala/model/search/SearchOperator.scala index ba5c4c046c..bccb75b366 100644 --- a/driver-scala/src/main/scala/org/mongodb/scala/model/search/SearchOperator.scala +++ b/driver-scala/src/main/scala/org/mongodb/scala/model/search/SearchOperator.scala @@ -228,6 +228,27 @@ object SearchOperator { def near(origin: Point, pivot: Number, paths: Iterable[_ <: FieldSearchPath]): GeoNearSearchOperator = JSearchOperator.near(origin, pivot, paths.asJava) + /** + * Returns a `SearchOperator` that enables queries which use special characters in the search string that can match any character. + * + * @param query The string to search for. + * @param path The indexed field to be searched. + * @return The requested `SearchOperator`. + * @see [[https://www.mongodb.com/docs/atlas/atlas-search/wildcard/ wildcard operator]] + */ + def wildcard(query: String, path: SearchPath): WildcardSearchOperator = JSearchOperator.wildcard(query, path) + + /** + * Returns a `SearchOperator` that enables queries which use special characters in the search string that can match any character. + * + * @param queries The non-empty strings to search for. + * @param paths The non-empty indexed fields to be searched. + * @return The requested `SearchOperator`. + * @see [[https://www.mongodb.com/docs/atlas/atlas-search/wildcard/ wildcard operator]] + */ + def wildcard(queries: Iterable[String], paths: Iterable[_ <: SearchPath]): WildcardSearchOperator = + JSearchOperator.wildcard(queries.asJava, paths.asJava) + /** * Returns a `SearchOperator` that supports querying a combination of indexed fields and values. * diff --git a/driver-scala/src/main/scala/org/mongodb/scala/model/search/package.scala b/driver-scala/src/main/scala/org/mongodb/scala/model/search/package.scala index b4e3c58d63..9fb3c9f4f4 100644 --- a/driver-scala/src/main/scala/org/mongodb/scala/model/search/package.scala +++ b/driver-scala/src/main/scala/org/mongodb/scala/model/search/package.scala @@ -198,6 +198,14 @@ package object search { @Beta(Array(Reason.CLIENT)) type GeoNearSearchOperator = com.mongodb.client.model.search.GeoNearSearchOperator + /** + * @see `SearchOperator.wildcard(String, SearchPath)` + * @see `SearchOperator.wildcard(Iterable, Iterable)` + */ + @Sealed + @Beta(Array(Reason.CLIENT)) + type WildcardSearchOperator = com.mongodb.client.model.search.WildcardSearchOperator + /** * @see `SearchOperator.queryString` */