/*
* Copyright (c) 2008-2015 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.acceptancetest.atomicoperations;
import com.mongodb.client.DatabaseTestCase;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.FindOneAndReplaceOptions;
import com.mongodb.client.model.ReturnDocument;
import com.mongodb.client.test.Worker;
import com.mongodb.client.test.WorkerCodecProvider;
import org.bson.Document;
import org.bson.codecs.BsonValueCodecProvider;
import org.bson.codecs.DocumentCodecProvider;
import org.bson.codecs.ValueCodecProvider;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.types.ObjectId;
import org.junit.Test;
import java.util.Date;
import static java.util.Arrays.asList;
import static org.bson.codecs.configuration.CodecRegistries.fromProviders;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
/**
* Documents and tests the functionality provided for find-and-replace atomic operations.
*
* @mongodb.driver.manual reference/command/findAndModify/ Find and Modify
*/
public class FindAndReplaceAcceptanceTest extends DatabaseTestCase {
private static final String KEY = "searchKey";
private static final String VALUE_TO_CARE_ABOUT = "Value to match";
@Test
public void shouldReplaceDocumentAndReturnOriginal() {
Document documentInserted = new Document(KEY, VALUE_TO_CARE_ABOUT).append("someOtherField", "withSomeOtherValue");
collection.insertOne(documentInserted);
assertThat(collection.count(), is(1L));
Document document = collection.findOneAndReplace(new Document(KEY, VALUE_TO_CARE_ABOUT),
new Document("foo", "bar").append("_id", documentInserted.get("_id")));
assertThat("Document, retrieved from replaceAndGet should match the document inserted before",
document, equalTo(documentInserted));
}
@Test
public void shouldReplaceAndReturnOriginalItemWithDocumentRequiringACustomEncoder() {
Worker pat = new Worker(new ObjectId(), "Pat", "Sales", new Date(), 0);
CodecRegistry codecRegistry = fromProviders(asList(new ValueCodecProvider(), new DocumentCodecProvider(),
new BsonValueCodecProvider(), new WorkerCodecProvider()));
MongoCollection<Worker> collection = database
.getCollection(getCollectionName(), Worker.class)
.withCodecRegistry(codecRegistry);
collection.insertOne(pat);
assertThat(collection.count(), is(1L));
Worker jordan = new Worker(pat.getId(), "Jordan", "Engineer", new Date(), 1);
Worker returnedDocument = collection.findOneAndReplace(new Document("name", "Pat"), jordan);
assertThat("Document, retrieved from getOneAndReplace, should match the document inserted before",
returnedDocument, equalTo(pat));
}
@Test
public void shouldReplaceAndReturnNewItemWithDocumentRequiringACustomEncoder() {
Worker pat = new Worker(new ObjectId(), "Pat", "Sales", new Date(), 3);
CodecRegistry codecRegistry = fromProviders(asList(new ValueCodecProvider(), new DocumentCodecProvider(),
new BsonValueCodecProvider(), new WorkerCodecProvider()));
MongoCollection<Worker> collection = database
.getCollection(getCollectionName(), Worker.class)
.withCodecRegistry(codecRegistry);
collection.insertOne(pat);
assertThat(collection.count(), is(1L));
Worker jordan = new Worker(pat.getId(), "Jordan", "Engineer", new Date(), 7);
Worker returnedDocument = collection.findOneAndReplace(new Document("name", "Pat"), jordan,
new FindOneAndReplaceOptions().returnDocument(ReturnDocument.AFTER));
assertThat("Worker retrieved from replaceOneAndGet should match the updated Worker",
returnedDocument, equalTo(jordan));
}
@Test
public void shouldReturnNewDocumentAfterReplaceWhenUsingReplaceOneAndGet() {
ObjectId id = new ObjectId();
Document documentInserted = new Document("_id", id).append(KEY, VALUE_TO_CARE_ABOUT);
Document documentReplacement = new Document("_id", id).append("foo", "bar");
collection.insertOne(documentInserted);
assertThat(collection.count(), is(1L));
Document document = collection.findOneAndReplace(new Document(KEY, VALUE_TO_CARE_ABOUT), documentReplacement,
new FindOneAndReplaceOptions().returnDocument(ReturnDocument.AFTER));
assertThat("Document, retrieved from replaceAndGet after change applied should match the document used as replacement",
document, equalTo(documentReplacement));
}
@Test
public void shouldReturnNullWhenNothingToReplaceForGetOneAndReplace() {
Document documentInserted = new Document(KEY, VALUE_TO_CARE_ABOUT);
collection.insertOne(documentInserted);
assertThat(collection.count(), is(1L));
Document document = collection.findOneAndReplace(new Document(KEY, "bar"), new Document("foo", "bar"));
assertNull("Document retrieved from getOneAndReplace should be null when no matching document found", document);
}
@Test
public void shouldReturnNullWhenNothingToReplaceForReplaceOneAndGet() {
Document documentInserted = new Document(KEY, VALUE_TO_CARE_ABOUT);
collection.insertOne(documentInserted);
assertThat(collection.count(), is(1L));
Document document = collection.findOneAndReplace(new Document(KEY, "bar"), new Document("foo", "bar"));
assertNull("Document retrieved from replaceOneAndGet should be null when no matching document found", document);
}
@Test
public void shouldInsertDocumentWhenFilterDoesNotMatchAnyDocumentsAndUpsertFlagIsSet() {
Document originalDocument = new Document(KEY, VALUE_TO_CARE_ABOUT);
collection.insertOne(originalDocument);
assertThat(collection.count(), is(1L));
Document replacementDocument = new Document("_id", new ObjectId()).append("foo", "bar");
Document document = collection.findOneAndReplace(new Document(KEY, "valueThatDoesNotMatch"),
replacementDocument,
new FindOneAndReplaceOptions()
.upsert(true)
.returnDocument(ReturnDocument.AFTER));
assertThat(collection.count(), is(2L));
assertThat("Document retrieved from replaceOneAndGet with filter that doesn't match should match the replacement document",
document, equalTo(replacementDocument));
}
}