Skip to content

Commit

Permalink
STITCH-2526: Add findOne() functionality (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
tkaye407 committed Mar 19, 2019
1 parent a286d82 commit bf9bc32
Show file tree
Hide file tree
Showing 19 changed files with 990 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,8 @@ fastlane/readme.md

# mac
.DS_Store

# eclipse
.project
.classpath
.settings/
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.mongodb.stitch.core.auth.providers.anonymous.AnonymousCredential
import com.mongodb.stitch.core.internal.common.BsonUtils
import com.mongodb.stitch.core.services.mongodb.remote.OperationType
import com.mongodb.stitch.core.services.mongodb.remote.RemoteCountOptions
import com.mongodb.stitch.core.services.mongodb.remote.RemoteFindOptions
import com.mongodb.stitch.core.services.mongodb.remote.RemoteUpdateOptions
import com.mongodb.stitch.core.testutils.CustomType
import org.bson.BsonDocument
Expand Down Expand Up @@ -131,6 +132,61 @@ class RemoteMongoClientIntTests : BaseStitchAndroidIntTest() {
}
}

@Test
fun testFindOne() {
val coll = getTestColl()

val doc1 = Document("hello", "world1")
val doc2 = Document("hello", "world2")
val doc3 = Document("hello", "world3")

// Test findOne() on empty collection with no filter and no options
assertNull(Tasks.await(coll.findOne()))

// Insert a document into the collection
Tasks.await(coll.insertOne(doc1))
assertEquals(1, Tasks.await(coll.count()))

// Test findOne() with no filter and no options
assertEquals(withoutId(Tasks.await(coll.findOne())), withoutId(doc1))

// Test findOne() with filter and no options
val result = Tasks.await(coll.findOne(Document("hello", "world1")))
assertEquals(withoutId(result), withoutId(doc1))

// Test findOne() with filter that does not match any documents and no options
assertNull(Tasks.await(coll.findOne(Document("hello", "worldDNE"))))

// Insert 2 more documents into the collection
Tasks.await(coll.insertMany(listOf(doc2, doc3)))
assertEquals(3, Tasks.await(coll.count()))

// test findOne() with projection and sort options
val projection = Document("hello", 1)
projection["_id"] = 0
val result2 = Tasks.await(coll.findOne(Document(), RemoteFindOptions()
.limit(2)
.projection(projection)
.sort(Document("hello", 1))))
assertEquals(result2, withoutId(doc1))

val result3 = Tasks.await(coll.findOne(Document(), RemoteFindOptions()
.limit(2)
.projection(projection)
.sort(Document("hello", -1))))
assertEquals(result3, withoutId(doc3))

// test findOne() properly fails
try {
Tasks.await(coll.findOne(Document("\$who", 1)))
fail()
} catch (ex: ExecutionException) {
assertTrue(ex.cause is StitchServiceException)
val svcEx = ex.cause as StitchServiceException
assertEquals(StitchServiceErrorCode.MONGODB_ERROR, svcEx.errorCode)
}
}

@Test
fun testFind() {
val coll = getTestColl()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.mongodb.stitch.core.services.mongodb.remote.ChangeStream;
import com.mongodb.stitch.core.services.mongodb.remote.RemoteCountOptions;
import com.mongodb.stitch.core.services.mongodb.remote.RemoteDeleteResult;
import com.mongodb.stitch.core.services.mongodb.remote.RemoteFindOptions;
import com.mongodb.stitch.core.services.mongodb.remote.RemoteInsertManyResult;
import com.mongodb.stitch.core.services.mongodb.remote.RemoteInsertOneResult;
import com.mongodb.stitch.core.services.mongodb.remote.RemoteUpdateOptions;
Expand Down Expand Up @@ -130,6 +131,63 @@ <NewDocumentT> RemoteMongoCollection<NewDocumentT> withDocumentClass(
*/
Task<Long> count(final Bson filter, final RemoteCountOptions options);

/**
* Finds a document in the collection.
*
* @return a task containing the result of the find one operation
*/
Task<DocumentT> findOne();

/**
* Finds a document in the collection.
*
* @param resultClass the class to decode each document into
* @param <ResultT> the target document type
* @return a task containing the result of the find one operation
*/
<ResultT> Task<ResultT> findOne(final Class<ResultT> resultClass);

/**
* Finds a document in the collection.
*
* @param filter the query filter
* @return a task containing the result of the find one operation
*/
Task<DocumentT> findOne(final Bson filter);

/**
* Finds a document in the collection.
*
* @param filter the query filter
* @param resultClass the class to decode each document into
* @param <ResultT> the target document type of the iterable.
* @return a task containing the result of the find one operation
*/
<ResultT> Task<ResultT> findOne(final Bson filter, final Class<ResultT> resultClass);

/**
* Finds a document in the collection.
*
* @param filter the query filter
* @param options A RemoteFindOptions struct
* @return a task containing the result of the find one operation
*/
Task<DocumentT> findOne(final Bson filter, final RemoteFindOptions options);

/**
* Finds a document in the collection.
*
* @param filter the query filter
* @param options A RemoteFindOptions struct
* @param resultClass the class to decode each document into
* @param <ResultT> the target document type of the iterable.
* @return a task containing the result of the find one operation
*/
<ResultT> Task<ResultT> findOne(
final Bson filter,
final RemoteFindOptions options,
final Class<ResultT> resultClass);

/**
* Finds all documents in the collection.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.mongodb.stitch.core.services.mongodb.remote.ChangeStream;
import com.mongodb.stitch.core.services.mongodb.remote.RemoteCountOptions;
import com.mongodb.stitch.core.services.mongodb.remote.RemoteDeleteResult;
import com.mongodb.stitch.core.services.mongodb.remote.RemoteFindOptions;
import com.mongodb.stitch.core.services.mongodb.remote.RemoteInsertManyResult;
import com.mongodb.stitch.core.services.mongodb.remote.RemoteInsertOneResult;
import com.mongodb.stitch.core.services.mongodb.remote.RemoteUpdateOptions;
Expand Down Expand Up @@ -140,6 +141,107 @@ public Long call() {
});
}


/**
* Finds a document in the collection
*
* @return a task containing the result of the find one operation
*/
public Task<DocumentT> findOne() {
return dispatcher.dispatchTask(new Callable<DocumentT>() {
@Override
public DocumentT call() {
return proxy.findOne();
}
});
}

/**
* Finds a document in the collection.
*
* @param resultClass the class to decode each document into
* @param <ResultT> the target document type
* @return a task containing the result of the find one operation
*/
public <ResultT> Task<ResultT> findOne(final Class<ResultT> resultClass) {
return dispatcher.dispatchTask(new Callable<ResultT>() {
@Override
public ResultT call() {
return proxy.findOne(resultClass);
}
});
}

/**
* Finds a document in the collection.
*
* @param filter the query filter
* @return a task containing the result of the find one operation
*/
public Task<DocumentT> findOne(final Bson filter) {
return dispatcher.dispatchTask(new Callable<DocumentT>() {
@Override
public DocumentT call() {
return proxy.findOne(filter);
}
});
}

/**
* Finds a document in the collection.
*
* @param filter the query filter
* @param resultClass the class to decode each document into
* @param <ResultT> the target document type of the iterable.
* @return a task containing the result of the find one operation
*/
public <ResultT> Task<ResultT> findOne(final Bson filter, final Class<ResultT> resultClass) {
return dispatcher.dispatchTask(new Callable<ResultT>() {
@Override
public ResultT call() {
return proxy.findOne(filter, resultClass);
}
});
}

/**
* Finds a document in the collection.
*
* @param filter the query filter
* @param options A RemoteFindOptions struct
* @return a task containing the result of the find one operation
*/
public Task<DocumentT> findOne(final Bson filter, final RemoteFindOptions options) {
return dispatcher.dispatchTask(new Callable<DocumentT>() {
@Override
public DocumentT call() {
return proxy.findOne(filter, options);
}
});
}

/**
* Finds a document in the collection.
*
* @param filter the query filter
* @param options A RemoteFindOptions struct
* @param resultClass the class to decode each document into
* @param <ResultT> the target document type of the iterable.
* @return a task containing the result of the find one operation
*/
public <ResultT> Task<ResultT> findOne(
final Bson filter,
final RemoteFindOptions options,
final Class<ResultT> resultClass) {
return dispatcher.dispatchTask(new Callable<ResultT>() {
@Override
public ResultT call() {
return proxy.findOne(filter, options, resultClass);
}
});
}


/**
* Finds all documents in the collection.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,13 @@
import javax.annotation.Nullable;
import javax.annotation.meta.When;

import org.bson.BsonType;
import org.bson.Document;
import org.bson.codecs.Decoder;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.configuration.CodecRegistries;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.json.JsonReader;

/**
* CoreStitchAuth is responsible for authenticating clients as well as acting as a client for
Expand Down Expand Up @@ -249,7 +253,15 @@ public <T> T doAuthenticatedRequest(final StitchAuthRequest stitchReq,
final Decoder<T> resultDecoder) {
final Response response = doAuthenticatedRequest(stitchReq);
try {
return BsonUtils.parseValue(IoUtils.readAllToString(response.getBody()), resultDecoder);
final String bodyStr = IoUtils.readAllToString(response.getBody());
final JsonReader bsonReader = new JsonReader(bodyStr);

// We must check this condition because the decoder will throw trying to decode null
if (bsonReader.readBsonType() == BsonType.NULL) {
return null;
}
return resultDecoder.decode(bsonReader, DecoderContext.builder().build());

} catch (final Exception e) {
throw new StitchRequestException(e, StitchRequestErrorCode.DECODING_ERROR);
}
Expand All @@ -276,8 +288,17 @@ public <T> T doAuthenticatedRequest(
final Response response = doAuthenticatedRequest(stitchReq);

try {
return BsonUtils.parseValue(IoUtils.readAllToString(
response.getBody()), resultClass, codecRegistry);
final String bodyStr = IoUtils.readAllToString(response.getBody());
final JsonReader bsonReader = new JsonReader(bodyStr);

// We must check this condition because the decoder will throw trying to decode null
if (bsonReader.readBsonType() == BsonType.NULL) {
return null;
}

final CodecRegistry newReg =
CodecRegistries.fromRegistries(BsonUtils.DEFAULT_CODEC_REGISTRY, codecRegistry);
return newReg.get(resultClass).decode(bsonReader, DecoderContext.builder().build());
} catch (final Exception e) {
throw new StitchRequestException(e, StitchRequestErrorCode.DECODING_ERROR);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.mongodb.stitch.core.services.mongodb.remote.ChangeEvent;
import com.mongodb.stitch.core.services.mongodb.remote.RemoteCountOptions;
import com.mongodb.stitch.core.services.mongodb.remote.RemoteDeleteResult;
import com.mongodb.stitch.core.services.mongodb.remote.RemoteFindOptions;
import com.mongodb.stitch.core.services.mongodb.remote.RemoteInsertManyResult;
import com.mongodb.stitch.core.services.mongodb.remote.RemoteInsertOneResult;
import com.mongodb.stitch.core.services.mongodb.remote.RemoteUpdateOptions;
Expand Down Expand Up @@ -103,6 +104,63 @@ <NewDocumentT> CoreRemoteMongoCollection<NewDocumentT> withDocumentClass(
*/
long count(final Bson filter, final RemoteCountOptions options);

/**
* Finds a document in the collection
*
* @return the resulting document
*/
DocumentT findOne();

/**
* Finds a document in the collection.
*
* @param resultClass the class to decode each document into
* @param <ResultT> the target document type
* @return the resulting document
*/
<ResultT> ResultT findOne(final Class<ResultT> resultClass);

/**
* Finds a document in the collection.
*
* @param filter the query filter
* @return the resulting document
*/
DocumentT findOne(final Bson filter);

/**
* Finds a document in the collection.
*
* @param filter the query filter
* @param resultClass the class to decode each document into
* @param <ResultT> the target document type of the iterable.
* @return the resulting document
*/
<ResultT> ResultT findOne(final Bson filter, final Class<ResultT> resultClass);

/**
* Finds a document in the collection.
*
* @param filter the query filter
* @param options A RemoteFindOptions struct
* @return the resulting document
*/
DocumentT findOne(final Bson filter, final RemoteFindOptions options);

/**
* Finds a document in the collection.
*
* @param filter the query filter
* @param options A RemoteFindOptions struct
* @param resultClass the class to decode each document into
* @param <ResultT> the target document type of the iterable.
* @return the resulting document
*/
<ResultT> ResultT findOne(
final Bson filter,
final RemoteFindOptions options,
final Class<ResultT> resultClass);

/**
* Finds all documents in the collection.
*
Expand Down

0 comments on commit bf9bc32

Please sign in to comment.