diff --git a/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/ExecutableFindOperationExtensions.kt b/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/ExecutableFindOperationExtensions.kt index e4a88c79c..15a5c1807 100644 --- a/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/ExecutableFindOperationExtensions.kt +++ b/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/ExecutableFindOperationExtensions.kt @@ -15,7 +15,10 @@ */ package org.springframework.data.mongodb.core +import org.springframework.data.mongodb.core.query.asString import kotlin.reflect.KClass +import kotlin.reflect.KProperty +import kotlin.reflect.KProperty1 /** * Extension for [ExecutableFindOperation.query] providing a [KClass] based variant. @@ -38,6 +41,15 @@ fun ExecutableFindOperation.query(entityClass: KClass): ExecutableF inline fun ExecutableFindOperation.query(): ExecutableFindOperation.ExecutableFind = query(T::class.java) +/** + * Extension for [ExecutableFindOperation.query] for a type-safe projection of distinct values. + * + * @author Mark Paluch + * @since 2.3 + */ +inline fun ExecutableFindOperation.distinct(field : KProperty1): ExecutableFindOperation.TerminatingDistinct = + query(T::class.java).distinct(field.name) + /** * Extension for [ExecutableFindOperation.FindWithProjection.as] providing a [KClass] based variant. * @@ -78,3 +90,12 @@ fun ExecutableFindOperation.DistinctWithProjection.asType(resultType: */ inline fun ExecutableFindOperation.DistinctWithProjection.asType(): ExecutableFindOperation.TerminatingDistinct = `as`(T::class.java) + +/** + * Extension for [ExecutableFindOperation.FindDistinct.distinct] leveraging KProperty. + * + * @author Mark Paluch + * @since 2.3 + */ +fun ExecutableFindOperation.FindDistinct.distinct(key: KProperty<*>): ExecutableFindOperation.TerminatingDistinct = + distinct(asString(key)) diff --git a/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/ReactiveFindOperationExtensions.kt b/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/ReactiveFindOperationExtensions.kt index 1037c22c2..6772ab623 100644 --- a/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/ReactiveFindOperationExtensions.kt +++ b/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/ReactiveFindOperationExtensions.kt @@ -20,7 +20,10 @@ import kotlinx.coroutines.reactive.asFlow import kotlinx.coroutines.reactive.awaitFirstOrNull import kotlinx.coroutines.reactive.awaitSingle import org.springframework.data.geo.GeoResult +import org.springframework.data.mongodb.core.query.asString import kotlin.reflect.KClass +import kotlin.reflect.KProperty +import kotlin.reflect.KProperty1 /** * Extension for [ReactiveFindOperation.query] providing a [KClass] based variant. @@ -41,6 +44,15 @@ fun ReactiveFindOperation.query(entityClass: KClass): ReactiveFindO inline fun ReactiveFindOperation.query(): ReactiveFindOperation.ReactiveFind = query(T::class.java) +/** + * Extension for [ReactiveFindOperation.query] for a type-safe projection of distinct values. + * + * @author Mark Paluch + * @since 2.3 + */ +inline fun ReactiveFindOperation.distinct(field : KProperty1): ReactiveFindOperation.TerminatingDistinct = + query(T::class.java).distinct(field.name) + /** * Extension for [ReactiveFindOperation.FindWithProjection.as] providing a [KClass] based variant. * @@ -79,6 +91,15 @@ fun ReactiveFindOperation.DistinctWithProjection.asType(resultType: KC inline fun ReactiveFindOperation.DistinctWithProjection.asType(): ReactiveFindOperation.TerminatingDistinct = `as`(T::class.java) +/** + * Extension for [ReactiveFindOperation.FindDistinct.distinct] leveraging KProperty. + * + * @author Mark Paluch + * @since 2.3 + */ +fun ReactiveFindOperation.FindDistinct.distinct(key: KProperty<*>): ReactiveFindOperation.TerminatingDistinct = + distinct(asString(key)) + /** * Non-nullable Coroutines variant of [ReactiveFindOperation.TerminatingFind.one]. * diff --git a/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/ExecutableFindOperationExtensionsTests.kt b/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/ExecutableFindOperationExtensionsTests.kt index 624f110fb..cbe614551 100644 --- a/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/ExecutableFindOperationExtensionsTests.kt +++ b/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/ExecutableFindOperationExtensionsTests.kt @@ -16,6 +16,7 @@ package org.springframework.data.mongodb.core import example.first.First +import io.mockk.every import io.mockk.mockk import io.mockk.verify import org.junit.Test @@ -32,6 +33,10 @@ class ExecutableFindOperationExtensionsTests { val distinctWithProjection = mockk(relaxed = true) + val findDistinct = mockk(relaxed = true) + + val executableFind = mockk>(relaxed = true) + @Test // DATAMONGO-1689 @Suppress("DEPRECATION") fun `ExecutableFindOperation#query(KClass) extension should call its Java counterpart`() { @@ -76,4 +81,25 @@ class ExecutableFindOperationExtensionsTests { distinctWithProjection.asType() verify { distinctWithProjection.`as`(User::class.java) } } + + @Test // DATAMONGO-2417 + fun `ExecutableFindOperation#distrinct() using KProperty1 should call its Java counterpart`() { + + every { operation.query(KotlinUser::class.java) } returns executableFind + + operation.distinct(KotlinUser::username) + verify { + operation.query(KotlinUser::class.java) + executableFind.distinct("username") + } + } + + @Test // DATAMONGO-2417 + fun `ExecutableFindOperation#FindDistinct#field() using KProperty should call its Java counterpart`() { + + findDistinct.distinct(KotlinUser::username) + verify { findDistinct.distinct("username") } + } + + data class KotlinUser(val username: String) } diff --git a/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/ReactiveFindOperationExtensionsTests.kt b/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/ReactiveFindOperationExtensionsTests.kt index 117b95383..b031b03f2 100644 --- a/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/ReactiveFindOperationExtensionsTests.kt +++ b/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/ReactiveFindOperationExtensionsTests.kt @@ -42,6 +42,10 @@ class ReactiveFindOperationExtensionsTests { val distinctWithProjection = mockk(relaxed = true) + val findDistinct = mockk(relaxed = true) + + val reactiveFind = mockk>(relaxed = true) + @Test // DATAMONGO-1719 @Suppress("DEPRECATION") fun `ReactiveFind#query(KClass) extension should call its Java counterpart`() { @@ -87,6 +91,25 @@ class ReactiveFindOperationExtensionsTests { verify { distinctWithProjection.`as`(User::class.java) } } + @Test // DATAMONGO-2417 + fun `ReactiveFind#distrinct() using KProperty1 should call its Java counterpart`() { + + every { operation.query(KotlinUser::class.java) } returns reactiveFind + + operation.distinct(KotlinUser::username) + verify { + operation.query(KotlinUser::class.java) + reactiveFind.distinct("username") + } + } + + @Test // DATAMONGO-2417 + fun `ReactiveFind#FindDistinct#field() using KProperty should call its Java counterpart`() { + + findDistinct.distinct(KotlinUser::username) + verify { findDistinct.distinct("username") } + } + @Test // DATAMONGO-2209 fun terminatingFindAwaitOneWithValue() { @@ -299,4 +322,6 @@ class ReactiveFindOperationExtensionsTests { spec.all() } } + + data class KotlinUser(val username: String) }