From 2359357977e8734331a78c88e0702f50f3a3c75e Mon Sep 17 00:00:00 2001 From: Sebastien Deleuze Date: Mon, 15 May 2017 15:55:14 +0200 Subject: [PATCH] DATAMONGO-1689 - Add Kotlin extensions for [Reactive]MongoOperations. We now offer dedicated Kotlin extensions for MongoOperations and ReactiveMongoOperations. Original pull request: #463. --- spring-data-mongodb/pom.xml | 83 +++ .../mongodb/core/MongoOperationsExtensions.kt | 520 ++++++++++++++++ .../core/ReactiveMongoOperationsExtensions.kt | 374 ++++++++++++ .../core/MongoOperationsExtensionsTests.kt | 562 ++++++++++++++++++ .../ReactiveMongoOperationsExtensionsTests.kt | 434 ++++++++++++++ 5 files changed, 1973 insertions(+) create mode 100644 spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/MongoOperationsExtensions.kt create mode 100644 spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/ReactiveMongoOperationsExtensions.kt create mode 100644 spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/MongoOperationsExtensionsTests.kt create mode 100644 spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/ReactiveMongoOperationsExtensionsTests.kt diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 99ef83a54..7e964146a 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -18,6 +18,7 @@ 1.3 1.5 + 1.1.2-3 @@ -230,12 +231,94 @@ spring-webmvc test + + org.jetbrains.kotlin + kotlin-stdlib-jre8 + ${kotlin} + true + + + org.jetbrains.kotlin + kotlin-reflect + ${kotlin} + true + + + org.jetbrains.kotlin + kotlin-test + ${kotlin} + test + + + com.nhaarman + mockito-kotlin + 1.4.0 + test + + + kotlin-maven-plugin + org.jetbrains.kotlin + ${kotlin} + + 1.8 + + + + compile + compile + compile + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/main/java + + + + + test-compile + test-compile + test-compile + + + ${project.basedir}/src/test/kotlin + ${project.basedir}/src/test/java + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + default-compile + none + + + default-testCompile + none + + + java-compile + compile + compile + + + java-test-compile + test-compile + testCompile + + + + com.mysema.maven apt-maven-plugin diff --git a/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/MongoOperationsExtensions.kt b/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/MongoOperationsExtensions.kt new file mode 100644 index 000000000..27afc6cc0 --- /dev/null +++ b/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/MongoOperationsExtensions.kt @@ -0,0 +1,520 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.core + +import com.mongodb.client.MongoCollection +import com.mongodb.client.result.DeleteResult +import com.mongodb.client.result.UpdateResult +import org.bson.Document +import org.springframework.data.geo.GeoResults +import org.springframework.data.mongodb.core.BulkOperations.BulkMode +import org.springframework.data.mongodb.core.aggregation.Aggregation +import org.springframework.data.mongodb.core.aggregation.AggregationResults +import org.springframework.data.mongodb.core.mapreduce.GroupBy +import org.springframework.data.mongodb.core.mapreduce.GroupByResults +import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions +import org.springframework.data.mongodb.core.mapreduce.MapReduceResults +import org.springframework.data.mongodb.core.query.Criteria +import org.springframework.data.mongodb.core.query.NearQuery +import org.springframework.data.mongodb.core.query.Query +import org.springframework.data.mongodb.core.query.Update +import org.springframework.data.util.CloseableIterator +import kotlin.reflect.KClass + +/** + * Extension for [MongoOperations.getCollectionName] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun MongoOperations.getCollectionName(entityClass: KClass): String = + getCollectionName(entityClass.java) + +/** + * Extension for [MongoOperations.getCollectionName] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.getCollectionName(): String = + getCollectionName(T::class.java) + +/** + * Extension for [MongoOperations.execute] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.execute(action: CollectionCallback): T = + execute(T::class.java, action) + +/** + * Extension for [MongoOperations.stream] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.stream(query: Query): CloseableIterator = + stream(query, T::class.java) + +/** + * Extension for [MongoOperations.stream] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.stream(query: Query, + collectionName: String? = null): CloseableIterator = + if (collectionName != null) stream(query, T::class.java, collectionName) + else stream(query, T::class.java) + +/** + * Extension for [MongoOperations.createCollection] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun MongoOperations.createCollection(entityClass: KClass, + collectionOptions: CollectionOptions? = null): MongoCollection = + if (collectionOptions != null) createCollection(entityClass.java, collectionOptions) + else createCollection(entityClass.java) + +/** + * Extension for [MongoOperations.createCollection] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.createCollection( + collectionOptions: CollectionOptions? = null): MongoCollection = + if (collectionOptions != null) createCollection(T::class.java, collectionOptions) + else createCollection(T::class.java) + +/** + * Extension for [MongoOperations.collectionExists] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun MongoOperations.collectionExists(entityClass: KClass): Boolean = + collectionExists(entityClass.java) + +/** + * Extension for [MongoOperations.collectionExists] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.collectionExists(): Boolean = + collectionExists(T::class.java) + +/** + * Extension for [MongoOperations.dropCollection] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun MongoOperations.dropCollection(entityClass: KClass) { + dropCollection(entityClass.java) +} + +/** + * Extension for [MongoOperations.dropCollection] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.dropCollection() { + dropCollection(T::class.java) +} + +/** + * Extension for [MongoOperations.indexOps] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun MongoOperations.indexOps(entityClass: KClass): IndexOperations = + indexOps(entityClass.java) + +/** + * Extension for [MongoOperations.indexOps] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.indexOps(): IndexOperations = + indexOps(T::class.java) + +/** + * Extension for [MongoOperations.bulkOps] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun MongoOperations.bulkOps(bulkMode: BulkMode, entityClass: KClass, + collectionName: String? = null): BulkOperations = + if (collectionName != null) bulkOps(bulkMode, entityClass.java, collectionName) + else bulkOps(bulkMode, entityClass.java) + +/** + * Extension for [MongoOperations.bulkOps] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER") +inline fun MongoOperations.bulkOps(bulkMode: BulkMode, + collectionName: String? = null): BulkOperations = + if (collectionName != null) bulkOps(bulkMode, T::class.java, collectionName) + else bulkOps(bulkMode, T::class.java) + +/** + * Extension for [MongoOperations.findAll] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.findAll(collectionName: String? = null): List = + if (collectionName != null) findAll(T::class.java, collectionName) else findAll(T::class.java) + +/** + * Extension for [MongoOperations.group] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.group(inputCollectionName: String, groupBy: GroupBy): GroupByResults = + group(inputCollectionName, groupBy, T::class.java) + +/** + * Extension for [MongoOperations.group] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.group(criteria: Criteria, + inputCollectionName: String, groupBy: GroupBy): GroupByResults = + group(criteria, inputCollectionName, groupBy, T::class.java) + +/** + * Extension for [MongoOperations.aggregate] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.aggregate(aggregation: Aggregation, + inputType: KClass<*>): AggregationResults = + aggregate(aggregation, inputType.java, O::class.java) + +/** + * Extension for [MongoOperations.aggregate] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.aggregate(aggregation: Aggregation, + collectionName: String): AggregationResults = + aggregate(aggregation, collectionName, O::class.java) + +/** + * Extension for [MongoOperations.aggregateStream] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.aggregateStream(aggregation: Aggregation, + inputType: KClass<*>): CloseableIterator = + aggregateStream(aggregation, inputType.java, O::class.java) + +/** + * Extension for [MongoOperations.aggregateStream] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.aggregateStream(aggregation: Aggregation, + collectionName: String): CloseableIterator = + aggregateStream(aggregation, collectionName, O::class.java) + +/** + * Extension for [MongoOperations.mapReduce] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.mapReduce(collectionName: String, + mapFunction: String, reduceFunction: String, options: MapReduceOptions? = null): MapReduceResults = + if (options != null) mapReduce(collectionName, mapFunction, reduceFunction, options, T::class.java) + else mapReduce(collectionName, mapFunction, reduceFunction, T::class.java) + +/** + * Extension for [MongoOperations.mapReduce] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.mapReduce(query: Query, collectionName: String, + mapFunction: String, reduceFunction: String, options: MapReduceOptions? = null): MapReduceResults = + if (options != null) mapReduce(query, collectionName, mapFunction, reduceFunction, options, T::class.java) + else mapReduce(query, collectionName, mapFunction, reduceFunction, T::class.java) + +/** + * Extension for [MongoOperations.geoNear] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.geoNear(near: NearQuery, + collectionName: String? = null): GeoResults = + if (collectionName != null) geoNear(near, T::class.java, collectionName) + else geoNear(near, T::class.java) + +/** + * Extension for [MongoOperations.findOne] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.findOne(query: Query, collectionName: String? = null): T = + if (collectionName != null) findOne(query, T::class.java, collectionName) else findOne(query, T::class.java) + +/** + * Extension for [MongoOperations.exists] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun MongoOperations.exists(query: Query, entityClass: KClass, + collectionName: String? = null): Boolean = + if (collectionName != null) exists(query, entityClass.java, collectionName) + else exists(query, entityClass.java) + +/** + * Extension for [MongoOperations.exists] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER") +inline fun MongoOperations.exists(query: Query, collectionName: String? = null): Boolean = + if (collectionName != null) exists(query, T::class.java, collectionName) + else exists(query, T::class.java) + +/** + * Extension for [MongoOperations.find] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.find(query: Query, collectionName: String? = null): List = + if (collectionName != null) find(query, T::class.java, collectionName) + else find(query, T::class.java) + +/** + * Extension for [MongoOperations.findById] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.findById(id: Any, collectionName: String? = null): T = + if (collectionName != null) findById(id, T::class.java, collectionName) + else findById(id, T::class.java) + +/** + * Extension for [MongoOperations.findAndModify] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.findAndModify(query: Query, update: Update, + options: FindAndModifyOptions, collectionName: String? = null): T = + if (collectionName != null) findAndModify(query, update, options, T::class.java, collectionName) + else findAndModify(query, update, options, T::class.java) + +/** + * Extension for [MongoOperations.findAndRemove] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.findAndRemove(query: Query, collectionName: String? = null): T = + if (collectionName != null) findAndRemove(query, T::class.java, collectionName) + else findAndRemove(query, T::class.java) + +/** + * Extension for [MongoOperations.count] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun MongoOperations.count(query: Query = Query(), entityClass: KClass, + collectionName: String? = null): Long = + if (collectionName != null) count(query, entityClass.java, collectionName) + else count(query, entityClass.java) + +/** + * Extension for [MongoOperations.count] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER") +inline fun MongoOperations.count(query: Query = Query(), collectionName: String? = null): Long = + if (collectionName != null) count(query, T::class.java, collectionName) else count(query, T::class.java) + +/** + * Extension for [MongoOperations.insert] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun MongoOperations.insert(batchToSave: Collection, entityClass: KClass) { + insert(batchToSave, entityClass.java) +} + +/** + * Extension for [MongoOperations.upsert] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun MongoOperations.upsert(query: Query, update: Update, entityClass: KClass, + collectionName: String? = null): UpdateResult = + if (collectionName != null) upsert(query, update, entityClass.java, collectionName) + else upsert(query, update, entityClass.java) + +/** + * Extension for [MongoOperations.upsert] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER") +inline fun MongoOperations.upsert(query: Query, update: Update, + collectionName: String? = null): UpdateResult = + if (collectionName != null) upsert(query, update, T::class.java, collectionName) + else upsert(query, update, T::class.java) + +/** + * Extension for [MongoOperations.updateFirst] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun MongoOperations.updateFirst(query: Query, update: Update, entityClass: KClass, + collectionName: String? = null): UpdateResult = + if (collectionName != null) updateFirst(query, update, entityClass.java, collectionName) + else updateFirst(query, update, entityClass.java) + +/** + * Extension for [MongoOperations.updateFirst] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER") +inline fun MongoOperations.updateFirst(query: Query, update: Update, + collectionName: String? = null): UpdateResult = + if (collectionName != null) updateFirst(query, update, T::class.java, collectionName) + else updateFirst(query, update, T::class.java) + + +/** + * Extension for [MongoOperations.updateMulti] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun MongoOperations.updateMulti(query: Query, update: Update, entityClass: KClass, + collectionName: String? = null): UpdateResult = + if (collectionName != null) updateMulti(query, update, entityClass.java, collectionName) + else updateMulti(query, update, entityClass.java) + +/** + * Extension for [MongoOperations.updateMulti] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER") +inline fun MongoOperations.updateMulti(query: Query, update: Update, + collectionName: String? = null): UpdateResult = + if (collectionName != null) updateMulti(query, update, T::class.java, collectionName) + else updateMulti(query, update, T::class.java) + +/** + * Extension for [MongoOperations.remove] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun MongoOperations.remove(query: Query, entityClass: KClass, + collectionName: String? = null): DeleteResult = + if (collectionName != null) remove(query, entityClass.java, collectionName) + else remove(query, entityClass.java) + +/** + * Extension for [MongoOperations.remove] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER") +inline fun MongoOperations.remove(query: Query, collectionName: String? = null): DeleteResult = + if (collectionName != null) remove(query, T::class.java, collectionName) + else remove(query, T::class.java) + +/** + * Extension for [MongoOperations.findAllAndRemove] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun MongoOperations.findAllAndRemove(query: Query): List = + findAllAndRemove(query, T::class.java) diff --git a/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/ReactiveMongoOperationsExtensions.kt b/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/ReactiveMongoOperationsExtensions.kt new file mode 100644 index 000000000..bc00f4707 --- /dev/null +++ b/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/ReactiveMongoOperationsExtensions.kt @@ -0,0 +1,374 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.core + +import com.mongodb.client.result.DeleteResult +import com.mongodb.client.result.UpdateResult +import com.mongodb.reactivestreams.client.MongoCollection +import org.bson.Document +import org.springframework.data.geo.GeoResult +import org.springframework.data.mongodb.core.query.NearQuery +import org.springframework.data.mongodb.core.query.Query +import org.springframework.data.mongodb.core.query.Update +import reactor.core.publisher.Flux +import reactor.core.publisher.Mono +import kotlin.reflect.KClass + +/** + * Extension for [ReactiveMongoOperations.indexOps] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun ReactiveMongoOperations.indexOps(entityClass: KClass): ReactiveIndexOperations = + indexOps(entityClass.java) + +/** + * Extension for [ReactiveMongoOperations.indexOps] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun ReactiveMongoOperations.indexOps(): ReactiveIndexOperations = + indexOps(T::class.java) + +/** + * Extension for [ReactiveMongoOperations.execute] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun ReactiveMongoOperations.execute(action: ReactiveCollectionCallback): Flux = + execute(T::class.java, action) + +/** + * Extension for [ReactiveMongoOperations.createCollection] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun ReactiveMongoOperations.createCollection(entityClass: KClass, + collectionOptions: CollectionOptions? = null): Mono> = + if (collectionOptions != null) createCollection(entityClass.java, collectionOptions) else createCollection(entityClass.java) + +/** + * Extension for [ReactiveMongoOperations.createCollection] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun ReactiveMongoOperations.createCollection( + collectionOptions: CollectionOptions? = null): Mono> = + if (collectionOptions != null) createCollection(T::class.java, collectionOptions) else createCollection(T::class.java) + +/** + * Extension for [ReactiveMongoOperations.collectionExists] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun ReactiveMongoOperations.collectionExists(entityClass: KClass): Mono = + collectionExists(entityClass.java) + +/** + * Extension for [ReactiveMongoOperations.collectionExists] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun ReactiveMongoOperations.collectionExists(): Mono = + collectionExists(T::class.java) + +/** + * Extension for [ReactiveMongoOperations.dropCollection] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun ReactiveMongoOperations.dropCollection(entityClass: KClass): Mono = + dropCollection(entityClass.java) + +/** + * Extension for [ReactiveMongoOperations.dropCollection] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun ReactiveMongoOperations.dropCollection(): Mono = + dropCollection(T::class.java) + + +/** + * Extension for [ReactiveMongoOperations.findAll] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun ReactiveMongoOperations.findAll(collectionName: String? = null): Flux = + if (collectionName != null) findAll(T::class.java, collectionName) else findAll(T::class.java) + +/** + * Extension for [ReactiveMongoOperations.findOne] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun ReactiveMongoOperations.findOne(query: Query, collectionName: String? = null): Mono = + if (collectionName != null) findOne(query, T::class.java, collectionName) else findOne(query, T::class.java) + +/** + * Extension for [ReactiveMongoOperations.exists] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun ReactiveMongoOperations.exists(query: Query, entityClass: KClass, + collectionName: String? = null): Mono = + if (collectionName != null) exists(query, entityClass.java, collectionName) else exists(query, entityClass.java) + +/** + * Extension for [ReactiveMongoOperations.exists] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER") +inline fun ReactiveMongoOperations.exists(query: Query, + collectionName: String? = null): Mono = + if (collectionName != null) exists(query, T::class.java, collectionName) else exists(query, T::class.java) + +/** + * Extension for [ReactiveMongoOperations.find] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun ReactiveMongoOperations.find(query: Query, collectionName: String? = null): Flux = + if (collectionName != null) find(query, T::class.java, collectionName) else find(query, T::class.java) + +/** + * Extension for [ReactiveMongoOperations.findById] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun ReactiveMongoOperations.findById(id: Any, collectionName: String? = null): Mono = + if (collectionName != null) findById(id, T::class.java, collectionName) else findById(id, T::class.java) + +/** + * Extension for [ReactiveMongoOperations.geoNear] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun ReactiveMongoOperations.geoNear(near: NearQuery, + collectionName: String? = null): Flux> = + if (collectionName != null) geoNear(near, T::class.java, collectionName) else geoNear(near, T::class.java) + +/** + * Extension for [ReactiveMongoOperations.findAndModify] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun ReactiveMongoOperations.findAndModify(query: Query, + update: Update, options: FindAndModifyOptions, collectionName: String? = null): Mono = + if (collectionName != null) findAndModify(query, update, options, T::class.java, collectionName) else findAndModify(query, update, options, T::class.java) + +/** + * Extension for [ReactiveMongoOperations.findAndRemove] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun ReactiveMongoOperations.findAndRemove(query: Query, + collectionName: String? = null): Mono = + if (collectionName != null) findAndRemove(query, T::class.java, collectionName) + else findAndRemove(query, T::class.java) + +/** + * Extension for [ReactiveMongoOperations.count] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun ReactiveMongoOperations.count(query: Query = Query(), entityClass: KClass, + collectionName: String? = null): Mono = + if (collectionName != null) count(query, entityClass.java, collectionName) + else count(query, entityClass.java) + +/** + * Extension for [ReactiveMongoOperations.count] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters + * + * @author Sebastien Deleuze + * @since 5.0 + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER") +inline fun ReactiveMongoOperations.count(query: Query = Query(), + collectionName: String? = null): Mono = + if (collectionName != null) count(query, T::class.java, collectionName) + else count(query, T::class.java) + +/** + * Extension for [ReactiveMongoOperations.insert] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun ReactiveMongoOperations.insert(batchToSave: Collection, entityClass: KClass): Flux = + insert(batchToSave, entityClass.java) + +/** + * Extension for [ReactiveMongoOperations.insertAll] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun ReactiveMongoOperations.insertAll(batchToSave: Mono>, + entityClass: KClass): Flux = + insertAll(batchToSave, entityClass.java) + +/** + * Extension for [ReactiveMongoOperations.upsert] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun ReactiveMongoOperations.upsert(query: Query, update: Update, entityClass: KClass, + collectionName: String? = null): Mono = + if (collectionName != null) upsert(query, update, entityClass.java, collectionName) else upsert(query, update, entityClass.java) + +/** + * Extension for [ReactiveMongoOperations.upsert] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER") +inline fun ReactiveMongoOperations.upsert(query: Query, update: Update, + collectionName: String? = null): Mono = + if (collectionName != null) upsert(query, update, T::class.java, collectionName) + else upsert(query, update, T::class.java) + +/** + * Extension for [ReactiveMongoOperations.updateFirst] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun ReactiveMongoOperations.updateFirst(query: Query, update: Update, + entityClass: KClass, collectionName: String? = null): Mono = + if (collectionName != null) updateFirst(query, update, entityClass.java, collectionName) + else updateFirst(query, update, entityClass.java) + +/** + * Extension for [ReactiveMongoOperations.updateFirst] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER") +inline fun ReactiveMongoOperations.updateFirst(query: Query, update: Update, + collectionName: String? = null): Mono = + if (collectionName != null) updateFirst(query, update, T::class.java, collectionName) + else updateFirst(query, update, T::class.java) + +/** + * Extension for [ReactiveMongoOperations.updateMulti] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun ReactiveMongoOperations.updateMulti(query: Query, update: Update, + entityClass: KClass, collectionName: String? = null): Mono = + if (collectionName != null) updateMulti(query, update, entityClass.java, collectionName) + else updateMulti(query, update, entityClass.java) + +/** + * Extension for [ReactiveMongoOperations.updateMulti] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER") +inline fun ReactiveMongoOperations.updateMulti(query: Query, update: Update, + collectionName: String? = null): Mono = + if (collectionName != null) updateMulti(query, update, T::class.java, collectionName) + else updateMulti(query, update, T::class.java) + +/** + * Extension for [ReactiveMongoOperations.remove] providing a [KClass] based variant. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +fun ReactiveMongoOperations.remove(query: Query, entityClass: KClass, + collectionName: String? = null): Mono = + if (collectionName != null) remove(query, entityClass.java, collectionName) + else remove(query, entityClass.java) + +/** + * Extension for [ReactiveMongoOperations.remove] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER") +inline fun ReactiveMongoOperations.remove(query: Query, + collectionName: String? = null): Mono = + if (collectionName != null) remove(query, T::class.java, collectionName) + else remove(query, T::class.java) + +/** + * Extension for [ReactiveMongoOperations.findAllAndRemove] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER") +inline fun ReactiveMongoOperations.findAllAndRemove(query: Query): Flux = + findAllAndRemove(query, T::class.java) + +/** + * Extension for [ReactiveMongoOperations.tail] avoiding requiring the type parameter + * thanks to Kotlin reified type parameters. + * + * @author Sebastien Deleuze + * @since 5.0 + */ +inline fun ReactiveMongoOperations.tail(query: Query, collectionName: String? = null): Flux = + if (collectionName != null) tail(query, T::class.java, collectionName) else tail(query, T::class.java) diff --git a/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/MongoOperationsExtensionsTests.kt b/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/MongoOperationsExtensionsTests.kt new file mode 100644 index 000000000..97b895060 --- /dev/null +++ b/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/MongoOperationsExtensionsTests.kt @@ -0,0 +1,562 @@ +/* + * Copyright 2016-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.core + +import com.nhaarman.mockito_kotlin.mock +import example.first.First +import example.second.Second +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Answers +import org.mockito.Mock +import org.mockito.Mockito.* +import org.mockito.junit.MockitoJUnitRunner +import org.springframework.data.mongodb.core.BulkOperations.BulkMode +import org.springframework.data.mongodb.core.aggregation.Aggregation +import org.springframework.data.mongodb.core.mapreduce.GroupBy +import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions +import org.springframework.data.mongodb.core.query.Criteria +import org.springframework.data.mongodb.core.query.NearQuery +import org.springframework.data.mongodb.core.query.Query +import org.springframework.data.mongodb.core.query.Update + +/** + * @author Sebastien Deleuze + */ +@RunWith(MockitoJUnitRunner::class) +class MongoOperationsExtensionsTests { + + @Mock(answer = Answers.RETURNS_MOCKS) + lateinit var operations: MongoOperations + + @Test + fun `getCollectionName(KClass) extension should call its Java counterpart`() { + operations.getCollectionName(First::class) + verify(operations, times(1)).getCollectionName(First::class.java) + } + + @Test + fun `getCollectionName() with reified type parameter extension should call its Java counterpart`() { + operations.getCollectionName() + verify(operations, times(1)).getCollectionName(First::class.java) + } + + @Test + fun `execute(CollectionCallback) with reified type parameter extension should call its Java counterpart`() { + val collectionCallback = mock>() + operations.execute(collectionCallback) + verify(operations, times(1)).execute(First::class.java, collectionCallback) + } + + @Test + fun `stream(Query) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + operations.stream(query) + verify(operations, times(1)).stream(query, First::class.java) + } + + @Test + fun `stream(Query, String) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val collectionName = "foo" + operations.stream(query, collectionName) + verify(operations, times(1)).stream(query, First::class.java, collectionName) + } + + @Test + fun `createCollection(KClass) extension should call its Java counterpart`() { + operations.createCollection(First::class) + verify(operations, times(1)).createCollection(First::class.java) + } + + @Test + fun `createCollection(KClass, CollectionOptions) extension should call its Java counterpart`() { + val collectionOptions = mock() + operations.createCollection(First::class, collectionOptions) + verify(operations, times(1)).createCollection(First::class.java,collectionOptions) + } + + @Test + fun `createCollection() with reified type parameter extension should call its Java counterpart`() { + operations.createCollection() + verify(operations, times(1)).createCollection(First::class.java) + } + + @Test + fun `createCollection(CollectionOptions) with reified type parameter extension should call its Java counterpart`() { + val collectionOptions = mock() + operations.createCollection(collectionOptions) + verify(operations, times(1)).createCollection(First::class.java, collectionOptions) + } + + + @Test + fun `collectionExists(KClass) extension should call its Java counterpart`() { + operations.collectionExists(First::class) + verify(operations, times(1)).collectionExists(First::class.java) + } + + @Test + fun `collectionExists() with reified type parameter extension should call its Java counterpart`() { + operations.collectionExists() + verify(operations, times(1)).collectionExists(First::class.java) + } + + @Test + fun `dropCollection(KClass) extension should call its Java counterpart`() { + operations.dropCollection(First::class) + verify(operations, times(1)).dropCollection(First::class.java) + } + + @Test + fun `dropCollection() with reified type parameter extension should call its Java counterpart`() { + operations.dropCollection() + verify(operations, times(1)).dropCollection(First::class.java) + } + + @Test + fun `indexOps(KClass) extension should call its Java counterpart`() { + operations.indexOps(First::class) + verify(operations, times(1)).indexOps(First::class.java) + } + + @Test + fun `indexOps() with reified type parameter extension should call its Java counterpart`() { + operations.indexOps() + verify(operations, times(1)).indexOps(First::class.java) + } + + @Test + fun `bulkOps(BulkMode, KClass) extension should call its Java counterpart`() { + val bulkMode = BulkMode.ORDERED + operations.bulkOps(bulkMode, First::class) + verify(operations, times(1)).bulkOps(bulkMode, First::class.java) + } + + @Test + fun `bulkOps(BulkMode, KClass, String) extension should call its Java counterpart`() { + val bulkMode = BulkMode.ORDERED + val collectionName = "foo" + operations.bulkOps(bulkMode, First::class, collectionName) + verify(operations, times(1)).bulkOps(bulkMode, First::class.java, collectionName) + } + + @Test + fun `bulkOps(BulkMode) with reified type parameter extension should call its Java counterpart`() { + val bulkMode = BulkMode.ORDERED + operations.bulkOps(bulkMode) + verify(operations, times(1)).bulkOps(bulkMode, First::class.java) + } + + @Test + fun `bulkOps(BulkMode, String) with reified type parameter extension should call its Java counterpart`() { + val bulkMode = BulkMode.ORDERED + val collectionName = "foo" + operations.bulkOps(bulkMode, collectionName) + verify(operations, times(1)).bulkOps(bulkMode, First::class.java, collectionName) + } + + @Test + fun `findAll() with reified type parameter extension should call its Java counterpart`() { + operations.findAll() + verify(operations, times(1)).findAll(First::class.java) + } + + @Test + fun `findAll(String) with reified type parameter extension should call its Java counterpart`() { + val collectionName = "foo" + operations.findAll(collectionName) + verify(operations, times(1)).findAll(First::class.java, collectionName) + } + + @Test + fun `group(String, GroupBy) with reified type parameter extension should call its Java counterpart`() { + val collectionName = "foo" + val groupBy = mock() + operations.group(collectionName, groupBy) + verify(operations, times(1)).group(collectionName, groupBy, First::class.java) + } + + @Test + fun `group(Criteria, String, GroupBy) with reified type parameter extension should call its Java counterpart`() { + val criteria = mock() + val collectionName = "foo" + val groupBy = mock() + operations.group(criteria, collectionName, groupBy) + verify(operations, times(1)).group(criteria, collectionName, groupBy, First::class.java) + } + + @Test + fun `aggregate(Aggregation, KClass) with reified type parameter extension should call its Java counterpart`() { + val aggregation = mock() + operations.aggregate(aggregation, Second::class) + verify(operations, times(1)).aggregate(aggregation, Second::class.java, First::class.java) + } + + @Test + fun `aggregate(Aggregation, String) with reified type parameter extension should call its Java counterpart`() { + val aggregation = mock() + val collectionName = "foo" + operations.aggregate(aggregation, collectionName) + verify(operations, times(1)).aggregate(aggregation, collectionName, First::class.java) + } + + @Test + fun `aggregateStream(Aggregation, KClass) with reified type parameter extension should call its Java counterpart`() { + val aggregation = mock() + operations.aggregateStream(aggregation, Second::class) + verify(operations, times(1)).aggregateStream(aggregation, Second::class.java, First::class.java) + } + + @Test + fun `aggregateStream(Aggregation, String) with reified type parameter extension should call its Java counterpart`() { + val aggregation = mock() + val collectionName = "foo" + operations.aggregateStream(aggregation, collectionName) + verify(operations, times(1)).aggregateStream(aggregation, collectionName, First::class.java) + } + + @Test + fun `mapReduce(String, String, String) with reified type parameter extension should call its Java counterpart`() { + val collectionName = "foo" + val mapFunction = "bar" + val reduceFunction = "baz" + operations.mapReduce(collectionName, mapFunction, reduceFunction) + verify(operations, times(1)).mapReduce(collectionName, mapFunction, reduceFunction, First::class.java) + } + + @Test + fun `mapReduce(String, String, String, MapReduceOptions) with reified type parameter extension should call its Java counterpart`() { + val collectionName = "foo" + val mapFunction = "bar" + val reduceFunction = "baz" + val options = mock() + operations.mapReduce(collectionName, mapFunction, reduceFunction, options) + verify(operations, times(1)).mapReduce(collectionName, mapFunction, reduceFunction, options, First::class.java) + } + + @Test + fun `mapReduce(Query, String, String, String) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val collectionName = "foo" + val mapFunction = "bar" + val reduceFunction = "baz" + operations.mapReduce(query, collectionName, mapFunction, reduceFunction) + verify(operations, times(1)).mapReduce(query, collectionName, mapFunction, reduceFunction, First::class.java) + } + + @Test + fun `mapReduce(Query, String, String, String, MapReduceOptions) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val collectionName = "foo" + val mapFunction = "bar" + val reduceFunction = "baz" + val options = mock() + operations.mapReduce(query, collectionName, mapFunction, reduceFunction, options) + verify(operations, times(1)).mapReduce(query, collectionName, mapFunction, reduceFunction, options, First::class.java) + } + + @Test + fun `geoNear(Query) with reified type parameter extension should call its Java counterpart`() { + val query = NearQuery.near(0.0, 0.0) + operations.geoNear(query) + verify(operations, times(1)).geoNear(query, First::class.java) + } + + @Test + fun `geoNear(Query, String) with reified type parameter extension should call its Java counterpart`() { + val collectionName = "foo" + val query = NearQuery.near(0.0, 0.0) + operations.geoNear(query, collectionName) + verify(operations, times(1)).geoNear(query, First::class.java, collectionName) + } + + @Test + fun `findOne(Query) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + operations.findOne(query) + verify(operations, times(1)).findOne(query, First::class.java) + } + + @Test + fun `findOne(Query, String) with reified type parameter extension should call its Java counterpart`() { + val collectionName = "foo" + val query = mock() + operations.findOne(query, collectionName) + verify(operations, times(1)).findOne(query, First::class.java, collectionName) + } + + @Test + fun `exists(Query, KClass) extension should call its Java counterpart`() { + val query = mock() + operations.exists(query, First::class) + verify(operations, times(1)).exists(query, First::class.java) + } + + @Test + fun `exists(Query) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + operations.exists(query) + verify(operations, times(1)).exists(query, First::class.java) + } + + @Test + fun `find(Query) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + operations.find(query) + verify(operations, times(1)).find(query, First::class.java) + } + + @Test + fun `find(Query, String) with reified type parameter extension should call its Java counterpart`() { + val collectionName = "foo" + val query = mock() + operations.find(query, collectionName) + verify(operations, times(1)).find(query, First::class.java, collectionName) + } + + @Test + fun `findById(Any) with reified type parameter extension should call its Java counterpart`() { + val id = 1L + operations.findById(id) + verify(operations, times(1)).findById(id, First::class.java) + } + + @Test + fun `findById(Any, String) with reified type parameter extension should call its Java counterpart`() { + val collectionName = "foo" + val id = 1L + operations.findById(id, collectionName) + verify(operations, times(1)).findById(id, First::class.java, collectionName) + } + + @Test + fun `findAndModify(Query, Update, FindAndModifyOptions) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val update = mock() + val options = mock() + operations.findAndModify(query, update, options) + verify(operations, times(1)).findAndModify(query, update, options, First::class.java) + } + + @Test + fun `findAndModify(Query, Update, FindAndModifyOptions, String) with reified type parameter extension should call its Java counterpart`() { + val collectionName = "foo" + val query = mock() + val update = mock() + val options = mock() + operations.findAndModify(query, update, options, collectionName) + verify(operations, times(1)).findAndModify(query, update, options, First::class.java, collectionName) + } + + @Test + fun `findAndRemove(Query) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + operations.findAndRemove(query) + verify(operations, times(1)).findAndRemove(query, First::class.java) + } + + @Test + fun `findAndRemove(Query, String) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val collectionName = "foo" + operations.findAndRemove(query, collectionName) + verify(operations, times(1)).findAndRemove(query, First::class.java, collectionName) + } + + @Test + fun `count() with reified type parameter extension should call its Java counterpart`() { + operations.count() + verify(operations, times(1)).count(any(), eq(First::class.java)) + } + + @Test + fun `count(Query) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + operations.count(query) + verify(operations, times(1)).count(query, First::class.java) + } + + @Test + fun `count(Query, String) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val collectionName = "foo" + operations.count(query, collectionName) + verify(operations, times(1)).count(query, First::class.java, collectionName) + } + + @Test + fun `count(Query, KClass) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + operations.count(query, First::class) + verify(operations, times(1)).count(query, First::class.java) + } + + @Test + fun `count(Query, KClass, String) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val collectionName = "foo" + operations.count(query, First::class, collectionName) + verify(operations, times(1)).count(query, First::class.java, collectionName) + } + + @Test + fun `insert(Collection, KClass) extension should call its Java counterpart`() { + val collection = listOf(First(), First()) + operations.insert(collection, First::class) + verify(operations, times(1)).insert(collection, First::class.java) + } + + @Test + fun `upsert(Query, Update, KClass) extension should call its Java counterpart`() { + val query = mock() + val update = mock() + operations.upsert(query, update, First::class) + verify(operations, times(1)).upsert(query, update, First::class.java) + } + + @Test + fun `upsert(Query, Update, KClass, String) extension should call its Java counterpart`() { + val query = mock() + val update = mock() + val collectionName = "foo" + operations.upsert(query, update, First::class, collectionName) + verify(operations, times(1)).upsert(query, update, First::class.java, collectionName) + } + + @Test + fun `upsert(Query, Update) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val update = mock() + operations.upsert(query, update) + verify(operations, times(1)).upsert(query, update, First::class.java) + } + + @Test + fun `upsert(Query, Update, String) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val update = mock() + val collectionName = "foo" + operations.upsert(query, update, collectionName) + verify(operations, times(1)).upsert(query, update, First::class.java, collectionName) + } + + @Test + fun `updateFirst(Query, Update, KClass) extension should call its Java counterpart`() { + val query = mock() + val update = mock() + operations.updateFirst(query, update, First::class) + verify(operations, times(1)).updateFirst(query, update, First::class.java) + } + + @Test + fun `updateFirst(Query, Update, KClass, String) extension should call its Java counterpart`() { + val query = mock() + val update = mock() + val collectionName = "foo" + operations.updateFirst(query, update, First::class, collectionName) + verify(operations, times(1)).updateFirst(query, update, First::class.java, collectionName) + } + + @Test + fun `updateFirst(Query, Update) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val update = mock() + operations.updateFirst(query, update) + verify(operations, times(1)).updateFirst(query, update, First::class.java) + } + + @Test + fun `updateFirst(Query, Update, String) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val update = mock() + val collectionName = "foo" + operations.updateFirst(query, update, collectionName) + verify(operations, times(1)).updateFirst(query, update, First::class.java, collectionName) + } + + @Test + fun `updateMulti(Query, Update, KClass) extension should call its Java counterpart`() { + val query = mock() + val update = mock() + operations.updateMulti(query, update, First::class) + verify(operations, times(1)).updateMulti(query, update, First::class.java) + } + + @Test + fun `updateMulti(Query, Update, KClass, String) extension should call its Java counterpart`() { + val query = mock() + val update = mock() + val collectionName = "foo" + operations.updateMulti(query, update, First::class, collectionName) + verify(operations, times(1)).updateMulti(query, update, First::class.java, collectionName) + } + + @Test + fun `updateMulti(Query, Update) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val update = mock() + operations.updateMulti(query, update) + verify(operations, times(1)).updateMulti(query, update, First::class.java) + } + + @Test + fun `updateMulti(Query, Update, String) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val update = mock() + val collectionName = "foo" + operations.updateMulti(query, update, collectionName) + verify(operations, times(1)).updateMulti(query, update, First::class.java, collectionName) + } + + @Test + fun `remove(Query, KClass) extension should call its Java counterpart`() { + val query = mock() + operations.remove(query, First::class) + verify(operations, times(1)).remove(query, First::class.java) + } + + @Test + fun `remove(Query, KClass, String) extension should call its Java counterpart`() { + val query = mock() + val collectionName = "foo" + operations.remove(query, First::class, collectionName) + verify(operations, times(1)).remove(query, First::class.java, collectionName) + } + + @Test + fun `remove(Query) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + operations.remove(query) + verify(operations, times(1)).remove(query, First::class.java) + } + + @Test + fun `remove(Query, String) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val collectionName = "foo" + operations.remove(query, collectionName) + verify(operations, times(1)).remove(query, First::class.java, collectionName) + } + + @Test + fun `findAllAndRemove(Query) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + operations.findAllAndRemove(query) + verify(operations, times(1)).findAllAndRemove(query, First::class.java) + } + +} diff --git a/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/ReactiveMongoOperationsExtensionsTests.kt b/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/ReactiveMongoOperationsExtensionsTests.kt new file mode 100644 index 000000000..b45c563dc --- /dev/null +++ b/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/ReactiveMongoOperationsExtensionsTests.kt @@ -0,0 +1,434 @@ +/* + * Copyright 2016-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.core + +import com.nhaarman.mockito_kotlin.mock +import example.first.First +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Answers +import org.mockito.Mock +import org.mockito.Mockito.* +import org.mockito.junit.MockitoJUnitRunner +import org.springframework.data.mongodb.core.query.NearQuery +import org.springframework.data.mongodb.core.query.Query +import org.springframework.data.mongodb.core.query.Update +import reactor.core.publisher.Mono + +/** + * @author Sebastien Deleuze + */ +@RunWith(MockitoJUnitRunner::class) +class ReactiveMongoOperationsExtensionsTests { + + @Mock(answer = Answers.RETURNS_MOCKS) + lateinit var operations: ReactiveMongoOperations + + @Test + fun `indexOps(KClass) extension should call its Java counterpart`() { + operations.indexOps(First::class) + verify(operations, times(1)).indexOps(First::class.java) + } + + @Test + fun `indexOps() with reified type parameter extension should call its Java counterpart`() { + operations.indexOps() + verify(operations, times(1)).indexOps(First::class.java) + } + + @Test + fun `execute(ReactiveCollectionCallback) with reified type parameter extension should call its Java counterpart`() { + val collectionCallback = mock>() + operations.execute(collectionCallback) + verify(operations, times(1)).execute(First::class.java, collectionCallback) + } + + @Test + fun `createCollection(KClass) extension should call its Java counterpart`() { + operations.createCollection(First::class) + verify(operations, times(1)).createCollection(First::class.java) + } + + @Test + fun `createCollection(KClass, CollectionOptions) extension should call its Java counterpart`() { + val collectionOptions = mock() + operations.createCollection(First::class, collectionOptions) + verify(operations, times(1)).createCollection(First::class.java, collectionOptions) + } + + @Test + fun `createCollection() with reified type parameter extension should call its Java counterpart`() { + operations.createCollection() + verify(operations, times(1)).createCollection(First::class.java) + } + + @Test + fun `createCollection(CollectionOptions) with reified type parameter extension should call its Java counterpart`() { + val collectionOptions = mock() + operations.createCollection(collectionOptions) + verify(operations, times(1)).createCollection(First::class.java, collectionOptions) + } + + @Test + fun `collectionExists(KClass) extension should call its Java counterpart`() { + operations.collectionExists(First::class) + verify(operations, times(1)).collectionExists(First::class.java) + } + + @Test + fun `collectionExists() with reified type parameter extension should call its Java counterpart`() { + operations.collectionExists() + verify(operations, times(1)).collectionExists(First::class.java) + } + + @Test + fun `dropCollection(KClass) extension should call its Java counterpart`() { + operations.dropCollection(First::class) + verify(operations, times(1)).dropCollection(First::class.java) + } + + @Test + fun `dropCollection() with reified type parameter extension should call its Java counterpart`() { + operations.dropCollection() + verify(operations, times(1)).dropCollection(First::class.java) + } + + @Test + fun `findAll() with reified type parameter extension should call its Java counterpart`() { + operations.findAll() + verify(operations, times(1)).findAll(First::class.java) + } + + @Test + fun `findAll(String) with reified type parameter extension should call its Java counterpart`() { + val collectionName = "foo" + operations.findAll(collectionName) + verify(operations, times(1)).findAll(First::class.java, collectionName) + } + + @Test + fun `findOne(Query) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + operations.findOne(query) + verify(operations, times(1)).findOne(query, First::class.java) + } + + @Test + fun `findOne(Query, String) with reified type parameter extension should call its Java counterpart`() { + val collectionName = "foo" + val query = mock() + operations.findOne(query, collectionName) + verify(operations, times(1)).findOne(query, First::class.java, collectionName) + } + + @Test + fun `exists(Query, KClass) extension should call its Java counterpart`() { + val query = mock() + operations.exists(query, First::class) + verify(operations, times(1)).exists(query, First::class.java) + } + + @Test + fun `exists(Query) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + operations.exists(query) + verify(operations, times(1)).exists(query, First::class.java) + } + + @Test + fun `find(Query) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + operations.find(query) + verify(operations, times(1)).find(query, First::class.java) + } + + @Test + fun `find(Query, String) with reified type parameter extension should call its Java counterpart`() { + val collectionName = "foo" + val query = mock() + operations.find(query, collectionName) + verify(operations, times(1)).find(query, First::class.java, collectionName) + } + + @Test + fun `findById(Any) with reified type parameter extension should call its Java counterpart`() { + val id = 1L + operations.findById(id) + verify(operations, times(1)).findById(id, First::class.java) + } + + @Test + fun `findById(Any, String) with reified type parameter extension should call its Java counterpart`() { + val collectionName = "foo" + val id = 1L + operations.findById(id, collectionName) + verify(operations, times(1)).findById(id, First::class.java, collectionName) + } + + @Test + fun `geoNear(Query) with reified type parameter extension should call its Java counterpart`() { + val query = NearQuery.near(0.0, 0.0) + operations.geoNear(query) + verify(operations, times(1)).geoNear(query, First::class.java) + } + + @Test + fun `geoNear(Query, String) with reified type parameter extension should call its Java counterpart`() { + val collectionName = "foo" + val query = NearQuery.near(0.0, 0.0) + operations.geoNear(query, collectionName) + verify(operations, times(1)).geoNear(query, First::class.java, collectionName) + } + + @Test + fun `findAndModify(Query, Update, FindAndModifyOptions) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val update = mock() + val options = mock() + operations.findAndModify(query, update, options) + verify(operations, times(1)).findAndModify(query, update, options, First::class.java) + } + + @Test + fun `findAndModify(Query, Update, FindAndModifyOptions, String) with reified type parameter extension should call its Java counterpart`() { + val collectionName = "foo" + val query = mock() + val update = mock() + val options = mock() + operations.findAndModify(query, update, options, collectionName) + verify(operations, times(1)).findAndModify(query, update, options, First::class.java, collectionName) + } + + @Test + fun `findAndRemove(Query) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + operations.findAndRemove(query) + verify(operations, times(1)).findAndRemove(query, First::class.java) + } + + @Test + fun `findAndRemove(Query, String) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val collectionName = "foo" + operations.findAndRemove(query, collectionName) + verify(operations, times(1)).findAndRemove(query, First::class.java, collectionName) + } + + @Test + fun `count() with reified type parameter extension should call its Java counterpart`() { + operations.count() + verify(operations, times(1)).count(any(), eq(First::class.java)) + } + + @Test + fun `count(Query) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + operations.count(query) + verify(operations, times(1)).count(query, First::class.java) + } + + @Test + fun `count(Query, String) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val collectionName = "foo" + operations.count(query, collectionName) + verify(operations, times(1)).count(query, First::class.java, collectionName) + } + + @Test + fun `count(Query, KClass) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + operations.count(query, First::class) + verify(operations, times(1)).count(query, First::class.java) + } + + @Test + fun `count(Query, KClass, String) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val collectionName = "foo" + operations.count(query, First::class, collectionName) + verify(operations, times(1)).count(query, First::class.java, collectionName) + } + + @Test + fun `insert(Collection, KClass) extension should call its Java counterpart`() { + val collection = listOf(First(), First()) + operations.insert(collection, First::class) + verify(operations, times(1)).insert(collection, First::class.java) + } + + @Test + fun `insertAll(Mono, KClass) extension should call its Java counterpart`() { + val collection = Mono.just(listOf(First(), First())) + operations.insertAll(collection, First::class) + verify(operations, times(1)).insertAll(collection, First::class.java) + } + + @Test + fun `upsert(Query, Update, KClass) extension should call its Java counterpart`() { + val query = mock() + val update = mock() + operations.upsert(query, update, First::class) + verify(operations, times(1)).upsert(query, update, First::class.java) + } + + @Test + fun `upsert(Query, Update, KClass, String) extension should call its Java counterpart`() { + val query = mock() + val update = mock() + val collectionName = "foo" + operations.upsert(query, update, First::class, collectionName) + verify(operations, times(1)).upsert(query, update, First::class.java, collectionName) + } + + @Test + fun `upsert(Query, Update) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val update = mock() + operations.upsert(query, update) + verify(operations, times(1)).upsert(query, update, First::class.java) + } + + @Test + fun `upsert(Query, Update, String) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val update = mock() + val collectionName = "foo" + operations.upsert(query, update, collectionName) + verify(operations, times(1)).upsert(query, update, First::class.java, collectionName) + } + + @Test + fun `updateFirst(Query, Update, KClass) extension should call its Java counterpart`() { + val query = mock() + val update = mock() + operations.updateFirst(query, update, First::class) + verify(operations, times(1)).updateFirst(query, update, First::class.java) + } + + @Test + fun `updateFirst(Query, Update, KClass, String) extension should call its Java counterpart`() { + val query = mock() + val update = mock() + val collectionName = "foo" + operations.updateFirst(query, update, First::class, collectionName) + verify(operations, times(1)).updateFirst(query, update, First::class.java, collectionName) + } + + @Test + fun `updateFirst(Query, Update) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val update = mock() + operations.updateFirst(query, update) + verify(operations, times(1)).updateFirst(query, update, First::class.java) + } + + @Test + fun `updateFirst(Query, Update, String) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val update = mock() + val collectionName = "foo" + operations.updateFirst(query, update, collectionName) + verify(operations, times(1)).updateFirst(query, update, First::class.java, collectionName) + } + + @Test + fun `updateMulti(Query, Update, KClass) extension should call its Java counterpart`() { + val query = mock() + val update = mock() + operations.updateMulti(query, update, First::class) + verify(operations, times(1)).updateMulti(query, update, First::class.java) + } + + @Test + fun `updateMulti(Query, Update, KClass, String) extension should call its Java counterpart`() { + val query = mock() + val update = mock() + val collectionName = "foo" + operations.updateMulti(query, update, First::class, collectionName) + verify(operations, times(1)).updateMulti(query, update, First::class.java, collectionName) + } + + @Test + fun `updateMulti(Query, Update) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val update = mock() + operations.updateMulti(query, update) + verify(operations, times(1)).updateMulti(query, update, First::class.java) + } + + @Test + fun `updateMulti(Query, Update, String) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val update = mock() + val collectionName = "foo" + operations.updateMulti(query, update, collectionName) + verify(operations, times(1)).updateMulti(query, update, First::class.java, collectionName) + } + + @Test + fun `remove(Query, KClass) extension should call its Java counterpart`() { + val query = mock() + operations.remove(query, First::class) + verify(operations, times(1)).remove(query, First::class.java) + } + + @Test + fun `remove(Query, KClass, String) extension should call its Java counterpart`() { + val query = mock() + val collectionName = "foo" + operations.remove(query, First::class, collectionName) + verify(operations, times(1)).remove(query, First::class.java, collectionName) + } + + @Test + fun `remove(Query) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + operations.remove(query) + verify(operations, times(1)).remove(query, First::class.java) + } + + @Test + fun `remove(Query, String) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val collectionName = "foo" + operations.remove(query, collectionName) + verify(operations, times(1)).remove(query, First::class.java, collectionName) + } + + @Test + fun `findAllAndRemove(Query) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + operations.findAllAndRemove(query) + verify(operations, times(1)).findAllAndRemove(query, First::class.java) + } + + @Test + fun `tail(Query) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + operations.tail(query) + verify(operations, times(1)).tail(query, First::class.java) + } + + @Test + fun `tail(Query, String) with reified type parameter extension should call its Java counterpart`() { + val query = mock() + val collectionName = "foo" + operations.tail(query, collectionName) + verify(operations, times(1)).tail(query, First::class.java, collectionName) + } + +}