DATACMNS-1508 - Polishing.
Add findAllById, deleteAll to CoroutineCrudRepository. Keep CoroutineCrudRepository somewhat in sync with ReactiveCrudRepository by adding based methods for those accecpting Publisher. Also add some test. Update License Headers of Kotlin files and fix some warnings. Switch to kotlin-test-junit5. Original pull request: #415.
This commit is contained in:
committed by
Mark Paluch
parent
93c708379e
commit
769b0f6af5
3
pom.xml
3
pom.xml
@@ -287,7 +287,8 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-test</artifactId>
|
||||
<artifactId>kotlin-test-junit5</artifactId>
|
||||
<version>${kotlin}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -40,13 +40,12 @@ import org.springframework.lang.Nullable;
|
||||
* errors.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @since 2.3
|
||||
* @see org.springframework.core.KotlinDetector#isKotlinReflectPresent()
|
||||
*/
|
||||
public final class KotlinReflectionUtils {
|
||||
|
||||
private static final int KOTLIN_KIND_CLASS = 1;
|
||||
|
||||
private KotlinReflectionUtils() {}
|
||||
|
||||
/**
|
||||
@@ -64,7 +63,7 @@ public final class KotlinReflectionUtils {
|
||||
return Arrays.stream(type.getDeclaredAnnotations()) //
|
||||
.filter(annotation -> annotation.annotationType().getName().equals("kotlin.Metadata")) //
|
||||
.map(annotation -> AnnotationUtils.getValue(annotation, "k")) //
|
||||
.anyMatch(it -> Integer.valueOf(KOTLIN_KIND_CLASS).equals(it));
|
||||
.anyMatch(it -> Integer.valueOf(KotlinClassHeaderKind.CLASS.id).equals(it));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -202,4 +201,15 @@ public final class KotlinReflectionUtils {
|
||||
Method javaMethod = ReflectJvmMapping.getJavaMethod(function);
|
||||
return javaMethod != null && javaMethod.equals(method);
|
||||
}
|
||||
|
||||
private enum KotlinClassHeaderKind {
|
||||
|
||||
CLASS(1), FILE(2), SYNTHETIC_CLASS(3), MULTI_FILE_CLASS_FACADE(4), MULTI_FILE_CLASS_PART(5);
|
||||
|
||||
int id;
|
||||
|
||||
KotlinClassHeaderKind(int val) {
|
||||
this.id = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2019 the original author or authors.
|
||||
* Copyright 2018-2020 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
* Copyright 2019-2020 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.
|
||||
@@ -24,6 +24,7 @@ import reactor.core.publisher.Mono
|
||||
* Interface for generic CRUD operations using Kotlin Coroutines on a repository for a specific type.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @since 2.3
|
||||
* @see Flow
|
||||
*/
|
||||
@@ -96,6 +97,18 @@ interface CoroutineCrudRepository<T, ID> : Repository<T, ID> {
|
||||
*/
|
||||
fun findAllById(ids: Iterable<ID>): Flow<T>
|
||||
|
||||
/**
|
||||
* Returns all instances of the type `T` with the given IDs.
|
||||
* If some or all ids are not found, no entities are returned for these IDs.
|
||||
* Note that the order of elements in the result is not guaranteed.
|
||||
*
|
||||
* @param ids must not be null nor contain any null values.
|
||||
* @return [Flow] emitting the found entities. The size can be equal or less than the number of given
|
||||
* ids.
|
||||
* @throws IllegalArgumentException in case the given [ids][Iterable] or one of its items is null.
|
||||
*/
|
||||
fun findAllById(ids: Flow<ID>): Flow<T>
|
||||
|
||||
/**
|
||||
* Returns the number of entities available.
|
||||
*
|
||||
@@ -128,6 +141,14 @@ interface CoroutineCrudRepository<T, ID> : Repository<T, ID> {
|
||||
*/
|
||||
suspend fun deleteAll(entities: Iterable<T>)
|
||||
|
||||
/**
|
||||
* Deletes all given entities.
|
||||
*
|
||||
* @param entityStream must not be null.
|
||||
* @throws IllegalArgumentException in case the given [entityStream][Flow] is null.
|
||||
*/
|
||||
fun <S : T> deleteAll(entityStream: Flow<S>)
|
||||
|
||||
/**
|
||||
* Deletes all entities managed by the repository.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
* Copyright 2019-2020 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.
|
||||
|
||||
@@ -112,7 +112,7 @@ public class DummyRepositoryFactory extends RepositoryFactorySupport {
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public static interface MyRepositoryQuery extends RepositoryQuery {
|
||||
public interface MyRepositoryQuery extends RepositoryQuery {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2019 the original author or authors.
|
||||
* Copyright 2017-2020 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2019 the original author or authors.
|
||||
* Copyright 2017-2020 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2019 the original author or authors.
|
||||
* Copyright 2017-2020 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.
|
||||
@@ -18,5 +18,4 @@ package org.springframework.data.mapping.context
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
data class SimpleDataClass(val firstname: String, val lastname: String) {
|
||||
}
|
||||
data class SimpleDataClass(val firstname: String, val lastname: String)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2019 the original author or authors.
|
||||
* Copyright 2017-2020 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.
|
||||
@@ -18,8 +18,7 @@ package org.springframework.data.mapping.context
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class TypeCreatingSyntheticClass {
|
||||
}
|
||||
class TypeCreatingSyntheticClass
|
||||
|
||||
fun foobar(args: Array<String>) {
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2019 the original author or authors.
|
||||
* Copyright 2018-2020 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.
|
||||
@@ -20,8 +20,7 @@ import java.util.*
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
data class DataClassKt(val id: String) {
|
||||
}
|
||||
data class DataClassKt(val id: String)
|
||||
|
||||
data class ExtendedDataClassKt(val id: Long, val name: String) {
|
||||
fun copy(name: String, id: Long): ExtendedDataClassKt {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2019 the original author or authors.
|
||||
* Copyright 2017-2020 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.
|
||||
@@ -109,8 +109,7 @@ class PreferredConstructorDiscovererUnitTests {
|
||||
constructor(firstname: String, lastname: String) : this(firstname)
|
||||
}
|
||||
|
||||
class DefaultConstructor(val firstname: String = "foo") {
|
||||
}
|
||||
class DefaultConstructor(val firstname: String = "foo")
|
||||
|
||||
class TwoDefaultConstructorsAnnotated(val firstname: String = "foo", val lastname: String = "bar") {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2019 the original author or authors.
|
||||
* Copyright 2017-2020 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.
|
||||
@@ -18,8 +18,7 @@ package org.springframework.data.mapping.model
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class TypeCreatingSyntheticClass {
|
||||
}
|
||||
class TypeCreatingSyntheticClass
|
||||
|
||||
fun foobar(args: Array<String>) {
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2019 the original author or authors.
|
||||
* Copyright 2018-2020 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.
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
package org.springframework.data.mapping.model
|
||||
|
||||
import java.sql.Timestamp
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2019 the original author or authors.
|
||||
* Copyright 2018-2020 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.
|
||||
@@ -18,5 +18,4 @@ package org.springframework.data.mapping.model
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class ValueClassKt(val immutable: String) {
|
||||
}
|
||||
class ValueClassKt(val immutable: String)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2019 the original author or authors.
|
||||
* Copyright 2018-2020 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2019 the original author or authors.
|
||||
* Copyright 2018-2020 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2019 the original author or authors.
|
||||
* Copyright 2008-2020 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2019 the original author or authors.
|
||||
* Copyright 2017-2020 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
* Copyright 2019-2020 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.
|
||||
@@ -35,8 +35,8 @@ import org.springframework.data.repository.sample.User
|
||||
class CoroutineCrudRepositoryCustomImplementationUnitTests {
|
||||
|
||||
val backingRepository = mockk<ReactiveCrudRepository<User, String>>()
|
||||
lateinit var factory: DummyReactiveRepositoryFactory;
|
||||
lateinit var coRepository: MyCoRepository;
|
||||
lateinit var factory: DummyReactiveRepositoryFactory
|
||||
lateinit var coRepository: MyCoRepository
|
||||
|
||||
@Before
|
||||
fun before() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
* Copyright 2019-2020 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.
|
||||
@@ -17,13 +17,16 @@ package org.springframework.data.repository.kotlin
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mockito
|
||||
import org.reactivestreams.Publisher
|
||||
import org.springframework.data.repository.core.support.DummyReactiveRepositoryFactory
|
||||
import org.springframework.data.repository.reactive.ReactiveCrudRepository
|
||||
import org.springframework.data.repository.sample.User
|
||||
@@ -40,8 +43,8 @@ import rx.Single
|
||||
class CoroutineCrudRepositoryUnitTests {
|
||||
|
||||
val backingRepository = mockk<ReactiveCrudRepository<User, String>>()
|
||||
lateinit var factory: DummyReactiveRepositoryFactory;
|
||||
lateinit var coRepository: MyCoRepository;
|
||||
lateinit var factory: DummyReactiveRepositoryFactory
|
||||
lateinit var coRepository: MyCoRepository
|
||||
|
||||
@Before
|
||||
fun before() {
|
||||
@@ -54,7 +57,7 @@ class CoroutineCrudRepositoryUnitTests {
|
||||
|
||||
val sample = User()
|
||||
|
||||
every { backingRepository.findAll() }.returns(Flux.just(sample))
|
||||
every { backingRepository.findAll() } returns Flux.just(sample)
|
||||
|
||||
val result = runBlocking {
|
||||
coRepository.findAll().toList()
|
||||
@@ -63,12 +66,54 @@ class CoroutineCrudRepositoryUnitTests {
|
||||
assertThat(result).hasSize(1).containsOnly(sample)
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1508
|
||||
fun shouldInvokeFindAllById() {
|
||||
|
||||
every { backingRepository.findAllById(any<Publisher<String>>()) } returns Flux.fromArray(arrayOf(User(), User()))
|
||||
|
||||
val result = runBlocking {
|
||||
coRepository.findAllById(flowOf("user-1", "user-2")).toList()
|
||||
}
|
||||
|
||||
assertThat(result).hasSize(2)
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1508
|
||||
fun shouldInvokeSaveAllWhenGivenIterable() {
|
||||
|
||||
val sample = listOf(User(), User())
|
||||
|
||||
every { backingRepository.saveAll(any<Iterable<User>>()) } returns Flux.fromIterable(sample)
|
||||
|
||||
val result = runBlocking {
|
||||
coRepository.saveAll(sample).toList()
|
||||
}
|
||||
|
||||
assertThat(result).containsExactlyElementsOf(sample)
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1508
|
||||
fun shouldInvokeSaveAllWhenGivenFlow() {
|
||||
|
||||
val u1 = User()
|
||||
val u2 = User()
|
||||
val sample = flowOf(u1, u2)
|
||||
|
||||
every { backingRepository.saveAll(any<Publisher<User>>()) } returns Flux.fromArray(arrayOf(u1, u2))
|
||||
|
||||
val result = runBlocking {
|
||||
coRepository.saveAll(sample).toList()
|
||||
}
|
||||
|
||||
assertThat(result).containsExactly(u1, u2)
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1508
|
||||
fun shouldInvokeFindById() {
|
||||
|
||||
val sample = User()
|
||||
|
||||
every { backingRepository.findById("foo") }.returns(Mono.just(sample))
|
||||
every { backingRepository.findById("foo") } returns Mono.just(sample)
|
||||
|
||||
val result = runBlocking {
|
||||
coRepository.findById("foo")
|
||||
@@ -77,6 +122,60 @@ class CoroutineCrudRepositoryUnitTests {
|
||||
assertThat(result).isNotNull().isEqualTo(sample)
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1508
|
||||
fun shouldInvokeExistsById() {
|
||||
|
||||
every { backingRepository.existsById("foo") } returns Mono.just(true)
|
||||
|
||||
val result = runBlocking {
|
||||
coRepository.existsById("foo")
|
||||
}
|
||||
|
||||
assertThat(result).isTrue()
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1508
|
||||
fun shouldInvokeDeleteAll() {
|
||||
|
||||
every { backingRepository.deleteAll() } returns Mono.empty()
|
||||
|
||||
runBlocking {
|
||||
coRepository.deleteAll()
|
||||
}
|
||||
|
||||
verify { backingRepository.deleteAll() }
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1508
|
||||
fun shouldInvokeDeleteAllWhenGivenIterable() {
|
||||
|
||||
val sample = listOf(User(), User())
|
||||
|
||||
every { backingRepository.deleteAll(any<Iterable<User>>()) } returns Mono.empty()
|
||||
|
||||
runBlocking {
|
||||
coRepository.deleteAll(sample)
|
||||
}
|
||||
|
||||
verify { backingRepository.deleteAll(sample) }
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1508
|
||||
fun shouldInvokeDeleteAllWhenGivenFlow() {
|
||||
|
||||
val u1 = User()
|
||||
val u2 = User()
|
||||
val sample = flowOf(u1, u2)
|
||||
|
||||
every { backingRepository.deleteAll(any<Publisher<User>>()) } returns Mono.empty()
|
||||
|
||||
runBlocking {
|
||||
coRepository.deleteAll(sample)
|
||||
}
|
||||
|
||||
verify { backingRepository.deleteAll(any<Publisher<User>>()) }
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1508
|
||||
fun shouldBridgeQueryMethod() {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
* Copyright 2019-2020 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.
|
||||
@@ -19,7 +19,6 @@ import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer
|
||||
import org.springframework.core.MethodParameter
|
||||
import org.springframework.core.ParameterNameDiscoverer
|
||||
import kotlin.reflect.jvm.javaMethod
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2019 the original author or authors.
|
||||
* Copyright 2017-2020 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2019 the original author or authors.
|
||||
* Copyright 2017-2020 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.
|
||||
@@ -18,8 +18,7 @@ package org.springframework.data.util
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class TypeCreatingSyntheticClass {
|
||||
}
|
||||
class TypeCreatingSyntheticClass
|
||||
|
||||
fun foobar(args: Array<String>) {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user