Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for managing Atlas search indexes. #1158

Merged
merged 34 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
bb610dd
Add support for managing Atlas search indexes.
vbabanin Jul 5, 2023
123c8cd
Fix formatting, spotbugs issues.
vbabanin Jul 5, 2023
1dd433d
Fix formatting.
vbabanin Jul 5, 2023
8ce344a
Add javadoc.
vbabanin Jul 5, 2023
e89553c
Fix tests.
vbabanin Jul 6, 2023
f977401
Change javadoc.
vbabanin Jul 6, 2023
ef13ea8
Change assignment ordering.
vbabanin Jul 7, 2023
795d351
Remove wildcard imports.
vbabanin Jul 11, 2023
891d386
Change documentation.
vbabanin Jul 11, 2023
ab7d67d
Change javadoc.
vbabanin Jul 11, 2023
95b6810
Remove maxAwaitTime option for ListSearchIndexes iterable/publisher i…
vbabanin Jul 11, 2023
78dcd04
Update driver-core/src/main/com/mongodb/internal/operation/SearchInde…
vbabanin Jul 15, 2023
d88b6a8
Update driver-core/src/main/com/mongodb/client/model/SearchIndexModel…
vbabanin Jul 15, 2023
36c6bc8
Update driver-core/src/main/com/mongodb/internal/operation/AbstractWr…
vbabanin Jul 15, 2023
d7208ca
Update driver-core/src/main/com/mongodb/internal/operation/AbstractWr…
vbabanin Jul 15, 2023
d04f161
Update driver-core/src/main/com/mongodb/internal/operation/AbstractWr…
vbabanin Jul 15, 2023
a7298ad
Update driver-core/src/main/com/mongodb/internal/operation/CreateSear…
vbabanin Jul 15, 2023
f8879d1
Update driver-core/src/main/com/mongodb/internal/operation/CreateSear…
vbabanin Jul 15, 2023
eb25379
Apply suggestions from code review
vbabanin Jul 15, 2023
f83e870
Add retryable functionality.
vbabanin Jul 15, 2023
1554663
Change javadoc.
vbabanin Jul 15, 2023
ba83e2e
Change Java doc of the createSearchIndexes methods.
vbabanin Jul 17, 2023
da5bed0
Change verb from "remove" to "drop" in javadoc.
vbabanin Jul 17, 2023
7bae99b
Fix spotBugs.
vbabanin Jul 17, 2023
4d8365c
Move test files.
vbabanin Jul 17, 2023
a24d795
Remove whitespaces.
vbabanin Jul 17, 2023
7163044
Revert retryable writes.
vbabanin Jul 18, 2023
dc04204
Remove mentioning of nullubility from ListSearchIterable and Publishe…
vbabanin Jul 24, 2023
684c455
Change javadoc.
vbabanin Jul 24, 2023
2235541
Update driver-sync/src/main/com/mongodb/client/MongoCollection.java
vbabanin Jul 24, 2023
e7b8192
Fix spotless warnings.
vbabanin Jul 25, 2023
f5f6230
Make class internal.
vbabanin Jul 25, 2023
f63ff7b
Add null-check.
vbabanin Jul 26, 2023
5cbee87
Add null-check.
vbabanin Jul 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions driver-core/src/main/com/mongodb/assertions/Assertions.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,34 @@ public static <T> T notNull(final String name, final T value) {
return value;
}

/**
* Throw IllegalArgumentException if the values is null or contains null.
*
* <p><b>Note:</b> If performance is a concern, consider deferring the integrity validation
* to the point of actual data iteration to avoid incurring additional reference chasing for collections of complex objects.
* However, if performance considerations are low and it is acceptable to iterate over the data twice,
* this method can still be used for validation purposes.
*
* @param name the parameter name.
* @param values the values that should not contain null elements.
* @param <T> the type of elements in the collection.
* @return the input collection if it passes the null element validation.
* @throws java.lang.IllegalArgumentException if the input collection is null or contains null elements.
*/
public static <T> Iterable<T> notNullElements(final String name, final Iterable<T> values) {
if (values == null) {
throw new IllegalArgumentException(name + " can not be null");
}

for (T value : values) {
if (value == null){
throw new IllegalArgumentException(name + " can not contain null");
}
}

return values;
}

/**
* Throw IllegalArgumentException if the value is null.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* 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;

import com.mongodb.lang.Nullable;
import org.bson.conversions.Bson;

import static com.mongodb.assertions.Assertions.notNull;

/**
* A model describing the creation of a single Atlas Search index.
*
* @since 4.11
* @mongodb.server.release 7.0
*/
public class SearchIndexModel {
vbabanin marked this conversation as resolved.
Show resolved Hide resolved
private final String name;
stIncMale marked this conversation as resolved.
Show resolved Hide resolved
private final Bson definition;

/**
* Construct an instance with the given Atlas Search index definition.
*
* @param definition the search index definition.
*/
public SearchIndexModel(final Bson definition) {
stIncMale marked this conversation as resolved.
Show resolved Hide resolved
this(null, definition);
stIncMale marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Construct an instance with the given Atlas Search name and index definition.
*
* @param name the search index name
* @param definition the search index definition.
*/
public SearchIndexModel(@Nullable final String name, final Bson definition) {
stIncMale marked this conversation as resolved.
Show resolved Hide resolved
this.definition = notNull("definition", definition);
this.name = name;
}

/**
* Get the Atlas Search index definition.
*
* @return the index definition.
*/
public Bson getDefinition() {
return definition;
}

/**
* Get the Atlas Search index name.
*
* @return the search index name.
*/
@Nullable
public String getName() {
return name;
}

@Override
public String toString() {
return "SearchIndexModel{"
+ "name=" + name
+ ", definition=" + definition
+ '}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* 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.internal.operation;


import com.mongodb.MongoCommandException;
import com.mongodb.MongoNamespace;
import com.mongodb.WriteConcern;
import com.mongodb.internal.async.SingleResultCallback;
import com.mongodb.internal.binding.AsyncWriteBinding;
import com.mongodb.internal.binding.WriteBinding;
import com.mongodb.lang.Nullable;
import org.bson.BsonDocument;

import static com.mongodb.internal.async.ErrorHandlingResultCallback.errorHandlingCallback;
import static com.mongodb.internal.operation.CommandOperationHelper.executeCommand;
import static com.mongodb.internal.operation.CommandOperationHelper.executeCommandAsync;
import static com.mongodb.internal.operation.CommandOperationHelper.writeConcernErrorTransformer;
import static com.mongodb.internal.operation.CommandOperationHelper.writeConcernErrorWriteTransformer;
import static com.mongodb.internal.operation.OperationHelper.LOGGER;
import static com.mongodb.internal.operation.OperationHelper.releasingCallback;
import static com.mongodb.internal.operation.OperationHelper.withAsyncConnection;
import static com.mongodb.internal.operation.OperationHelper.withConnection;

/**
* An abstract class for defining operations for managing Atlas Search indexes.
*
* <p>This class is not part of the public API and may be removed or changed at any time</p>
*/
abstract class AbstractWriteSearchIndexOperation implements AsyncWriteOperation<Void>, WriteOperation<Void> {
private final MongoNamespace namespace;
private final WriteConcern writeConcern;
vbabanin marked this conversation as resolved.
Show resolved Hide resolved
vbabanin marked this conversation as resolved.
Show resolved Hide resolved

AbstractWriteSearchIndexOperation(final MongoNamespace mongoNamespace, @Nullable final WriteConcern writeConcern) {
this.namespace = mongoNamespace;
this.writeConcern = writeConcern;
}

@Override
public Void execute(final WriteBinding binding) {
return withConnection(binding, connection -> {
try {
executeCommand(binding, namespace.getDatabaseName(), buildCommand(), connection, writeConcernErrorTransformer());
stIncMale marked this conversation as resolved.
Show resolved Hide resolved
} catch (MongoCommandException mongoCommandException){
handleCommandException(mongoCommandException);
}
return null;
});
}

@Override
public void executeAsync(final AsyncWriteBinding binding, final SingleResultCallback<Void> callback) {
withAsyncConnection(binding, (connection, connectionException) -> {
SingleResultCallback<Void> errHandlingCallback = errorHandlingCallback(callback, LOGGER);
if (connectionException != null) {
errHandlingCallback.onResult(null, connectionException);
} else {
SingleResultCallback<Void> completionCallback = releasingCallback(errHandlingCallback, connection);
try {
executeCommandAsync(binding, namespace.getDatabaseName(),
buildCommand(), connection, writeConcernErrorWriteTransformer(),
getCommandExecutionCallback(completionCallback));
stIncMale marked this conversation as resolved.
Show resolved Hide resolved
} catch (Throwable commandExecutionException) {
completionCallback.onResult(null, commandExecutionException);
}
stIncMale marked this conversation as resolved.
Show resolved Hide resolved
}
});
}
stIncMale marked this conversation as resolved.
Show resolved Hide resolved

SingleResultCallback<Void> getCommandExecutionCallback(final SingleResultCallback<Void> completionCallback) {
return (result, commandExecutionException) -> completionCallback.onResult(null, commandExecutionException);
}

void handleCommandException(final MongoCommandException mongoCommandException) {
throw mongoCommandException;
}
stIncMale marked this conversation as resolved.
Show resolved Hide resolved

abstract BsonDocument buildCommand();

public MongoNamespace getNamespace() {
vbabanin marked this conversation as resolved.
Show resolved Hide resolved
return namespace;
}

public WriteConcern getWriteConcern() {
vbabanin marked this conversation as resolved.
Show resolved Hide resolved
return writeConcern;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public BsonValue getComment() {
return wrapped.getComment();
}

public AggregateOperation<T> comment(final BsonValue comment) {
public AggregateOperation<T> comment(@Nullable final BsonValue comment) {
stIncMale marked this conversation as resolved.
Show resolved Hide resolved
wrapped.comment(comment);
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ BsonValue getComment() {
return comment;
}

AggregateOperationImpl<T> comment(final BsonValue comment) {
AggregateOperationImpl<T> comment(@Nullable final BsonValue comment) {
this.comment = comment;
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import com.mongodb.client.model.InsertOneOptions;
import com.mongodb.client.model.RenameCollectionOptions;
import com.mongodb.client.model.ReplaceOptions;
import com.mongodb.client.model.SearchIndexModel;
import com.mongodb.client.model.UpdateOptions;
import com.mongodb.client.model.WriteModel;
import com.mongodb.client.model.changestream.FullDocument;
Expand All @@ -48,6 +49,7 @@
import com.mongodb.internal.client.model.AggregationLevel;
import com.mongodb.internal.client.model.FindOptions;
import com.mongodb.internal.client.model.changestream.ChangeStreamLevel;
import com.mongodb.lang.Nullable;
import org.bson.BsonDocument;
import org.bson.BsonTimestamp;
import org.bson.BsonValue;
Expand Down Expand Up @@ -274,6 +276,29 @@ public AsyncWriteOperation<Void> createIndexes(final List<IndexModel> indexes, f
return operations.createIndexes(indexes, options);
}

public AsyncWriteOperation<Void> createSearchIndexes(final List<SearchIndexModel> indexes) {
return operations.createSearchIndexes(indexes);
}

public AsyncWriteOperation<Void> updateSearchIndex(final String indexName, final Bson definition) {
return operations.updateSearchIndex(indexName, definition);
}

public AsyncWriteOperation<Void> dropSearchIndex(final String indexName) {
return operations.dropSearchIndex(indexName);
}

public <TResult> AsyncExplainableReadOperation<AsyncBatchCursor<TResult>> listSearchIndexes(final Class<TResult> resultClass,
final long maxTimeMS,
@Nullable final String indexName,
@Nullable final Integer batchSize,
@Nullable final Collation collation,
@Nullable final BsonValue comment,
@Nullable final Boolean allowDiskUse) {
return operations.listSearchIndexes(resultClass, maxTimeMS, indexName, batchSize, collation,
comment, allowDiskUse);
}

public AsyncWriteOperation<Void> dropIndex(final String indexName, final DropIndexOptions options) {
return operations.dropIndex(indexName, options);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* 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.internal.operation;

import com.mongodb.MongoNamespace;
import com.mongodb.WriteConcern;
import com.mongodb.lang.Nullable;
import org.bson.BsonArray;
import org.bson.BsonDocument;
import org.bson.BsonString;

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

import static com.mongodb.assertions.Assertions.assertNotNull;
import static com.mongodb.internal.operation.WriteConcernHelper.appendWriteConcernToCommand;

/**
* An operation that creates one or more Atlas Search indexes.
*
* <p>This class is not part of the public API and may be removed or changed at any time</p>
*/
class CreateSearchIndexesOperation extends AbstractWriteSearchIndexOperation {
vbabanin marked this conversation as resolved.
Show resolved Hide resolved
private static final String COMMAND_NAME = "createSearchIndexes";
private final List<SearchIndexRequest> indexRequests;

CreateSearchIndexesOperation(final MongoNamespace namespace, final List<SearchIndexRequest> indexRequests,
@Nullable final WriteConcern writeConcern) {
super(namespace, writeConcern);
this.indexRequests = assertNotNull(indexRequests);
}

private BsonArray convert(final List<SearchIndexRequest> requests) {
return requests.stream()
.map(this::convert)
.collect(Collectors.toCollection(BsonArray::new));
}
vbabanin marked this conversation as resolved.
Show resolved Hide resolved

private BsonDocument convert(final SearchIndexRequest request) {
vbabanin marked this conversation as resolved.
Show resolved Hide resolved
BsonDocument bsonIndexRequest = new BsonDocument();
String searchIndexName = request.getIndexName();
if (searchIndexName != null) {
bsonIndexRequest.append("name", new BsonString(searchIndexName));
}
bsonIndexRequest.append("definition", request.getDefinition());
return bsonIndexRequest;
}

@Override
BsonDocument buildCommand() {
BsonDocument command = new BsonDocument(COMMAND_NAME, new BsonString(getNamespace().getCollectionName()))
.append("indexes", convert(indexRequests));
appendWriteConcernToCommand(getWriteConcern(), command);
return command;
}
}
Loading