From 77c5a68c206dfb29df0e703e4d7436cb4c875ba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus=20R=C3=B8rbech?= Date: Tue, 5 Dec 2023 19:19:59 +0100 Subject: [PATCH] More API experiments --- .../kotlin/io/realm/kotlin/mongodb/User.kt | 6 +- .../mongodb/internal/MongoClientImpl.kt | 13 +- .../mongodb/internal/MongoCollectionImpl.kt | 83 +- .../mongodb/internal/MongoDatabaseImpl.kt | 19 +- .../realm/kotlin/mongodb/internal/UserImpl.kt | 5 +- .../realm/kotlin/mongodb/mongo/MongoClient.kt | 6 +- .../kotlin/mongodb/mongo/MongoCollection.kt | 549 +++---- .../kotlin/mongodb/mongo/MongoDatabase.kt | 10 +- .../mongodb/common/mongo/MongoClientTest.kt | 1456 +++++++++-------- 9 files changed, 1078 insertions(+), 1069 deletions(-) diff --git a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/User.kt b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/User.kt index c276cdfb00..64accd35ff 100644 --- a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/User.kt +++ b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/User.kt @@ -22,6 +22,8 @@ import io.realm.kotlin.mongodb.ext.customDataAsBsonDocument import io.realm.kotlin.mongodb.ext.profileAsBsonDocument import io.realm.kotlin.mongodb.mongo.MongoClient import io.realm.kotlin.mongodb.sync.SyncConfiguration +import org.mongodb.kbson.ExperimentalKBsonSerializerApi +import org.mongodb.kbson.serialization.EJson /** * A **user** holds the user's metadata and tokens for accessing App Services and Device Sync @@ -203,8 +205,8 @@ public interface User { public suspend fun linkCredentials(credentials: Credentials): User // TODO Doc - // TODO serializer argument - public fun mongoClient(serviceName: String): MongoClient + @OptIn(ExperimentalKBsonSerializerApi::class) + public fun mongoClient(serviceName: String, eJson: EJson? = null): MongoClient /** * Two Users are considered equal if they have the same user identity and are associated diff --git a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/MongoClientImpl.kt b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/MongoClientImpl.kt index 3ba5277d7b..77ff03f9d6 100644 --- a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/MongoClientImpl.kt +++ b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/MongoClientImpl.kt @@ -18,11 +18,18 @@ package io.realm.kotlin.mongodb.internal import io.realm.kotlin.mongodb.mongo.MongoClient import io.realm.kotlin.mongodb.mongo.MongoDatabase +import org.mongodb.kbson.ExperimentalKBsonSerializerApi +import org.mongodb.kbson.serialization.EJson +@OptIn(ExperimentalKBsonSerializerApi::class) @PublishedApi internal class MongoClientImpl( - @PublishedApi - internal val user: UserImpl, override val serviceName: String) : MongoClient { - override fun database(databaseName: String): MongoDatabase = MongoDatabaseImpl(this, databaseName) + internal val user: UserImpl, + override val serviceName: String, + val eJson: EJson, +) : MongoClient { + + override fun database(databaseName: String, eJson: EJson?): MongoDatabase = + MongoDatabaseImpl(this, databaseName, eJson ?: this.eJson) } diff --git a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/MongoCollectionImpl.kt b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/MongoCollectionImpl.kt index 172f083d76..e8e541fcc9 100644 --- a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/MongoCollectionImpl.kt +++ b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/MongoCollectionImpl.kt @@ -17,49 +17,94 @@ package io.realm.kotlin.mongodb.internal import io.realm.kotlin.annotations.ExperimentalRealmSerializerApi -import io.realm.kotlin.mongodb.ext.CallBuilder import io.realm.kotlin.mongodb.ext.call import io.realm.kotlin.mongodb.mongo.MongoCollection +import io.realm.kotlin.mongodb.mongo.insertMany +import org.mongodb.kbson.BsonArray import org.mongodb.kbson.BsonDocument import org.mongodb.kbson.BsonInt64 import org.mongodb.kbson.BsonString import org.mongodb.kbson.BsonValue +import org.mongodb.kbson.ExperimentalKBsonSerializerApi +import org.mongodb.kbson.serialization.EJson +import org.mongodb.kbson.serialization.decodeFromBsonValue +import org.mongodb.kbson.serialization.encodeToBsonValue +@OptIn(ExperimentalKBsonSerializerApi::class, ExperimentalRealmSerializerApi::class) @PublishedApi -internal open class MongoCollectionImpl( - +internal class MongoCollectionImpl @OptIn(ExperimentalKBsonSerializerApi::class) constructor( @PublishedApi internal val database: MongoDatabaseImpl, override val name: String, -) : MongoCollection { + val eJson: EJson, +): MongoCollection { val client = this.database.client val user = client.user val functions = user.functions + val defaults: Map = mapOf( "database" to BsonString(database.name), "collection" to BsonString(name), ) - override suspend fun count(filter: BsonDocument?, limit: Long?): Int { - @OptIn(ExperimentalRealmSerializerApi::class) - return user.functions.call("count") { + @ExperimentalRealmSerializerApi + private suspend inline fun call(name: String, crossinline document: MutableMap.()-> Unit): R { + return user.functions.call(name) { serviceName(client.serviceName) - val args = defaults.toMutableMap() - limit?.let { args.put("limit", BsonInt64(limit)) } - filter?.let { args.put("query", it) } - add(BsonDocument(args)) + val doc = defaults.toMutableMap() + document(doc) + add(doc) + } + } + + @PublishedApi + internal suspend fun count(filter: BsonDocument? = null, limit: Long? = null): Long { + return call("count") { + filter?.let { put("query", it) } + limit?.let { put("limit", BsonInt64(it)) } } } + + @PublishedApi + internal suspend fun findOne(filter: BsonDocument? = null, projection: BsonDocument? = null, sort: BsonDocument? = null): BsonValue = + call("findOne") { + filter?.let { put("query", it) } + projection?.let { put("projection", it) } + sort?.let { put("sort", it) } + } + + @PublishedApi + internal suspend fun find(filter: BsonDocument? = null, projection: BsonDocument? = null, sort: BsonDocument? = null, limit: Long? = null): BsonValue = + call("find") { + filter?.let { put("query", it) } + projection?.let { put("projection", it) } + sort?.let { put("sort", it) } + limit?.let { put("limit", BsonInt64(it)) } + } + + @PublishedApi + internal suspend fun aggregate(pipeline: List): List = + call("aggregate") { put("pipeline", BsonArray(pipeline)) }.asArray().toList() + + @PublishedApi + internal suspend fun insertOne(document: BsonDocument): BsonValue = + call("insertOne") { put("document", document) }.asDocument()["insertedId"]!! + + @PublishedApi + internal suspend fun insertMany(documents: List): List = + call("insertMany") { + put("documents", BsonArray(documents)) + }.asDocument().get("insertedIds")!!.asArray().toList() } -@ExperimentalRealmSerializerApi +@OptIn(ExperimentalKBsonSerializerApi::class) @PublishedApi -internal suspend inline fun MongoCollectionImpl.call(name: String, crossinline document: MutableMap.()-> Unit): BsonValue { - return user.functions.call(name) { - serviceName(client.serviceName) - val doc = this@call.defaults.toMutableMap() - document(doc) - add(doc) - } +internal inline fun MongoCollectionImpl<*, *>.decodeFromBsonValue(bsonValue: BsonValue): R { + return eJson.decodeFromBsonValue(bsonValue) +} +@OptIn(ExperimentalKBsonSerializerApi::class) +@PublishedApi +internal inline fun MongoCollectionImpl<*, *>.encodeToBsonValue(value: R): BsonValue { + return eJson.encodeToBsonValue(value) } diff --git a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/MongoDatabaseImpl.kt b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/MongoDatabaseImpl.kt index 69c79a68d3..9c71dfeb82 100644 --- a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/MongoDatabaseImpl.kt +++ b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/MongoDatabaseImpl.kt @@ -18,24 +18,23 @@ package io.realm.kotlin.mongodb.internal import io.realm.kotlin.mongodb.mongo.MongoCollection import io.realm.kotlin.mongodb.mongo.MongoDatabase -import io.realm.kotlin.mongodb.mongo.TypedMongoCollection -import io.realm.kotlin.mongodb.mongo.TypedMongoCollectionImpl import org.mongodb.kbson.BsonValue +import org.mongodb.kbson.ExperimentalKBsonSerializerApi +import org.mongodb.kbson.serialization.EJson @PublishedApi -internal class MongoDatabaseImpl( +@OptIn(ExperimentalKBsonSerializerApi::class) +internal class MongoDatabaseImpl constructor( @PublishedApi internal val client: MongoClientImpl, override val name: String, + val eJson: EJson, ) : MongoDatabase { - override fun collection(collectionName: String): MongoCollection = - MongoCollectionImpl(this, collectionName) - override fun typedCollectionbson(collectionName: String): TypedMongoCollection { - return TypedMongoCollectionImpl(collection(collectionName) as MongoCollectionImpl) + override fun collection(collectionName: String): MongoCollection { + return MongoCollectionImpl(this, collectionName, this.eJson) } - override fun typedCollection(collectionName: String): TypedMongoCollection { - return TypedMongoCollectionImpl(collection(collectionName) as MongoCollectionImpl) - } + override fun collection(collectionName: String, eJson: EJson?): MongoCollection = + MongoCollectionImpl(this, collectionName, eJson ?: this.eJson) } diff --git a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/UserImpl.kt b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/UserImpl.kt index 0cfb36b840..d429dd78d8 100644 --- a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/UserImpl.kt +++ b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/UserImpl.kt @@ -32,6 +32,8 @@ import io.realm.kotlin.mongodb.mongo.MongoClient import io.realm.kotlin.mongodb.mongo.MongoCollection import io.realm.kotlin.mongodb.mongo.MongoDatabase import kotlinx.coroutines.channels.Channel +import org.mongodb.kbson.ExperimentalKBsonSerializerApi +import org.mongodb.kbson.serialization.EJson // TODO Public due to being a transitive dependency to SyncConfigurationImpl public class UserImpl( @@ -185,7 +187,8 @@ public class UserImpl( } } - override fun mongoClient(serviceName: String): MongoClient = MongoClientImpl(this, serviceName) + @OptIn(ExperimentalKBsonSerializerApi::class) + override fun mongoClient(serviceName: String, eJson: EJson?): MongoClient = MongoClientImpl(this, serviceName, eJson ?: app.configuration.ejson) override fun equals(other: Any?): Boolean { if (this === other) return true diff --git a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/mongo/MongoClient.kt b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/mongo/MongoClient.kt index 93cd022da0..b890b49551 100644 --- a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/mongo/MongoClient.kt +++ b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/mongo/MongoClient.kt @@ -16,6 +16,9 @@ package io.realm.kotlin.mongodb.mongo +import org.mongodb.kbson.ExperimentalKBsonSerializerApi +import org.mongodb.kbson.serialization.EJson + /** * The remote MongoClient used for working with data in MongoDB remotely via Realm. */ @@ -23,5 +26,6 @@ public interface MongoClient { public val serviceName: String - public fun database(databaseName: String): MongoDatabase + @OptIn(ExperimentalKBsonSerializerApi::class) + public fun database(databaseName: String, eJson: EJson? = null): MongoDatabase } diff --git a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/mongo/MongoCollection.kt b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/mongo/MongoCollection.kt index 195060396a..6109d5d5be 100644 --- a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/mongo/MongoCollection.kt +++ b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/mongo/MongoCollection.kt @@ -16,360 +16,299 @@ // TODO - QUESTIONS // - should we allow serialization of update, sort and projection arguments? + package io.realm.kotlin.mongodb.mongo -import io.realm.kotlin.annotations.ExperimentalRealmSerializerApi +import io.realm.kotlin.internal.util.Validation import io.realm.kotlin.mongodb.internal.MongoCollectionImpl -import io.realm.kotlin.mongodb.internal.call -import io.realm.kotlin.mongodb.internal.serializerOrRealmBuiltInSerializer -import kotlinx.serialization.KSerializer -import org.mongodb.kbson.BsonArray -import org.mongodb.kbson.BsonBoolean +import io.realm.kotlin.mongodb.internal.decodeFromBsonValue import org.mongodb.kbson.BsonDocument -import org.mongodb.kbson.BsonInt64 import org.mongodb.kbson.BsonValue import org.mongodb.kbson.ExperimentalKBsonSerializerApi import org.mongodb.kbson.serialization.EJson import org.mongodb.kbson.serialization.decodeFromBsonValue +import org.mongodb.kbson.serialization.encodeToBsonValue import kotlin.jvm.JvmName -public interface MongoCollection { +public interface MongoCollection { public val name: String - public suspend fun count(filter: BsonDocument? = null, limit: Long? = null): Int -// public suspend fun findOne(filter: BsonDocument? = null, projection: BsonDocument? = null, sort: BsonDocument? = null): BsonValue { -// TODO() -// } - @ExperimentalRealmSerializerApi - public fun typedCollection(): TypedMongoCollection = TypedMongoCollectionImpl(this as MongoCollectionImpl) -} - -public interface TypedMongoCollection: MongoCollection { } - -@PublishedApi -internal class TypedMongoCollectionImpl(collectionImpl: MongoCollectionImpl): TypedMongoCollection, MongoCollectionImpl(collectionImpl.database, collectionImpl.name) - -@OptIn(ExperimentalKBsonSerializerApi::class) -@ExperimentalRealmSerializerApi -public suspend inline fun MongoCollection.findOne(filter: BsonDocument? = null, projection: BsonDocument? = null, sort: BsonDocument? = null, serializer: KSerializer? = null): R { - val value = (this as MongoCollectionImpl).call("findOne") { - filter?.let { put("query", it) } - projection?.let { put("projection", it) } - sort?.let { put("sort", it) } + @OptIn(ExperimentalKBsonSerializerApi::class) + public fun typedCollection(eJson: EJson? = null): MongoCollection { + val source = this as MongoCollectionImpl<*, *> + return MongoCollectionImpl(source.database, source.name, eJson ?: source.eJson) } - return decodeFromBsonValue(value, serializer) } -@OptIn(ExperimentalKBsonSerializerApi::class) -@PublishedApi -internal inline fun MongoCollection.decodeFromBsonValue(bsonValue: BsonValue, serializer: KSerializer? = null): R { - val serializer = serializer ?: (this as MongoCollectionImpl).functions.app.configuration.ejson.serializersModule.serializerOrRealmBuiltInSerializer() - return (this as MongoCollectionImpl).functions.app.configuration.ejson.decodeFromBsonValue(serializer, bsonValue) +public suspend inline fun MongoCollection<*, *>.count(filter: BsonDocument? = null, limit: Long? = null): Long { + return (this as MongoCollectionImpl).count(filter, limit) } - -public class ClientOption { - +public suspend inline fun MongoCollection.findOne(filter: BsonDocument? = null, projection: BsonDocument? = null, sort: BsonDocument? = null): T { + return (this as MongoCollectionImpl).decodeFromBsonValue(findOne(filter, projection, sort)) } -@PublishedApi -internal interface FilterOptionInternal { - var filter: BsonDocument? -} -@PublishedApi -internal interface LimitOptionInternal { - var limit: Long? +@JvmName("findOneTyped") +public suspend inline fun MongoCollection<*, *>.findOne(filter: BsonDocument? = null, projection: BsonDocument? = null, sort: BsonDocument? = null): T { + return (this as MongoCollection).findOne(filter, projection, sort) } -public interface LimitOption { } -public fun LimitOption.limit(limit: Long) { - (this as LimitOptionInternal).limit = limit -} -public interface FilterOption { } -public fun FilterOption.filter(json: String) { - (this as FilterOptionInternal).filter = BsonDocument(json) -} -@ExperimentalKBsonSerializerApi -public inline fun FilterOption.filter(argument: T) { - filter(argument, EJson.serializersModule.serializerOrRealmBuiltInSerializer()) -} @OptIn(ExperimentalKBsonSerializerApi::class) -public inline fun FilterOption.filter(argument: T, serializer: KSerializer) { - (this as FilterOptionInternal).filter = EJson.encodeToBsonValue(serializer, argument).asDocument() -} -public interface ProjectionOption -public interface SortOption - -public interface CountOptions : LimitOption, FilterOption -public interface FindOneOptions : LimitOption, FilterOption, SortOption, ProjectionOption - -@PublishedApi -internal class FindOptionsInternal: FindOneOptions, FilterOptionInternal, LimitOptionInternal { - override var filter: BsonDocument? = null - override var limit: Long? = null -} - -@OptIn(ExperimentalKBsonSerializerApi::class) -@ExperimentalRealmSerializerApi -public suspend inline fun MongoCollection.count(filter: BsonDocument, limit: Long): Long { - return EJson.decodeFromBsonValue((this as MongoCollectionImpl).call("findOne") { - put("query", filter) - put("limit", BsonInt64(limit)) - }) +public suspend inline fun MongoCollection.find(filter: BsonDocument? = null, projection: BsonDocument? = null, sort: BsonDocument? = null, limit: Long? = null): List { + Validation.isType>(this, "") + val objects = find(filter, projection, sort, limit).asArray().toList() + return if (T::class == BsonValue::class) { objects as List } else {objects.map {EJson.decodeFromBsonValue(it) } } } - -//public suspend inline fun findOne(filter: Bson = {}, options: FindOptions(limit, projection, sort)): T -// query -// findoptions -// limit -// projection -// sort - -@OptIn(ExperimentalKBsonSerializerApi::class) -@ExperimentalRealmSerializerApi -public suspend inline fun MongoCollection.findOne(configuration: FindOneOptions.() -> Unit): T { - val options = FindOptionsInternal() - configuration(options) - val response = (this as MongoCollectionImpl).call("findOne") { - options.filter?.let { put("query", it) } -// options.projection?.let { put("projection", it) } -// options.sort?.let { put("sort", it) } - } - return EJson.decodeFromBsonValue(response) +@JvmName("findTyped") +public suspend inline fun MongoCollection<*, *>.find(filter: BsonDocument? = null, projection: BsonDocument? = null, sort: BsonDocument? = null, limit: Long? = null ): List { + return (this as MongoCollection).find(filter, projection, sort, limit) } @OptIn(ExperimentalKBsonSerializerApi::class) -@ExperimentalRealmSerializerApi -public suspend inline fun MongoCollection.find(filter: BsonDocument? = null, limit: Long? = null, projection: BsonDocument? = null, sort: BsonDocument? = null): List { - val objects = (this as MongoCollectionImpl).call("find") { - filter?.let { put("query", it) } - projection?.let { put("projection", it) } - sort?.let { put("sort", it) } - limit?.let { put("limit", BsonInt64(limit)) } - }.asArray().toList() - return if (T::class == BsonValue::class) { objects as List } else {objects.map {EJson.decodeFromBsonValue(it) } } +public suspend inline fun MongoCollection.aggregate(pipeline: List): List { + Validation.isType>(this, "") + val objects = aggregate(pipeline) + return if (T::class == BsonValue::class) { objects as List } else { objects.map { EJson.decodeFromBsonValue(it) } } } -//@ExperimentalRealmSerializerApi -//@OptIn(ExperimentalKBsonSerializerApi::class) -//public suspend inline fun MongoCollection.insertOne(document: T): R { -// val value: KSerializer = EJson.serializersModule.serializerOrRealmBuiltInSerializer() -// val x: BsonValue = EJson.encodeToBsonValue(value, document) -// return (this as MongoCollectionImpl).call("insertOne") { -// put("document", x) -// } -//} - -//@ExperimentalRealmSerializerApi -//@OptIn(ExperimentalKBsonSerializerApi::class) -//public suspend inline fun MongoCollection.insertOneReturnId(document: T): ObjectId { -// val encodedDocument: BsonValue = EJson.encodeToBsonValue( -// EJson.serializersModule.serializerOrRealmBuiltInSerializer(), -// document -// ) -// return (this as MongoCollectionImpl).call("insertOne") { -// put("document", encodedDocument) -// }.asDocument().get("insertedId")!!.asObjectId() -//} - -@ExperimentalRealmSerializerApi -@OptIn(ExperimentalKBsonSerializerApi::class) -public suspend inline fun MongoCollection.aggregate(pipeline: List): List { - val insertedId: List = (this as MongoCollectionImpl).call("aggregate") { - put("pipeline", BsonArray(pipeline)) - }.asArray().toList() - return if (T::class == BsonValue::class) { insertedId as List } else { insertedId.map { EJson.decodeFromBsonValue(it) } } +@JvmName("aggregateTyped") +public suspend inline fun MongoCollection<*, *>.aggregate(pipeline: List): List { + return (this as MongoCollection).aggregate(pipeline) } -@ExperimentalRealmSerializerApi @OptIn(ExperimentalKBsonSerializerApi::class) -public suspend inline fun MongoCollection.insertOne(document: T): R { - val encodedDocument: BsonValue = EJson.encodeToBsonValue( EJson.serializersModule.serializerOrRealmBuiltInSerializer(), document ) - val insertedId: BsonValue = (this as MongoCollectionImpl).call("insertOne") { - put("document", encodedDocument) - }.asDocument().get("insertedId")!! +public suspend inline fun MongoCollection.insertOne(document: T): R { + Validation.isType>(this, "") + val encodedDocument: BsonDocument = eJson.encodeToBsonValue(document).asDocument() + val insertedId = insertOne(encodedDocument) return if (insertedId is R) { insertedId } else { EJson.decodeFromBsonValue(insertedId) } } +@JvmName("insertOneTyped") +public suspend inline fun MongoCollection<*, *>.insertOne(document: T): R { + return (this as MongoCollection).insertOne(document) +} -// insertMany(docList): Map TypedMongoCollection.insertMany( +public suspend inline fun MongoCollection.insertMany( documents: Collection, ): List { - val encodedDocument: BsonValue = EJson.encodeToBsonValue( - EJson.serializersModule.serializerOrRealmBuiltInSerializer(), - documents - ) - val insertedId: List = (this as MongoCollectionImpl).call("insertMany") { - put("documents", encodedDocument) - }.asDocument().get("insertedIds")!!.asArray().toList() + Validation.isType>(this, "") + val encodedDocuments: List = documents.map { eJson.encodeToBsonValue(it).asDocument() } + val insertedIds: List = insertMany(encodedDocuments) return if (R::class == BsonValue::class) { - insertedId as List + insertedIds as List } else { - insertedId.map { decodeFromBsonValue(it) } + insertedIds.map { (this as MongoCollectionImpl).decodeFromBsonValue(it) } } } -@ExperimentalRealmSerializerApi -public suspend inline fun TypedMongoCollection<*, *>.insertMany(documents: Collection): List = - (this as TypedMongoCollectionImpl).insertMany(documents) - -@ExperimentalRealmSerializerApi -@OptIn(ExperimentalKBsonSerializerApi::class) -public suspend inline fun MongoCollection.insertMany(documents: Collection): List { - val encodedDocument: BsonValue = EJson.encodeToBsonValue(EJson.serializersModule.serializerOrRealmBuiltInSerializer(), documents) - val insertedId: List = (this as MongoCollectionImpl).call("insertMany") { - put("documents", encodedDocument) - }.asDocument().get("insertedIds")!!.asArray().toList() - return if (R::class == BsonValue::class) { insertedId as List } else { insertedId.map { EJson.decodeFromBsonValue(it) } } -} - -// deleteOne(filter): Count -// query -@ExperimentalRealmSerializerApi -@OptIn(ExperimentalKBsonSerializerApi::class) -public suspend inline fun MongoCollection.deleteOne(filter: BsonDocument): Boolean { -// val encodedDocument: BsonValue = EJson.encodeToBsonValue(EJson.serializersModule.serializerOrRealmBuiltInSerializer(), documents) - val insertedId: BsonValue = (this as MongoCollectionImpl).call("deleteOne") { - put("query", filter) - }.asDocument().get("deletedCount")!! - val decodeFromBsonValue = EJson.decodeFromBsonValue(insertedId) - return when(decodeFromBsonValue) { - 0L -> false - 1L -> true - else -> TODO("Unexpected $decodeFromBsonValue") - } +@JvmName("insertManyTyped") +public suspend inline fun MongoCollection<*, *>.insertMany(documents: Collection): List { + return (this as MongoCollection).insertMany(documents) } +//@OptIn(ExperimentalKBsonSerializerApi::class) +//public suspend inline fun MongoCollection<*, *>.deleteOne(filter: BsonDocument): Boolean { +//// val encodedDocument: BsonValue = EJson.encodeToBsonValue(EJson.serializersModule.serializerOrRealmBuiltInSerializer(), documents) +// val insertedId: BsonValue = (this as BsonMongoCollection).call("deleteOne") { +// put("query", filter) +// }.asDocument().get("deletedCount")!! +// val decodeFromBsonValue = EJson.decodeFromBsonValue(insertedId) +// return when(decodeFromBsonValue) { +// 0L -> false +// 1L -> true +// else -> TODO("Unexpected $decodeFromBsonValue") +// } +//} +// +// +//// deleteMany(filter): Count +//// query +//@ExperimentalRealmSerializerApi +//@OptIn(ExperimentalKBsonSerializerApi::class) +//public suspend inline fun MongoCollection<*, *>.deleteMany(filter: BsonDocument): Long { +// val insertedId: BsonValue = (this as BsonMongoCollection).call("deleteMany") { +// put("query", filter) +// }.asDocument().get("deletedCount")!! +// return EJson.decodeFromBsonValue(insertedId) +//} +// +//// updateOne(filter, updateDoc, updateOptions(upsert: Boolean)): UpdateResult(matchCount, modifiedCount, upsertedId) +//// updateMany(filter, updateDoc, updateOptions(upsert: Boolean)): UpdateResult(matchCount, modifiedCount, upsertedId) +//// query +//// update : BsonDocument +//// upsert: Boolean +// +//// FIXME Would we also allow filter and update to be serializables? +//// FIXME Could just return Boolean, since matchedCount=1,modifiedCount=1 even if multiple documents should be matching :thinking: +//// FIXME Should we split into upsertOne, since response only contains 'upsertedId' if call has 'upsert:true` +//@ExperimentalRealmSerializerApi +//@OptIn(ExperimentalKBsonSerializerApi::class) +//public suspend inline fun MongoCollection<*, *>.updateOne( +// filter: BsonDocument, +// update: BsonDocument, +// upsert: Boolean = false +//): R { +// val insertedId: BsonValue = (this as BsonMongoCollection).call("updateOne") { +// put("query", filter) +// put("update", update) +// put("upsert", BsonBoolean(upsert)) +// }.asDocument()//.get("insertedId")!!.asArray().toList() +// // {"matchedCount":{"$numberInt":"0"},"modifiedCount":{"$numberInt":"0"}} +// +// return if (R::class == BsonValue::class) { insertedId as R } else { EJson.decodeFromBsonValue(insertedId) } +//} +//@ExperimentalRealmSerializerApi +//@OptIn(ExperimentalKBsonSerializerApi::class) +//public suspend inline fun MongoCollection<*, *>.updateMany( +// filter: BsonDocument, +// update: BsonDocument, +// upsert: Boolean = false +//): R { +// val insertedId: BsonValue = (this as BsonMongoCollection).call("updateMany") { +// put("query", filter) +// put("update", update) +// put("upsert", BsonBoolean(upsert)) +// }.asDocument().get("upsertedId")!! +// // {"matchedCount":{"$numberInt":"0"},"modifiedCount":{"$numberInt":"0"}} +// +// return if (R::class == BsonValue::class) { insertedId as R } else { EJson.decodeFromBsonValue(insertedId) } +//} +// +//@ExperimentalRealmSerializerApi +//@OptIn(ExperimentalKBsonSerializerApi::class) +//public suspend inline fun MongoCollection<*, *>.findOneAndUpdate( +// filter: BsonDocument, +// update: BsonDocument, +// projection: BsonDocument? = null, +// sort: BsonDocument? = null, +// upsert: Boolean = false, +// returnNewDoc: Boolean = false, +//): R { +// val updatedDocument: BsonValue = (this as BsonMongoCollection).call("findOneAndUpdate") { +// put("filter", filter) +// put("update", update) +// projection?.let { put("projection", projection)} +// sort?.let { put("sort", sort)} +// put("upsert", BsonBoolean(upsert)) +// put("returnNewDoc", BsonBoolean(returnNewDoc)) +// } +// return if (R::class == BsonValue::class) { +// updatedDocument as R +// } else { +// EJson.decodeFromBsonValue(updatedDocument) +// } +//} +// +//@ExperimentalRealmSerializerApi +//@OptIn(ExperimentalKBsonSerializerApi::class) +//public suspend inline fun MongoCollection<*, *>.findOneAndReplace( +// filter: BsonDocument, +// update: BsonDocument, +// projection: BsonDocument? = null, +// sort: BsonDocument? = null, +// upsert: Boolean = false, +// returnNewDoc: Boolean = false, +//): R { +// // If returnNewDoc==true then the returned document is after the update otherwise it is from +// // before the update +// val updatedDocument: BsonValue = (this as BsonMongoCollection).call("findOneAndReplace") { +// put("filter", filter) +// put("update", update) +// projection?.let { put("projection", projection)} +// sort?.let { put("sort", sort)} +// put("upsert", BsonBoolean(upsert)) +// put("returnNewDoc", BsonBoolean(returnNewDoc)) +// } +// return if (R::class == BsonValue::class) { +// updatedDocument as R +// } else { +// EJson.decodeFromBsonValue(updatedDocument) +// } +//} +// +//@ExperimentalRealmSerializerApi +//@OptIn(ExperimentalKBsonSerializerApi::class) +//public suspend inline fun MongoCollection<*, *>.findOneAndDelete( +// filter: BsonDocument, +// projection: BsonDocument? = null, +// sort: BsonDocument? = null, +//): R { +// val deletedDocument: BsonValue = (this as BsonMongoCollection).call("findOneAndDelete") { +// put("filter", filter) +// projection?.let { put("projection", projection)} +// sort?.let { put("sort", sort)} +// } +// return if (R::class == BsonValue::class) { +// deletedDocument as R +// } else { +// EJson.decodeFromBsonValue(deletedDocument) +// } +//} -// deleteMany(filter): Count -// query -@ExperimentalRealmSerializerApi -@OptIn(ExperimentalKBsonSerializerApi::class) -public suspend inline fun MongoCollection.deleteMany(filter: BsonDocument): Long { - val insertedId: BsonValue = (this as MongoCollectionImpl).call("deleteMany") { - put("query", filter) - }.asDocument().get("deletedCount")!! - return EJson.decodeFromBsonValue(insertedId) -} +// +// +//public class ClientOption { +// +//} +// +//@PublishedApi +//internal interface FilterOptionInternal { +// var filter: BsonDocument? +//} +//@PublishedApi +//internal interface LimitOptionInternal { +// var limit: Long? +//} +// +//public interface LimitOption { } +//public fun LimitOption.limit(limit: Long) { +// (this as LimitOptionInternal).limit = limit +//} +//public interface FilterOption { } +//public fun FilterOption.filter(json: String) { +// (this as FilterOptionInternal).filter = BsonDocument(json) +//} +//@ExperimentalKBsonSerializerApi +//public inline fun FilterOption.filter(argument: T) { +// filter(argument, EJson.serializersModule.serializerOrRealmBuiltInSerializer()) +//} +//@OptIn(ExperimentalKBsonSerializerApi::class) +//public inline fun FilterOption.filter(argument: T, serializer: KSerializer) { +// (this as FilterOptionInternal).filter = EJson.encodeToBsonValue(serializer, argument).asDocument() +//} +//public interface ProjectionOption +//public interface SortOption +// +//public interface CountOptions : LimitOption, FilterOption +//public interface FindOneOptions : LimitOption, FilterOption, SortOption, ProjectionOption +// +//@PublishedApi +//internal class FindOptionsInternal: FindOneOptions, FilterOptionInternal, LimitOptionInternal { +// override var filter: BsonDocument? = null +// override var limit: Long? = null +//} -// updateOne(filter, updateDoc, updateOptions(upsert: Boolean)): UpdateResult(matchCount, modifiedCount, upsertedId) -// updateMany(filter, updateDoc, updateOptions(upsert: Boolean)): UpdateResult(matchCount, modifiedCount, upsertedId) +//public suspend inline fun findOne(filter: Bson = {}, options: FindOptions(limit, projection, sort)): T // query -// update : BsonDocument -// upsert: Boolean - -// FIXME Would we also allow filter and update to be serializables? -// FIXME Could just return Boolean, since matchedCount=1,modifiedCount=1 even if multiple documents should be matching :thinking: -// FIXME Should we split into upsertOne, since response only contains 'upsertedId' if call has 'upsert:true` -@ExperimentalRealmSerializerApi -@OptIn(ExperimentalKBsonSerializerApi::class) -public suspend inline fun MongoCollection.updateOne( - filter: BsonDocument, - update: BsonDocument, - upsert: Boolean = false -): R { - val insertedId: BsonValue = (this as MongoCollectionImpl).call("updateOne") { - put("query", filter) - put("update", update) - put("upsert", BsonBoolean(upsert)) - }.asDocument()//.get("insertedId")!!.asArray().toList() - // {"matchedCount":{"$numberInt":"0"},"modifiedCount":{"$numberInt":"0"}} - - return if (R::class == BsonValue::class) { insertedId as R } else { EJson.decodeFromBsonValue(insertedId) } -} -@ExperimentalRealmSerializerApi -@OptIn(ExperimentalKBsonSerializerApi::class) -public suspend inline fun MongoCollection.updateMany( - filter: BsonDocument, - update: BsonDocument, - upsert: Boolean = false -): R { - val insertedId: BsonValue = (this as MongoCollectionImpl).call("updateMany") { - put("query", filter) - put("update", update) - put("upsert", BsonBoolean(upsert)) - }.asDocument().get("upsertedId")!! - // {"matchedCount":{"$numberInt":"0"},"modifiedCount":{"$numberInt":"0"}} - - return if (R::class == BsonValue::class) { insertedId as R } else { EJson.decodeFromBsonValue(insertedId) } -} - -@ExperimentalRealmSerializerApi -@OptIn(ExperimentalKBsonSerializerApi::class) -public suspend inline fun MongoCollection.findOneAndUpdate( - filter: BsonDocument, - update: BsonDocument, - projection: BsonDocument? = null, - sort: BsonDocument? = null, - upsert: Boolean = false, - returnNewDoc: Boolean = false, -): R { - val updatedDocument: BsonValue = (this as MongoCollectionImpl).call("findOneAndUpdate") { - put("filter", filter) - put("update", update) - projection?.let { put("projection", projection)} - sort?.let { put("sort", sort)} - put("upsert", BsonBoolean(upsert)) - put("returnNewDoc", BsonBoolean(returnNewDoc)) - } - return if (R::class == BsonValue::class) { - updatedDocument as R - } else { - EJson.decodeFromBsonValue(updatedDocument) - } -} +// findoptions +// limit +// projection +// sort -@ExperimentalRealmSerializerApi -@OptIn(ExperimentalKBsonSerializerApi::class) -public suspend inline fun MongoCollection.findOneAndReplace( - filter: BsonDocument, - update: BsonDocument, - projection: BsonDocument? = null, - sort: BsonDocument? = null, - upsert: Boolean = false, - returnNewDoc: Boolean = false, -): R { - // If returnNewDoc==true then the returned document is after the update otherwise it is from - // before the update - val updatedDocument: BsonValue = (this as MongoCollectionImpl).call("findOneAndReplace") { - put("filter", filter) - put("update", update) - projection?.let { put("projection", projection)} - sort?.let { put("sort", sort)} - put("upsert", BsonBoolean(upsert)) - put("returnNewDoc", BsonBoolean(returnNewDoc)) - } - return if (R::class == BsonValue::class) { - updatedDocument as R - } else { - EJson.decodeFromBsonValue(updatedDocument) - } -} +//@OptIn(ExperimentalKBsonSerializerApi::class) +//@ExperimentalRealmSerializerApi +//public suspend inline fun MongoCollection.findOne(configuration: FindOneOptions.() -> Unit): T { +// val options = FindOptionsInternal() +// configuration(options) +// val response = (this as BsonMongoCollection).call("findOne") { +// options.filter?.let { put("query", it) } +//// options.projection?.let { put("projection", it) } +//// options.sort?.let { put("sort", it) } +// } +// return EJson.decodeFromBsonValue(response) +//} -@ExperimentalRealmSerializerApi -@OptIn(ExperimentalKBsonSerializerApi::class) -public suspend inline fun MongoCollection.findOneAndDelete( - filter: BsonDocument, - projection: BsonDocument? = null, - sort: BsonDocument? = null, -): R { - val deletedDocument: BsonValue = (this as MongoCollectionImpl).call("findOneAndDelete") { - put("filter", filter) - projection?.let { put("projection", projection)} - sort?.let { put("sort", sort)} - } - return if (R::class == BsonValue::class) { - deletedDocument as R - } else { - EJson.decodeFromBsonValue(deletedDocument) - } -} diff --git a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/mongo/MongoDatabase.kt b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/mongo/MongoDatabase.kt index 4fbfbadc09..6a1b34fb1d 100644 --- a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/mongo/MongoDatabase.kt +++ b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/mongo/MongoDatabase.kt @@ -16,7 +16,10 @@ package io.realm.kotlin.mongodb.mongo +import io.realm.kotlin.annotations.ExperimentalRealmSerializerApi import org.mongodb.kbson.BsonValue +import org.mongodb.kbson.ExperimentalKBsonSerializerApi +import org.mongodb.kbson.serialization.EJson import kotlin.jvm.JvmName /** @@ -29,9 +32,10 @@ public interface MongoDatabase { */ public val name: String - public fun collection(collectionName: String): MongoCollection - public fun typedCollectionbson(collectionName: String): TypedMongoCollection - public fun typedCollection(collectionName: String): TypedMongoCollection + public fun collection(collectionName: String): MongoCollection + + @OptIn(ExperimentalKBsonSerializerApi::class) + public fun collection(collectionName: String, eJson: EJson? = null): MongoCollection } diff --git a/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/mongo/MongoClientTest.kt b/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/mongo/MongoClientTest.kt index 1ccd687acd..154fd791ab 100644 --- a/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/mongo/MongoClientTest.kt +++ b/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/mongo/MongoClientTest.kt @@ -27,22 +27,21 @@ import io.realm.kotlin.mongodb.exceptions.ServiceException import io.realm.kotlin.mongodb.mongo.MongoClient import io.realm.kotlin.mongodb.mongo.MongoCollection import io.realm.kotlin.mongodb.mongo.MongoDatabase -import io.realm.kotlin.mongodb.mongo.TypedMongoCollection import io.realm.kotlin.mongodb.mongo.aggregate -import io.realm.kotlin.mongodb.mongo.deleteMany -import io.realm.kotlin.mongodb.mongo.deleteOne +import io.realm.kotlin.mongodb.mongo.count +//import io.realm.kotlin.mongodb.mongo.deleteMany +//import io.realm.kotlin.mongodb.mongo.deleteOne import io.realm.kotlin.mongodb.mongo.find import io.realm.kotlin.mongodb.mongo.findOne -import io.realm.kotlin.mongodb.mongo.findOneAndDelete -import io.realm.kotlin.mongodb.mongo.findOneAndReplace -import io.realm.kotlin.mongodb.mongo.findOneAndUpdate +//import io.realm.kotlin.mongodb.mongo.findOneAndDelete +//import io.realm.kotlin.mongodb.mongo.findOneAndReplace +//import io.realm.kotlin.mongodb.mongo.findOneAndUpdate import io.realm.kotlin.mongodb.mongo.insertMany import io.realm.kotlin.mongodb.mongo.insertOne -import io.realm.kotlin.mongodb.mongo.updateMany -import io.realm.kotlin.mongodb.mongo.updateOne +//import io.realm.kotlin.mongodb.mongo.updateMany +//import io.realm.kotlin.mongodb.mongo.updateOne import io.realm.kotlin.test.mongodb.TestApp import io.realm.kotlin.test.mongodb.asTestApp - import io.realm.kotlin.test.mongodb.common.utils.assertFailsWithMessage import io.realm.kotlin.types.RealmObject import kotlinx.serialization.Serializable @@ -52,7 +51,6 @@ import org.mongodb.kbson.BsonString import org.mongodb.kbson.BsonValue import org.mongodb.kbson.ExperimentalKBsonSerializerApi import org.mongodb.kbson.ObjectId -import org.mongodb.kbson.serialization.Bson import org.mongodb.kbson.serialization.EJson import org.mongodb.kbson.serialization.encodeToBsonValue import kotlin.random.Random @@ -67,13 +65,13 @@ import kotlin.test.assertTrue private const val SERVICE_NAME = "BackingDB" -@OptIn(ExperimentalRealmSerializerApi::class) +@OptIn(ExperimentalRealmSerializerApi::class, ExperimentalKBsonSerializerApi::class) class MongoClientTest { lateinit var app: TestApp lateinit var client: MongoClient lateinit var database: MongoDatabase - lateinit var collection: MongoCollection + lateinit var collection: MongoCollection @BeforeTest fun setUp() { @@ -93,7 +91,7 @@ class MongoClientTest { val user = app.createUserAndLogin() client = user.mongoClient(SERVICE_NAME) database = client.database(databaseName) - collection = database.collection("SyncDog") + collection = database.collection("SyncDog") } @AfterTest @@ -113,7 +111,9 @@ class MongoClientTest { @Test fun count() = runBlocking { - assertEquals(0, collection.count()) + RealmLog.level = LogLevel.ALL + val actual = collection.count() + assertEquals(0, actual) app.asTestApp.run { (1..10).forEach { @@ -144,7 +144,10 @@ class MongoClientTest { @Test fun findOne() = runBlocking { - assertNull(collection.findOne()) + val actual = collection.findOne() + assertNull(actual) + val actual1 = collection.findOne() + assertNull(actual1) app.asTestApp.run { (1..10).forEach { @@ -322,6 +325,7 @@ class MongoClientTest { @Test fun find() = runBlocking { RealmLog.level = LogLevel.ALL + assertTrue { collection.find().isEmpty() } assertTrue { collection.find().isEmpty() } val x: List = collection.insertMany(listOf(SyncDog("dog1"), SyncDog("dog2"))) @@ -396,7 +400,9 @@ class MongoClientTest { @Test fun aggregate() = runBlocking { RealmLog.level = LogLevel.ALL + collection.aggregate(listOf()) collection.aggregate(listOf()) + collection.aggregate(listOf()) val x: List = collection.insertMany(listOf(SyncDog(name = "dog1"), SyncDog(name = "dog2"))) collection.aggregate(listOf()) @@ -530,7 +536,7 @@ class MongoClientTest { fun insertMany() = runBlocking { RealmLog.level = LogLevel.ALL val x: List = collection.insertMany(listOf(SyncDog("a"))) - val syncDogIntIdCollection = database.collection("SyncDogIntId") + val syncDogIntIdCollection = database.collection("SyncDogIntId") val elements = SyncDogIntId("a", Random.nextInt()) val y: List = syncDogIntIdCollection.insertMany(listOf(elements)) @@ -544,10 +550,10 @@ class MongoClientTest { val z: List = typedCollection.insertMany(listOf(SyncDog("sadf"))) val tyz = typedCollection.insertMany(listOf(SyncDog("sadf"))) - val bsonSyncDogs /*: TypedMongoCollection */ = database.typedCollectionbson("SyncDog") + val bsonSyncDogs: MongoCollection = database.collection("SyncDog") val insertMany /*: List */ = bsonSyncDogs.insertMany(listOf(BsonDocument("name", "x"))) - val syncDogs: TypedMongoCollection = database.typedCollection("SyncDog") + val syncDogs: MongoCollection = database.collection("SyncDog") val objectIds = syncDogs.insertMany(listOf(SyncDog("name"))) @@ -661,735 +667,735 @@ class MongoClientTest { // } // - @Test - fun deleteOne() = runBlocking { - // Argument wrapper DSL - RealmLog.level = LogLevel.ALL - assertFalse { collection.deleteOne(BsonDocument()) } - - // A bit ann - val elements = SyncDog("x") - assertEquals(2, collection.insertMany(listOf(elements, elements)).size) - assertTrue { collection.deleteOne(BsonDocument("""{ "name": "x" }""")) } - } - - // @Test -// fun deleteOne_singleDocument() { -// with(getCollectionInternal()) { -// assertEquals(0, deleteOne(Document()).get()!!.deletedCount) -// assertEquals(0, deleteOne(Document("hello", "world")).get()!!.deletedCount) -// -// val doc1 = Document("hello", "world") -// -// insertOne(doc1).get() -// assertEquals(1, deleteOne(doc1).get()!!.deletedCount) -// assertEquals(0, count().get()) -// } -// } -// -// @Test -// fun deleteOne_fails() { -// with(getCollectionInternal()) { -// assertFailsWithErrorCode(ErrorCode.MONGODB_ERROR) { -// deleteOne(Document("\$who", 1)).get() -// }.also { e -> -// assertTrue(e.errorMessage!!.contains("operator", true)) -// } -// } -// } -// -// @Test -// fun deleteOne_multipleDocuments() { -// with(getCollectionInternal()) { -// assertEquals(0, count().get()) -// -// val rawDoc = Document("hello", "world") -// val doc1 = Document(rawDoc) -// val doc1b = Document(rawDoc) -// val doc2 = Document("foo", "bar") -// val doc3 = Document("42", "666") -// insertMany(listOf(doc1, doc1b, doc2, doc3)).get() -// assertEquals(1, deleteOne(rawDoc).get()!!.deletedCount) -// assertEquals(1, deleteOne(Document()).get()!!.deletedCount) -// assertEquals(2, count().get()) -// } -// } -// - @Test - fun deleteMany() = runBlocking { - // Argument wrapper DSL - RealmLog.level = LogLevel.ALL - assertEquals(0, collection.deleteMany(BsonDocument())) - - // A bit ann - val elements = SyncDog("x") - assertEquals(2, collection.insertMany(listOf(elements, elements)).size) - assertEquals(2, collection.deleteMany(BsonDocument("""{ "name": "x" }"""))) - - assertEquals( - 3, - collection.insertMany(listOf(elements, elements, elements)).size - ) - assertEquals(3, collection.deleteMany(BsonDocument())) - } - - // @Test -// fun deleteMany_singleDocument() { -// with(getCollectionInternal()) { -// assertEquals(0, count().get()) -// -// val rawDoc = Document("hello", "world") -// val doc1 = Document(rawDoc) -// -// insertOne(doc1).get() -// assertEquals(1, count().get()) -// assertEquals(1, deleteMany(doc1).get()!!.deletedCount) -// assertEquals(0, count().get()) -// } -// } -// -// @Test -// fun deleteMany_multipleDocuments() { -// with(getCollectionInternal()) { -// assertEquals(0, count().get()) -// -// val rawDoc = Document("hello", "world") -// val doc1 = Document(rawDoc) -// val doc1b = Document(rawDoc) -// val doc2 = Document("foo", "bar") -// val doc3 = Document("42", "666") -// insertMany(listOf(doc1, doc1b, doc2, doc3)).get() -// assertEquals(2, deleteMany(rawDoc).get()!!.deletedCount) // two docs will be deleted -// assertEquals(2, count().get()) // two docs still present -// assertEquals(2, deleteMany(Document()).get()!!.deletedCount) // delete all -// assertEquals(0, count().get()) -// -// insertMany(listOf(doc1, doc1b, doc2, doc3)).get() -// assertEquals(4, deleteMany(Document()).get()!!.deletedCount) // delete all -// assertEquals(0, count().get()) -// } -// } -// -// @Test -// fun deleteMany_fails() { -// with(getCollectionInternal()) { -// assertFailsWithErrorCode(ErrorCode.MONGODB_ERROR) { -// deleteMany(Document("\$who", 1)).get() -// }.also { e -> -// assertTrue(e.errorMessage!!.contains("operator", true)) -// } -// } -// } -// - @Test - fun updateOne() = runBlocking { - // Argument wrapper DSL - RealmLog.level = LogLevel.ALL - - val elements = SyncDog("x") - assertEquals(2, collection.insertMany(listOf(elements, elements)).size) - assertEquals(2, collection.count(filter = BsonDocument("""{"name": "x"}"""))) - - // A bit ann - collection.updateOne( - BsonDocument("""{ "name": "x"}"""), - BsonDocument("""{ "name": "y"}"""), - true - ) -// assertEquals(2, collection.deleteMany(BsonDocument("""{ "name": "x" }""" )) ) - -// assertEquals(3, collection.insertMany(listOf(elements, elements, elements)).size) -// assertEquals(3, collection.deleteMany(BsonDocument()) ) - - collection.updateOne( - BsonDocument("""{ "name": "z"}"""), - BsonDocument(""" { "name": "y"}"""), - upsert = true - ) - } - - // @Test -// fun updateOne_emptyCollection() { -// with(getCollectionInternal()) { -// val doc1 = Document("hello", "world") -// -// // Update on an empty collection -// updateOne(Document(), doc1) -// .get()!! -// .let { -// assertEquals(0, it.matchedCount) -// assertEquals(0, it.modifiedCount) -// assertNull(it.upsertedId) -// } -// -// // Update on an empty collection adding some values -// val doc2 = Document("\$set", Document("woof", "meow")) -// updateOne(Document(), doc2) -// .get()!! -// .let { -// assertEquals(0, it.matchedCount) -// assertEquals(0, it.modifiedCount) -// assertNull(it.upsertedId) -// assertEquals(0, count().get()) -// } -// } -// } -// -// @Test -// fun updateOne_emptyCollectionWithUpsert() { -// with(getCollectionInternal()) { -// val doc1 = Document("hello", "world") -// -// // Update on empty collection with upsert -// val options = UpdateOptions().upsert(true) -// updateOne(Document(), doc1, options) -// .get()!! -// .let { -// assertEquals(0, it.matchedCount) -// assertEquals(0, it.modifiedCount) -// assertFalse(it.upsertedId!!.isNull) -// } -// assertEquals(1, count().get()) -// -// assertEquals(doc1, find(Document()).first().get()!!.withoutId()) -// } -// } -// -// @Test -// fun updateOne_fails() { -// with(getCollectionInternal()) { -// assertFailsWithErrorCode(ErrorCode.MONGODB_ERROR) { -// updateOne(Document("\$who", 1), Document()).get() -// }.also { e -> -// assertTrue(e.errorMessage!!.contains("operator", true)) -// } -// } -// } -// - @Test - fun updateMany() = runBlocking { - RealmLog.level = LogLevel.ALL - assertEquals( - 4, - collection.insertMany( - listOf( - SyncDog("x"), - SyncDog("x"), - SyncDog("y"), - SyncDog("z") - ) - ).size - ) - assertEquals(2, collection.count(filter = BsonDocument("""{"name": "x"}"""))) - collection.updateMany( - BsonDocument("""{"name": "x2"}"""), - BsonDocument("""{"name": "x1"}"""), - true - ) - } - - // @Test -// fun updateMany_emptyCollection() { -// with(getCollectionInternal()) { -// val doc1 = Document("hello", "world") -// -// // Update on empty collection -// updateMany(Document(), doc1) -// .get()!! -// .let { -// assertEquals(0, it.matchedCount) -// assertEquals(0, it.modifiedCount) -// assertNull(it.upsertedId) -// } -// assertEquals(0, count().get()) -// } -// } -// -// @Test -// fun updateMany_emptyCollectionWithUpsert() { -// with(getCollectionInternal()) { -// val doc1 = Document("hello", "world") -// -// // Update on empty collection with upsert -// updateMany(Document(), doc1, UpdateOptions().upsert(true)) -// .get()!! -// .let { -// assertEquals(0, it.matchedCount) -// assertEquals(0, it.modifiedCount) -// assertNotNull(it.upsertedId) -// } -// assertEquals(1, count().get()) -// -// // Add new value using update -// val update = Document("woof", "meow") -// updateMany(Document(), Document("\$set", update)) -// .get()!! -// .let { -// assertEquals(1, it.matchedCount) -// assertEquals(1, it.modifiedCount) -// assertNull(it.upsertedId) -// } -// assertEquals(1, count().get()) -// val expected = Document(doc1).apply { this["woof"] = "meow" } -// assertEquals(expected, find().first().get()!!.withoutId()) -// -// // Insert empty document, add ["woof", "meow"] to it and check it worked -// insertOne(Document()).get() -// updateMany(Document(), Document("\$set", update)) -// .get()!! -// .let { -// assertEquals(2, it.matchedCount) -// assertEquals(2, it.modifiedCount) -// } -// assertEquals(2, count().get()) -// find().iterator() -// .get()!! -// .let { -// assertEquals(expected, it.next().withoutId()) -// assertEquals(update, it.next().withoutId()) -// assertFalse(it.hasNext()) -// } -// } -// } -// // @Test -// fun updateMany_fails() { -// with(getCollectionInternal()) { -// assertFailsWithErrorCode(ErrorCode.MONGODB_ERROR) { -// updateMany(Document("\$who", 1), Document()).get() -// }.also { e -> -// assertTrue(e.errorMessage!!.contains("operator", true)) -// } -// } -// } -// - @Test - fun findOneAndUpdate() = runBlocking { - RealmLog.level = LogLevel.ALL - assertNull(collection.findOneAndUpdate(BsonDocument(), BsonDocument())) - collection.insertMany( - listOf( - SyncDog("dog1"), - SyncDog("dog1"), - SyncDog("dog2") - ) - ) - collection.findOneAndUpdate( - BsonDocument(), - BsonDocument("""{ "name": "dog1" }"""), - upsert = true - ) - } -// @Test -// fun findOneAndUpdate_emptyCollection() { -// with(getCollectionInternal()) { -// // Test null return format -// assertNull(findOneAndUpdate(Document(), Document()).get()) -// } +// fun deleteOne() = runBlocking { +// // Argument wrapper DSL +// RealmLog.level = LogLevel.ALL +// assertFalse { collection.deleteOne(BsonDocument()) } +// +// // A bit ann +// val elements = SyncDog("x") +// assertEquals(2, collection.insertMany(listOf(elements, elements)).size) +// assertTrue { collection.deleteOne(BsonDocument("""{ "name": "x" }""")) } // } // +// // @Test +//// fun deleteOne_singleDocument() { +//// with(getCollectionInternal()) { +//// assertEquals(0, deleteOne(Document()).get()!!.deletedCount) +//// assertEquals(0, deleteOne(Document("hello", "world")).get()!!.deletedCount) +//// +//// val doc1 = Document("hello", "world") +//// +//// insertOne(doc1).get() +//// assertEquals(1, deleteOne(doc1).get()!!.deletedCount) +//// assertEquals(0, count().get()) +//// } +//// } +//// +//// @Test +//// fun deleteOne_fails() { +//// with(getCollectionInternal()) { +//// assertFailsWithErrorCode(ErrorCode.MONGODB_ERROR) { +//// deleteOne(Document("\$who", 1)).get() +//// }.also { e -> +//// assertTrue(e.errorMessage!!.contains("operator", true)) +//// } +//// } +//// } +//// +//// @Test +//// fun deleteOne_multipleDocuments() { +//// with(getCollectionInternal()) { +//// assertEquals(0, count().get()) +//// +//// val rawDoc = Document("hello", "world") +//// val doc1 = Document(rawDoc) +//// val doc1b = Document(rawDoc) +//// val doc2 = Document("foo", "bar") +//// val doc3 = Document("42", "666") +//// insertMany(listOf(doc1, doc1b, doc2, doc3)).get() +//// assertEquals(1, deleteOne(rawDoc).get()!!.deletedCount) +//// assertEquals(1, deleteOne(Document()).get()!!.deletedCount) +//// assertEquals(2, count().get()) +//// } +//// } +//// // @Test -// fun findOneAndUpdate_noUpdates() { -// with(getCollectionInternal()) { -// assertNull(findOneAndUpdate(Document(), Document()).get()) -// assertEquals(0, count().get()) -// } +// fun deleteMany() = runBlocking { +// // Argument wrapper DSL +// RealmLog.level = LogLevel.ALL +// assertEquals(0, collection.deleteMany(BsonDocument())) +// +// // A bit ann +// val elements = SyncDog("x") +// assertEquals(2, collection.insertMany(listOf(elements, elements)).size) +// assertEquals(2, collection.deleteMany(BsonDocument("""{ "name": "x" }"""))) +// +// assertEquals( +// 3, +// collection.insertMany(listOf(elements, elements, elements)).size +// ) +// assertEquals(3, collection.deleteMany(BsonDocument())) // } // +// // @Test +//// fun deleteMany_singleDocument() { +//// with(getCollectionInternal()) { +//// assertEquals(0, count().get()) +//// +//// val rawDoc = Document("hello", "world") +//// val doc1 = Document(rawDoc) +//// +//// insertOne(doc1).get() +//// assertEquals(1, count().get()) +//// assertEquals(1, deleteMany(doc1).get()!!.deletedCount) +//// assertEquals(0, count().get()) +//// } +//// } +//// +//// @Test +//// fun deleteMany_multipleDocuments() { +//// with(getCollectionInternal()) { +//// assertEquals(0, count().get()) +//// +//// val rawDoc = Document("hello", "world") +//// val doc1 = Document(rawDoc) +//// val doc1b = Document(rawDoc) +//// val doc2 = Document("foo", "bar") +//// val doc3 = Document("42", "666") +//// insertMany(listOf(doc1, doc1b, doc2, doc3)).get() +//// assertEquals(2, deleteMany(rawDoc).get()!!.deletedCount) // two docs will be deleted +//// assertEquals(2, count().get()) // two docs still present +//// assertEquals(2, deleteMany(Document()).get()!!.deletedCount) // delete all +//// assertEquals(0, count().get()) +//// +//// insertMany(listOf(doc1, doc1b, doc2, doc3)).get() +//// assertEquals(4, deleteMany(Document()).get()!!.deletedCount) // delete all +//// assertEquals(0, count().get()) +//// } +//// } +//// +//// @Test +//// fun deleteMany_fails() { +//// with(getCollectionInternal()) { +//// assertFailsWithErrorCode(ErrorCode.MONGODB_ERROR) { +//// deleteMany(Document("\$who", 1)).get() +//// }.also { e -> +//// assertTrue(e.errorMessage!!.contains("operator", true)) +//// } +//// } +//// } +//// // @Test -// fun findOneAndUpdate_noUpsert() { -// with(getCollectionInternal()) { -// val sampleDoc = Document("hello", "world1") -// sampleDoc["num"] = 2 -// -// // Insert a sample Document -// insertOne(sampleDoc).get() -// assertEquals(1, count().get()) -// -// // Sample call to findOneAndUpdate() where we get the previous document back -// val sampleUpdate = Document("\$set", Document("hello", "hellothere")).apply { -// this["\$inc"] = Document("num", 1) -// } -// findOneAndUpdate(Document("hello", "world1"), sampleUpdate) -// .get()!! -// .withoutId() -// .let { -// assertEquals(sampleDoc.withoutId(), it) -// } -// assertEquals(1, count().get()) -// -// // Make sure the update took place -// val expectedDoc = Document("hello", "hellothere") -// expectedDoc["num"] = 3 -// assertEquals(expectedDoc.withoutId(), find().first().get()!!.withoutId()) -// assertEquals(1, count().get()) -// -// // Call findOneAndUpdate() again but get the new document -// sampleUpdate.remove("\$set") -// expectedDoc["num"] = 4 -// val options = FindOneAndModifyOptions() -// .returnNewDocument(true) -// findOneAndUpdate(Document("hello", "hellothere"), sampleUpdate, options) -// .get()!! -// .withoutId() -// .let { -// assertEquals(expectedDoc.withoutId(), it) -// } -// assertEquals(1, count().get()) -// -// // Test null behaviour again with a filter that should not match any documents -// assertNull(findOneAndUpdate(Document("hello", "zzzzz"), Document()).get()) -// assertEquals(1, count().get()) -// } +// fun updateOne() = runBlocking { +// // Argument wrapper DSL +// RealmLog.level = LogLevel.ALL +// +// val elements = SyncDog("x") +// assertEquals(2, collection.insertMany(listOf(elements, elements)).size) +// assertEquals(2, collection.count(filter = BsonDocument("""{"name": "x"}"""))) +// +// // A bit ann +// collection.updateOne( +// BsonDocument("""{ "name": "x"}"""), +// BsonDocument("""{ "name": "y"}"""), +// true +// ) +//// assertEquals(2, collection.deleteMany(BsonDocument("""{ "name": "x" }""" )) ) +// +//// assertEquals(3, collection.insertMany(listOf(elements, elements, elements)).size) +//// assertEquals(3, collection.deleteMany(BsonDocument()) ) +// +// collection.updateOne( +// BsonDocument("""{ "name": "z"}"""), +// BsonDocument(""" { "name": "y"}"""), +// upsert = true +// ) // } // +// // @Test +//// fun updateOne_emptyCollection() { +//// with(getCollectionInternal()) { +//// val doc1 = Document("hello", "world") +//// +//// // Update on an empty collection +//// updateOne(Document(), doc1) +//// .get()!! +//// .let { +//// assertEquals(0, it.matchedCount) +//// assertEquals(0, it.modifiedCount) +//// assertNull(it.upsertedId) +//// } +//// +//// // Update on an empty collection adding some values +//// val doc2 = Document("\$set", Document("woof", "meow")) +//// updateOne(Document(), doc2) +//// .get()!! +//// .let { +//// assertEquals(0, it.matchedCount) +//// assertEquals(0, it.modifiedCount) +//// assertNull(it.upsertedId) +//// assertEquals(0, count().get()) +//// } +//// } +//// } +//// +//// @Test +//// fun updateOne_emptyCollectionWithUpsert() { +//// with(getCollectionInternal()) { +//// val doc1 = Document("hello", "world") +//// +//// // Update on empty collection with upsert +//// val options = UpdateOptions().upsert(true) +//// updateOne(Document(), doc1, options) +//// .get()!! +//// .let { +//// assertEquals(0, it.matchedCount) +//// assertEquals(0, it.modifiedCount) +//// assertFalse(it.upsertedId!!.isNull) +//// } +//// assertEquals(1, count().get()) +//// +//// assertEquals(doc1, find(Document()).first().get()!!.withoutId()) +//// } +//// } +//// +//// @Test +//// fun updateOne_fails() { +//// with(getCollectionInternal()) { +//// assertFailsWithErrorCode(ErrorCode.MONGODB_ERROR) { +//// updateOne(Document("\$who", 1), Document()).get() +//// }.also { e -> +//// assertTrue(e.errorMessage!!.contains("operator", true)) +//// } +//// } +//// } +//// // @Test -// fun findOneAndUpdate_upsert() { -// with(getCollectionInternal()) { -// val doc1 = Document("hello", "world1").apply { this["num"] = 1 } -// val doc2 = Document("hello", "world2").apply { this["num"] = 2 } -// val doc3 = Document("hello", "world3").apply { this["num"] = 3 } -// -// val filter = Document("hello", "hellothere") -// -// // Test the upsert option where it should not actually be invoked -// var options = FindOneAndModifyOptions() -// .returnNewDocument(true) -// .upsert(true) -// val update1 = Document("\$set", doc1) -// assertEquals(doc1, -// findOneAndUpdate(filter, update1, options) -// .get()!! -// .withoutId()) -// assertEquals(1, count().get()) -// assertEquals(doc1.withoutId(), -// find().first() -// .get()!! -// .withoutId()) -// -// // Test the upsert option where the server should perform upsert and return new document -// val update2 = Document("\$set", doc2) -// assertEquals(doc2, -// findOneAndUpdate(filter, update2, options) -// .get()!! -// .withoutId()) -// assertEquals(2, count().get()) -// -// // Test the upsert option where the server should perform upsert and return old document -// // The old document should be empty -// options = FindOneAndModifyOptions() -// .upsert(true) -// val update = Document("\$set", doc3) -// assertNull(findOneAndUpdate(filter, update, options).get()) -// assertEquals(3, count().get()) -// } +// fun updateMany() = runBlocking { +// RealmLog.level = LogLevel.ALL +// assertEquals( +// 4, +// collection.insertMany( +// listOf( +// SyncDog("x"), +// SyncDog("x"), +// SyncDog("y"), +// SyncDog("z") +// ) +// ).size +// ) +// assertEquals(2, collection.count(filter = BsonDocument("""{"name": "x"}"""))) +// collection.updateMany( +// BsonDocument("""{"name": "x2"}"""), +// BsonDocument("""{"name": "x1"}"""), +// true +// ) // } // +// // @Test +//// fun updateMany_emptyCollection() { +//// with(getCollectionInternal()) { +//// val doc1 = Document("hello", "world") +//// +//// // Update on empty collection +//// updateMany(Document(), doc1) +//// .get()!! +//// .let { +//// assertEquals(0, it.matchedCount) +//// assertEquals(0, it.modifiedCount) +//// assertNull(it.upsertedId) +//// } +//// assertEquals(0, count().get()) +//// } +//// } +//// +//// @Test +//// fun updateMany_emptyCollectionWithUpsert() { +//// with(getCollectionInternal()) { +//// val doc1 = Document("hello", "world") +//// +//// // Update on empty collection with upsert +//// updateMany(Document(), doc1, UpdateOptions().upsert(true)) +//// .get()!! +//// .let { +//// assertEquals(0, it.matchedCount) +//// assertEquals(0, it.modifiedCount) +//// assertNotNull(it.upsertedId) +//// } +//// assertEquals(1, count().get()) +//// +//// // Add new value using update +//// val update = Document("woof", "meow") +//// updateMany(Document(), Document("\$set", update)) +//// .get()!! +//// .let { +//// assertEquals(1, it.matchedCount) +//// assertEquals(1, it.modifiedCount) +//// assertNull(it.upsertedId) +//// } +//// assertEquals(1, count().get()) +//// val expected = Document(doc1).apply { this["woof"] = "meow" } +//// assertEquals(expected, find().first().get()!!.withoutId()) +//// +//// // Insert empty document, add ["woof", "meow"] to it and check it worked +//// insertOne(Document()).get() +//// updateMany(Document(), Document("\$set", update)) +//// .get()!! +//// .let { +//// assertEquals(2, it.matchedCount) +//// assertEquals(2, it.modifiedCount) +//// } +//// assertEquals(2, count().get()) +//// find().iterator() +//// .get()!! +//// .let { +//// assertEquals(expected, it.next().withoutId()) +//// assertEquals(update, it.next().withoutId()) +//// assertFalse(it.hasNext()) +//// } +//// } +//// } +//// +//// @Test +//// fun updateMany_fails() { +//// with(getCollectionInternal()) { +//// assertFailsWithErrorCode(ErrorCode.MONGODB_ERROR) { +//// updateMany(Document("\$who", 1), Document()).get() +//// }.also { e -> +//// assertTrue(e.errorMessage!!.contains("operator", true)) +//// } +//// } +//// } +//// // @Test -// fun findOneAndUpdate_withProjectionAndSort() { -// with(getCollectionInternal()) { -// insertMany(listOf( -// Document(mapOf(Pair("team", "Fearful Mallards"), Pair("score", 25000))), -// Document(mapOf(Pair("team", "Tactful Mooses"), Pair("score", 23500))), -// Document(mapOf(Pair("team", "Aquatic Ponies"), Pair("score", 19250))), -// Document(mapOf(Pair("team", "Cuddly Zebras"), Pair("score", 15235))), -// Document(mapOf(Pair("team", "Garrulous Bears"), Pair("score", 18000))) -// )).get() -// -// assertEquals(5, count().get()) -// assertNotNull(findOne(Document("team", "Cuddly Zebras"))) -// -// // Project: team, hide _id; Sort: score ascending -// val project = Document(mapOf(Pair("_id", 0), Pair("team", 1), Pair("score", 1))) -// val sort = Document("score", 1) -// -// // This results in the update of Cuddly Zebras -// val updatedDocument = findOneAndUpdate( -// Document("score", Document("\$lt", 22250)), -// Document("\$inc", Document("score", 1)), -// FindOneAndModifyOptions() -// .projection(project) -// .sort(sort) -// ).get() -// -// assertEquals(5, count().get()) -// assertEquals( -// Document(mapOf(Pair("team", "Cuddly Zebras"), Pair("score", 15235))), -// updatedDocument +// fun findOneAndUpdate() = runBlocking { +// RealmLog.level = LogLevel.ALL +// assertNull(collection.findOneAndUpdate(BsonDocument(), BsonDocument())) +// collection.insertMany( +// listOf( +// SyncDog("dog1"), +// SyncDog("dog1"), +// SyncDog("dog2") // ) -// assertEquals( -// Document(mapOf(Pair("team", "Cuddly Zebras"), Pair("score", 15235 + 1))), -// findOne(Document("team", "Cuddly Zebras")).get().withoutId() -// ) -// } -// } -// -// @Test -// fun findOneAndUpdate_fails() { -// with(getCollectionInternal()) { -// assertFailsWithErrorCode(ErrorCode.MONGODB_ERROR) { -// findOneAndUpdate(Document(), Document("\$who", 1)).get() -// }.also { e -> -// assertTrue(e.errorMessage!!.contains("modifier", true)) -// } -// -// assertFailsWithErrorCode(ErrorCode.MONGODB_ERROR) { -// findOneAndUpdate(Document(), Document("\$who", 1), FindOneAndModifyOptions().upsert(true)).get() -// }.also { e -> -// assertTrue(e.errorMessage!!.contains("modifier", true)) -// } -// } -// } - - // FIXME Invalid fields?~? - @Test - fun findOneAndReplace() = runBlocking { - RealmLog.level = LogLevel.ALL - assertNull(collection.findOneAndReplace(BsonDocument(), BsonDocument())) - collection.insertMany( - listOf( - SyncDog("dog1"), - SyncDog("dog1"), - SyncDog("dog2") - ) - ) - val x = collection.findOneAndReplace( - BsonDocument(), - BsonDocument("""{ "name": "dog1" }"""), - upsert = true - ) - println(x) - } -// -// @Test -// fun findOneAndReplace_noUpdates() { -// with(getCollectionInternal()) { -// // Test null behaviour again with a filter that should not match any documents -// assertNull(findOneAndReplace(Document("hello", "zzzzz"), Document()).get()) -// assertEquals(0, count().get()) -// assertNull(findOneAndReplace(Document(), Document()).get()) -// assertEquals(0, count().get()) -// } -// } -// -// @Test -// fun findOneAndReplace_noUpsert() { -// with(getCollectionInternal()) { -// val sampleDoc = Document("hello", "world1").apply { this["num"] = 2 } -// -// // Insert a sample Document -// insertOne(sampleDoc).get() -// assertEquals(1, count().get()) -// -// // Sample call to findOneAndReplace() where we get the previous document back -// var sampleUpdate = Document("hello", "world2").apply { this["num"] = 2 } -// assertEquals(sampleDoc.withoutId(), -// findOneAndReplace(Document("hello", "world1"), sampleUpdate).get()!!.withoutId()) -// assertEquals(1, count().get()) -// -// // Make sure the update took place -// val expectedDoc = Document("hello", "world2").apply { this["num"] = 2 } -// assertEquals(expectedDoc.withoutId(), find().first().get()!!.withoutId()) -// assertEquals(1, count().get()) -// -// // Call findOneAndReplace() again but get the new document -// sampleUpdate = Document("hello", "world3").apply { this["num"] = 3 } -// val options = FindOneAndModifyOptions().returnNewDocument(true) -// assertEquals(sampleUpdate.withoutId(), -// findOneAndReplace(Document(), sampleUpdate, options).get()!!.withoutId()) -// assertEquals(1, count().get()) -// -// // Test null behaviour again with a filter that should not match any documents -// assertNull(findOneAndReplace(Document("hello", "zzzzz"), Document()).get()) -// assertEquals(1, count().get()) -// } -// } -// -// @Test -// fun findOneAndReplace_upsert() { -// with(getCollectionInternal()) { -// val doc4 = Document("hello", "world4").apply { this["num"] = 4 } -// val doc5 = Document("hello", "world5").apply { this["num"] = 5 } -// val doc6 = Document("hello", "world6").apply { this["num"] = 6 } -// -// // Test the upsert option where it should not actually be invoked -// val sampleUpdate = Document("hello", "world4").apply { this["num"] = 4 } -// var options = FindOneAndModifyOptions() -// .returnNewDocument(true) -// .upsert(true) -// assertEquals(doc4.withoutId(), -// findOneAndReplace(Document("hello", "world3"), doc4, options) -// .get()!! -// .withoutId()) -// assertEquals(1, count().get()) -// assertEquals(doc4.withoutId(), find().first().get()!!.withoutId()) -// -// // Test the upsert option where the server should perform upsert and return new document -// options = FindOneAndModifyOptions().returnNewDocument(true).upsert(true) -// assertEquals(doc5.withoutId(), findOneAndReplace(Document("hello", "hellothere"), doc5, options).get()!!.withoutId()) -// assertEquals(2, count().get()) -// -// // Test the upsert option where the server should perform upsert and return old document -// // The old document should be empty -// options = FindOneAndModifyOptions().upsert(true) -// assertNull(findOneAndReplace(Document("hello", "hellothere"), doc6, options).get()) -// assertEquals(3, count().get()) -// } +// ) +// collection.findOneAndUpdate( +// BsonDocument(), +// BsonDocument("""{ "name": "dog1" }"""), +// upsert = true +// ) // } +//// @Test +//// fun findOneAndUpdate_emptyCollection() { +//// with(getCollectionInternal()) { +//// // Test null return format +//// assertNull(findOneAndUpdate(Document(), Document()).get()) +//// } +//// } +//// +//// @Test +//// fun findOneAndUpdate_noUpdates() { +//// with(getCollectionInternal()) { +//// assertNull(findOneAndUpdate(Document(), Document()).get()) +//// assertEquals(0, count().get()) +//// } +//// } +//// +//// @Test +//// fun findOneAndUpdate_noUpsert() { +//// with(getCollectionInternal()) { +//// val sampleDoc = Document("hello", "world1") +//// sampleDoc["num"] = 2 +//// +//// // Insert a sample Document +//// insertOne(sampleDoc).get() +//// assertEquals(1, count().get()) +//// +//// // Sample call to findOneAndUpdate() where we get the previous document back +//// val sampleUpdate = Document("\$set", Document("hello", "hellothere")).apply { +//// this["\$inc"] = Document("num", 1) +//// } +//// findOneAndUpdate(Document("hello", "world1"), sampleUpdate) +//// .get()!! +//// .withoutId() +//// .let { +//// assertEquals(sampleDoc.withoutId(), it) +//// } +//// assertEquals(1, count().get()) +//// +//// // Make sure the update took place +//// val expectedDoc = Document("hello", "hellothere") +//// expectedDoc["num"] = 3 +//// assertEquals(expectedDoc.withoutId(), find().first().get()!!.withoutId()) +//// assertEquals(1, count().get()) +//// +//// // Call findOneAndUpdate() again but get the new document +//// sampleUpdate.remove("\$set") +//// expectedDoc["num"] = 4 +//// val options = FindOneAndModifyOptions() +//// .returnNewDocument(true) +//// findOneAndUpdate(Document("hello", "hellothere"), sampleUpdate, options) +//// .get()!! +//// .withoutId() +//// .let { +//// assertEquals(expectedDoc.withoutId(), it) +//// } +//// assertEquals(1, count().get()) +//// +//// // Test null behaviour again with a filter that should not match any documents +//// assertNull(findOneAndUpdate(Document("hello", "zzzzz"), Document()).get()) +//// assertEquals(1, count().get()) +//// } +//// } +//// +//// @Test +//// fun findOneAndUpdate_upsert() { +//// with(getCollectionInternal()) { +//// val doc1 = Document("hello", "world1").apply { this["num"] = 1 } +//// val doc2 = Document("hello", "world2").apply { this["num"] = 2 } +//// val doc3 = Document("hello", "world3").apply { this["num"] = 3 } +//// +//// val filter = Document("hello", "hellothere") +//// +//// // Test the upsert option where it should not actually be invoked +//// var options = FindOneAndModifyOptions() +//// .returnNewDocument(true) +//// .upsert(true) +//// val update1 = Document("\$set", doc1) +//// assertEquals(doc1, +//// findOneAndUpdate(filter, update1, options) +//// .get()!! +//// .withoutId()) +//// assertEquals(1, count().get()) +//// assertEquals(doc1.withoutId(), +//// find().first() +//// .get()!! +//// .withoutId()) +//// +//// // Test the upsert option where the server should perform upsert and return new document +//// val update2 = Document("\$set", doc2) +//// assertEquals(doc2, +//// findOneAndUpdate(filter, update2, options) +//// .get()!! +//// .withoutId()) +//// assertEquals(2, count().get()) +//// +//// // Test the upsert option where the server should perform upsert and return old document +//// // The old document should be empty +//// options = FindOneAndModifyOptions() +//// .upsert(true) +//// val update = Document("\$set", doc3) +//// assertNull(findOneAndUpdate(filter, update, options).get()) +//// assertEquals(3, count().get()) +//// } +//// } +//// +//// @Test +//// fun findOneAndUpdate_withProjectionAndSort() { +//// with(getCollectionInternal()) { +//// insertMany(listOf( +//// Document(mapOf(Pair("team", "Fearful Mallards"), Pair("score", 25000))), +//// Document(mapOf(Pair("team", "Tactful Mooses"), Pair("score", 23500))), +//// Document(mapOf(Pair("team", "Aquatic Ponies"), Pair("score", 19250))), +//// Document(mapOf(Pair("team", "Cuddly Zebras"), Pair("score", 15235))), +//// Document(mapOf(Pair("team", "Garrulous Bears"), Pair("score", 18000))) +//// )).get() +//// +//// assertEquals(5, count().get()) +//// assertNotNull(findOne(Document("team", "Cuddly Zebras"))) +//// +//// // Project: team, hide _id; Sort: score ascending +//// val project = Document(mapOf(Pair("_id", 0), Pair("team", 1), Pair("score", 1))) +//// val sort = Document("score", 1) +//// +//// // This results in the update of Cuddly Zebras +//// val updatedDocument = findOneAndUpdate( +//// Document("score", Document("\$lt", 22250)), +//// Document("\$inc", Document("score", 1)), +//// FindOneAndModifyOptions() +//// .projection(project) +//// .sort(sort) +//// ).get() +//// +//// assertEquals(5, count().get()) +//// assertEquals( +//// Document(mapOf(Pair("team", "Cuddly Zebras"), Pair("score", 15235))), +//// updatedDocument +//// ) +//// assertEquals( +//// Document(mapOf(Pair("team", "Cuddly Zebras"), Pair("score", 15235 + 1))), +//// findOne(Document("team", "Cuddly Zebras")).get().withoutId() +//// ) +//// } +//// } +//// +//// @Test +//// fun findOneAndUpdate_fails() { +//// with(getCollectionInternal()) { +//// assertFailsWithErrorCode(ErrorCode.MONGODB_ERROR) { +//// findOneAndUpdate(Document(), Document("\$who", 1)).get() +//// }.also { e -> +//// assertTrue(e.errorMessage!!.contains("modifier", true)) +//// } +//// +//// assertFailsWithErrorCode(ErrorCode.MONGODB_ERROR) { +//// findOneAndUpdate(Document(), Document("\$who", 1), FindOneAndModifyOptions().upsert(true)).get() +//// }.also { e -> +//// assertTrue(e.errorMessage!!.contains("modifier", true)) +//// } +//// } +//// } // +// // FIXME Invalid fields?~? // @Test -// fun findOneAndReplace_withProjectionAndSort() { -// with(getCollectionInternal()) { -// insertMany(listOf( -// Document(mapOf(Pair("team", "Fearful Mallards"), Pair("score", 25000))), -// Document(mapOf(Pair("team", "Tactful Mooses"), Pair("score", 23500))), -// Document(mapOf(Pair("team", "Aquatic Ponies"), Pair("score", 19250))), -// Document(mapOf(Pair("team", "Cuddly Zebras"), Pair("score", 15235))), -// Document(mapOf(Pair("team", "Garrulous Bears"), Pair("score", 18000))) -// )).get() -// -// assertEquals(5, count().get()) -// assertNotNull(findOne(Document("team", "Cuddly Zebras"))) -// -// // Project: team, hide _id; Sort: score ascending -// val project = Document(mapOf(Pair("_id", 0), Pair("team", 1))) -// val sort = Document("score", 1) -// -// // This results in the replacement of Cuddly Zebras -// val replacedDocument = findOneAndReplace( -// Document("score", Document("\$lt", 22250)), -// Document(mapOf(Pair("team", "Therapeutic Hamsters"), Pair("score", 22250))), -// FindOneAndModifyOptions() -// .projection(project) -// .sort(sort) -// ).get() -// -// assertEquals(5, count().get()) -// assertEquals(Document("team", "Cuddly Zebras"), replacedDocument) -// assertNull(findOne(Document("team", "Cuddly Zebras")).get()) -// assertNotNull(findOne(Document("team", "Therapeutic Hamsters")).get()) -// -// // Check returnNewDocument -// val newDocument = findOneAndReplace( -// Document("score", 22250), -// Document(mapOf(Pair("team", "New Therapeutic Hamsters"), Pair("score", 30000))), -// FindOneAndModifyOptions().returnNewDocument(true) -// ).get() -// -// assertEquals(Document(mapOf(Pair("team", "New Therapeutic Hamsters"), Pair("score", 30000))), newDocument.withoutId()) -// } +// fun findOneAndReplace() = runBlocking { +// RealmLog.level = LogLevel.ALL +// assertNull(collection.findOneAndReplace(BsonDocument(), BsonDocument())) +// collection.insertMany( +// listOf( +// SyncDog("dog1"), +// SyncDog("dog1"), +// SyncDog("dog2") +// ) +// ) +// val x = collection.findOneAndReplace( +// BsonDocument(), +// BsonDocument("""{ "name": "dog1" }"""), +// upsert = true +// ) +// println(x) // } +//// +//// @Test +//// fun findOneAndReplace_noUpdates() { +//// with(getCollectionInternal()) { +//// // Test null behaviour again with a filter that should not match any documents +//// assertNull(findOneAndReplace(Document("hello", "zzzzz"), Document()).get()) +//// assertEquals(0, count().get()) +//// assertNull(findOneAndReplace(Document(), Document()).get()) +//// assertEquals(0, count().get()) +//// } +//// } +//// +//// @Test +//// fun findOneAndReplace_noUpsert() { +//// with(getCollectionInternal()) { +//// val sampleDoc = Document("hello", "world1").apply { this["num"] = 2 } +//// +//// // Insert a sample Document +//// insertOne(sampleDoc).get() +//// assertEquals(1, count().get()) +//// +//// // Sample call to findOneAndReplace() where we get the previous document back +//// var sampleUpdate = Document("hello", "world2").apply { this["num"] = 2 } +//// assertEquals(sampleDoc.withoutId(), +//// findOneAndReplace(Document("hello", "world1"), sampleUpdate).get()!!.withoutId()) +//// assertEquals(1, count().get()) +//// +//// // Make sure the update took place +//// val expectedDoc = Document("hello", "world2").apply { this["num"] = 2 } +//// assertEquals(expectedDoc.withoutId(), find().first().get()!!.withoutId()) +//// assertEquals(1, count().get()) +//// +//// // Call findOneAndReplace() again but get the new document +//// sampleUpdate = Document("hello", "world3").apply { this["num"] = 3 } +//// val options = FindOneAndModifyOptions().returnNewDocument(true) +//// assertEquals(sampleUpdate.withoutId(), +//// findOneAndReplace(Document(), sampleUpdate, options).get()!!.withoutId()) +//// assertEquals(1, count().get()) +//// +//// // Test null behaviour again with a filter that should not match any documents +//// assertNull(findOneAndReplace(Document("hello", "zzzzz"), Document()).get()) +//// assertEquals(1, count().get()) +//// } +//// } +//// +//// @Test +//// fun findOneAndReplace_upsert() { +//// with(getCollectionInternal()) { +//// val doc4 = Document("hello", "world4").apply { this["num"] = 4 } +//// val doc5 = Document("hello", "world5").apply { this["num"] = 5 } +//// val doc6 = Document("hello", "world6").apply { this["num"] = 6 } +//// +//// // Test the upsert option where it should not actually be invoked +//// val sampleUpdate = Document("hello", "world4").apply { this["num"] = 4 } +//// var options = FindOneAndModifyOptions() +//// .returnNewDocument(true) +//// .upsert(true) +//// assertEquals(doc4.withoutId(), +//// findOneAndReplace(Document("hello", "world3"), doc4, options) +//// .get()!! +//// .withoutId()) +//// assertEquals(1, count().get()) +//// assertEquals(doc4.withoutId(), find().first().get()!!.withoutId()) +//// +//// // Test the upsert option where the server should perform upsert and return new document +//// options = FindOneAndModifyOptions().returnNewDocument(true).upsert(true) +//// assertEquals(doc5.withoutId(), findOneAndReplace(Document("hello", "hellothere"), doc5, options).get()!!.withoutId()) +//// assertEquals(2, count().get()) +//// +//// // Test the upsert option where the server should perform upsert and return old document +//// // The old document should be empty +//// options = FindOneAndModifyOptions().upsert(true) +//// assertNull(findOneAndReplace(Document("hello", "hellothere"), doc6, options).get()) +//// assertEquals(3, count().get()) +//// } +//// } +//// +//// @Test +//// fun findOneAndReplace_withProjectionAndSort() { +//// with(getCollectionInternal()) { +//// insertMany(listOf( +//// Document(mapOf(Pair("team", "Fearful Mallards"), Pair("score", 25000))), +//// Document(mapOf(Pair("team", "Tactful Mooses"), Pair("score", 23500))), +//// Document(mapOf(Pair("team", "Aquatic Ponies"), Pair("score", 19250))), +//// Document(mapOf(Pair("team", "Cuddly Zebras"), Pair("score", 15235))), +//// Document(mapOf(Pair("team", "Garrulous Bears"), Pair("score", 18000))) +//// )).get() +//// +//// assertEquals(5, count().get()) +//// assertNotNull(findOne(Document("team", "Cuddly Zebras"))) +//// +//// // Project: team, hide _id; Sort: score ascending +//// val project = Document(mapOf(Pair("_id", 0), Pair("team", 1))) +//// val sort = Document("score", 1) +//// +//// // This results in the replacement of Cuddly Zebras +//// val replacedDocument = findOneAndReplace( +//// Document("score", Document("\$lt", 22250)), +//// Document(mapOf(Pair("team", "Therapeutic Hamsters"), Pair("score", 22250))), +//// FindOneAndModifyOptions() +//// .projection(project) +//// .sort(sort) +//// ).get() +//// +//// assertEquals(5, count().get()) +//// assertEquals(Document("team", "Cuddly Zebras"), replacedDocument) +//// assertNull(findOne(Document("team", "Cuddly Zebras")).get()) +//// assertNotNull(findOne(Document("team", "Therapeutic Hamsters")).get()) +//// +//// // Check returnNewDocument +//// val newDocument = findOneAndReplace( +//// Document("score", 22250), +//// Document(mapOf(Pair("team", "New Therapeutic Hamsters"), Pair("score", 30000))), +//// FindOneAndModifyOptions().returnNewDocument(true) +//// ).get() +//// +//// assertEquals(Document(mapOf(Pair("team", "New Therapeutic Hamsters"), Pair("score", 30000))), newDocument.withoutId()) +//// } +//// } +//// +//// @Test +//// fun findOneAndReplace_fails() { +//// with(getCollectionInternal()) { +//// assertFailsWithErrorCode(ErrorCode.INVALID_PARAMETER) { +//// findOneAndReplace(Document(), Document("\$who", 1)).get() +//// } +//// +//// assertFailsWithErrorCode(ErrorCode.INVALID_PARAMETER) { +//// findOneAndReplace(Document(), Document("\$who", 1), FindOneAndModifyOptions().upsert(true)).get() +//// } +//// } +//// } // // @Test -// fun findOneAndReplace_fails() { -// with(getCollectionInternal()) { -// assertFailsWithErrorCode(ErrorCode.INVALID_PARAMETER) { -// findOneAndReplace(Document(), Document("\$who", 1)).get() -// } -// -// assertFailsWithErrorCode(ErrorCode.INVALID_PARAMETER) { -// findOneAndReplace(Document(), Document("\$who", 1), FindOneAndModifyOptions().upsert(true)).get() -// } -// } -// } - - @Test - fun findOneAndDelete() = runBlocking { - RealmLog.level = LogLevel.ALL - assertNull(collection.findOneAndDelete(BsonDocument(), BsonDocument())) - collection.insertMany( - listOf( - SyncDog("dog1"), - SyncDog("dog1"), - SyncDog("dog2") - ) - ) - val x: SyncDog = collection.findOneAndDelete( - BsonDocument(), - BsonDocument("""{ "name": "dog1" }"""), - ) - } - // -// @Test -// fun findOneAndDelete() { -// with(getCollectionInternal()) { -// val sampleDoc = Document("hello", "world1").apply { this["num"] = 1 } -// -// // Collection should start out empty -// // This also tests the null return format -// assertNull(findOneAndDelete(Document()).get()) -// -// // Insert a sample Document -// insertOne(sampleDoc).get() -// assertEquals(1, count().get()) -// -// // Sample call to findOneAndDelete() where we delete the only doc in the collection -// assertEquals(sampleDoc.withoutId(), -// findOneAndDelete(Document()).get()!!.withoutId()) -// -// // There should be no documents in the collection now -// assertEquals(0, count().get()) -// -// // Insert a sample Document -// insertOne(sampleDoc).get() -// assertEquals(1, count().get()) -// -// // Call findOneAndDelete() again but this time with a filter -// assertEquals(sampleDoc.withoutId(), -// findOneAndDelete(Document("hello", "world1")).get()!!.withoutId()) -// -// // There should be no documents in the collection now -// assertEquals(0, count().get()) -// -// // Insert a sample Document -// insertOne(sampleDoc).get() -// assertEquals(1, count().get()) -// -// // Test null behaviour again with a filter that should not match any documents -// assertNull(findOneAndDelete(Document("hello", "zzzzz")).get()) -// assertEquals(1, count().get()) -// -// val doc2 = Document("hello", "world2").apply { this["num"] = 2 } -// val doc3 = Document("hello", "world3").apply { this["num"] = 3 } -// -// // Insert new documents -// insertMany(listOf(doc2, doc3)).get() -// assertEquals(3, count().get()) -// } +// fun findOneAndDelete() = runBlocking { +// RealmLog.level = LogLevel.ALL +// assertNull(collection.findOneAndDelete(BsonDocument(), BsonDocument())) +// collection.insertMany( +// listOf( +// SyncDog("dog1"), +// SyncDog("dog1"), +// SyncDog("dog2") +// ) +// ) +// val x: SyncDog = collection.findOneAndDelete( +// BsonDocument(), +// BsonDocument("""{ "name": "dog1" }"""), +// ) // } +// // +//// @Test +//// fun findOneAndDelete() { +//// with(getCollectionInternal()) { +//// val sampleDoc = Document("hello", "world1").apply { this["num"] = 1 } +//// +//// // Collection should start out empty +//// // This also tests the null return format +//// assertNull(findOneAndDelete(Document()).get()) +//// +//// // Insert a sample Document +//// insertOne(sampleDoc).get() +//// assertEquals(1, count().get()) +//// +//// // Sample call to findOneAndDelete() where we delete the only doc in the collection +//// assertEquals(sampleDoc.withoutId(), +//// findOneAndDelete(Document()).get()!!.withoutId()) +//// +//// // There should be no documents in the collection now +//// assertEquals(0, count().get()) +//// +//// // Insert a sample Document +//// insertOne(sampleDoc).get() +//// assertEquals(1, count().get()) +//// +//// // Call findOneAndDelete() again but this time with a filter +//// assertEquals(sampleDoc.withoutId(), +//// findOneAndDelete(Document("hello", "world1")).get()!!.withoutId()) +//// +//// // There should be no documents in the collection now +//// assertEquals(0, count().get()) +//// +//// // Insert a sample Document +//// insertOne(sampleDoc).get() +//// assertEquals(1, count().get()) +//// +//// // Test null behaviour again with a filter that should not match any documents +//// assertNull(findOneAndDelete(Document("hello", "zzzzz")).get()) +//// assertEquals(1, count().get()) +//// +//// val doc2 = Document("hello", "world2").apply { this["num"] = 2 } +//// val doc3 = Document("hello", "world3").apply { this["num"] = 3 } +//// +//// // Insert new documents +//// insertMany(listOf(doc2, doc3)).get() +//// assertEquals(3, count().get()) +//// } +//// } +//// +//// @Test +//// fun findOneAndDelete_withProjectionAndSort() { +//// with(getCollectionInternal()) { +//// insertMany(listOf( +//// Document(mapOf(Pair("team", "Fearful Mallards"), Pair("score", 25000))), +//// Document(mapOf(Pair("team", "Tactful Mooses"), Pair("score", 23500))), +//// Document(mapOf(Pair("team", "Aquatic Ponies"), Pair("score", 19250))), +//// Document(mapOf(Pair("team", "Cuddly Zebras"), Pair("score", 15235))), +//// Document(mapOf(Pair("team", "Garrulous Bears"), Pair("score", 18000))) +//// )).get() +//// +//// assertEquals(5, count().get()) +//// assertNotNull(findOne(Document("team", "Cuddly Zebras"))) +//// +//// // Project: team, hide _id; Sort: score ascending +//// val project = Document(mapOf(Pair("_id", 0), Pair("team", 1))) +//// val sort = Document("score", 1) +//// +//// // This results in the deletion of Cuddly Zebras +//// val deletedDocument = findOneAndDelete( +//// Document("score", Document("\$lt", 22250)), +//// FindOneAndModifyOptions() +//// .projection(project) +//// .sort(sort) +//// ).get() +//// +//// assertEquals(4, count().get()) +//// assertEquals(Document("team", "Cuddly Zebras"), deletedDocument.withoutId()) +//// assertNull(findOne(Document("team", "Cuddly Zebras")).get()) +//// } +//// } // -// @Test -// fun findOneAndDelete_withProjectionAndSort() { -// with(getCollectionInternal()) { -// insertMany(listOf( -// Document(mapOf(Pair("team", "Fearful Mallards"), Pair("score", 25000))), -// Document(mapOf(Pair("team", "Tactful Mooses"), Pair("score", 23500))), -// Document(mapOf(Pair("team", "Aquatic Ponies"), Pair("score", 19250))), -// Document(mapOf(Pair("team", "Cuddly Zebras"), Pair("score", 15235))), -// Document(mapOf(Pair("team", "Garrulous Bears"), Pair("score", 18000))) -// )).get() -// -// assertEquals(5, count().get()) -// assertNotNull(findOne(Document("team", "Cuddly Zebras"))) -// -// // Project: team, hide _id; Sort: score ascending -// val project = Document(mapOf(Pair("_id", 0), Pair("team", 1))) -// val sort = Document("score", 1) -// -// // This results in the deletion of Cuddly Zebras -// val deletedDocument = findOneAndDelete( -// Document("score", Document("\$lt", 22250)), -// FindOneAndModifyOptions() -// .projection(project) -// .sort(sort) -// ).get() -// -// assertEquals(4, count().get()) -// assertEquals(Document("team", "Cuddly Zebras"), deletedDocument.withoutId()) -// assertNull(findOne(Document("team", "Cuddly Zebras")).get()) -// } -// } - }