DATAREDIS-1033 - Add Kotlin Flow based extensions.
Original Pull Request: #477
This commit is contained in:
committed by
Christoph Strobl
parent
669d3a9c5c
commit
78b895feb4
@@ -15,12 +15,19 @@
|
||||
*/
|
||||
package org.springframework.data.redis.core
|
||||
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.reactive.asFlow
|
||||
import kotlinx.coroutines.reactive.awaitFirstOrNull
|
||||
import kotlinx.coroutines.reactive.awaitSingle
|
||||
import kotlinx.coroutines.reactor.asFlux
|
||||
import org.springframework.data.geo.Circle
|
||||
import org.springframework.data.geo.Distance
|
||||
import org.springframework.data.geo.GeoResult
|
||||
import org.springframework.data.geo.Metric
|
||||
import org.springframework.data.geo.Point
|
||||
import org.springframework.data.redis.connection.RedisGeoCommands
|
||||
import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation
|
||||
import org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveGeoOperations.add].
|
||||
@@ -37,7 +44,7 @@ suspend fun <K : Any, M : Any> ReactiveGeoOperations<K, M>.addAndAwait(key: K, p
|
||||
* @author Mark Paluch
|
||||
* @since 2.2
|
||||
*/
|
||||
suspend fun <K : Any, M : Any> ReactiveGeoOperations<K, M>.addAndAwait(key: K, location: RedisGeoCommands.GeoLocation<M>): Long =
|
||||
suspend fun <K : Any, M : Any> ReactiveGeoOperations<K, M>.addAndAwait(key: K, location: GeoLocation<M>): Long =
|
||||
add(key, location).awaitSingle()
|
||||
|
||||
/**
|
||||
@@ -55,9 +62,19 @@ suspend fun <K : Any, M : Any> ReactiveGeoOperations<K, M>.addAndAwait(key: K, m
|
||||
* @author Mark Paluch
|
||||
* @since 2.2
|
||||
*/
|
||||
suspend fun <K : Any, M : Any> ReactiveGeoOperations<K, M>.addAndAwait(key: K, locations: Iterable<RedisGeoCommands.GeoLocation<M>>): Long =
|
||||
suspend fun <K : Any, M : Any> ReactiveGeoOperations<K, M>.addAndAwait(key: K, locations: Iterable<GeoLocation<M>>): Long =
|
||||
add(key, locations).awaitSingle()
|
||||
|
||||
/**
|
||||
* Coroutines [Flow] variant of [ReactiveGeoOperations.add].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, M : Any> ReactiveGeoOperations<K, M>.add(key: K, locations: Flow<Collection<GeoLocation<M>>>): Flow<Long> =
|
||||
add(key, locations.asFlux()).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveGeoOperations.distance].
|
||||
*
|
||||
@@ -115,6 +132,37 @@ suspend fun <K : Any, M : Any> ReactiveGeoOperations<K, M>.positionAndAwait(key:
|
||||
suspend fun <K : Any, M : Any> ReactiveGeoOperations<K, M>.positionAndAwait(key: K, vararg members: M): List<Point> =
|
||||
position(key, *members).awaitSingle()
|
||||
|
||||
/**
|
||||
* Coroutines [Flow] variant of [ReactiveGeoOperations.radius].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, M : Any> ReactiveGeoOperations<K, M>.radiusAsFlow(key: K, within: Circle, args: GeoRadiusCommandArgs? = null): Flow<GeoResult<GeoLocation<M>>> =
|
||||
(if (args != null) radius(key, within, args) else radius(key, within)).asFlow()
|
||||
|
||||
|
||||
/**
|
||||
* Coroutines [Flow] variant of [ReactiveGeoOperations.radius].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, M : Any> ReactiveGeoOperations<K, M>.radiusAsFlow(key: K, member: M, radius: Double): Flow<GeoResult<GeoLocation<M>>> =
|
||||
radius(key, member, radius).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines [Flow] variant of [ReactiveGeoOperations.radius].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, M : Any> ReactiveGeoOperations<K, M>.radiusAsFlow(key: K, member: M, distance: Distance, args: GeoRadiusCommandArgs? = null): Flow<GeoResult<GeoLocation<M>>> =
|
||||
(if (args != null) radius(key, member, distance, args) else radius(key, member, distance)).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveGeoOperations.remove].
|
||||
*
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.redis.core
|
||||
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.reactive.asFlow
|
||||
import kotlinx.coroutines.reactive.awaitFirstOrNull
|
||||
import kotlinx.coroutines.reactive.awaitSingle
|
||||
|
||||
@@ -55,6 +58,16 @@ suspend fun <H : Any, HK : Any, HV : Any> ReactiveHashOperations<H, HK, HV>.mult
|
||||
suspend fun <H : Any, HK : Any, HV : Any> ReactiveHashOperations<H, HK, HV>.incrementAndAwait(key: H, hashKey: HK, delta: Long): Long =
|
||||
increment(key, hashKey, delta).awaitSingle()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveHashOperations.keys].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <H : Any, HK : Any, HV : Any> ReactiveHashOperations<H, HK, HV>.keysAsFlow(key: H): Flow<HK> =
|
||||
keys(key).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveHashOperations.increment].
|
||||
*
|
||||
@@ -100,6 +113,36 @@ suspend fun <H : Any, HK : Any, HV : Any> ReactiveHashOperations<H, HK, HV>.putA
|
||||
suspend fun <H : Any, HK : Any, HV : Any> ReactiveHashOperations<H, HK, HV>.putIfAbsentAndAwait(key: H, hashKey: HK, hashValue: HV): Boolean =
|
||||
putIfAbsent(key, hashKey, hashValue).awaitSingle()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveHashOperations.values].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <H : Any, HK : Any, HV : Any> ReactiveHashOperations<H, HK, HV>.valuesAsFlow(key: H): Flow<HV> =
|
||||
values(key).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveHashOperations.entries].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <H : Any, HK : Any, HV : Any> ReactiveHashOperations<H, HK, HV>.entriesAsFlow(key: H): Flow<Map.Entry<HK, HV>> =
|
||||
entries(key).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveHashOperations.scan].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <H : Any, HK : Any, HV : Any> ReactiveHashOperations<H, HK, HV>.scanAsFlow(key: H, options: ScanOptions = ScanOptions.NONE): Flow<Map.Entry<HK, HV>> =
|
||||
scan(key, options).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveHashOperations.remove].
|
||||
*
|
||||
|
||||
@@ -15,10 +15,23 @@
|
||||
*/
|
||||
package org.springframework.data.redis.core
|
||||
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.reactive.asFlow
|
||||
import kotlinx.coroutines.reactive.awaitFirstOrNull
|
||||
import kotlinx.coroutines.reactive.awaitSingle
|
||||
import java.time.Duration
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveListOperations.range].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveListOperations<K, V>.rangeAsFlow(key: K, start: Long, end: Long): Flow<V> =
|
||||
range(key, start, end).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveListOperations.trim].
|
||||
*
|
||||
|
||||
@@ -15,12 +15,52 @@
|
||||
*/
|
||||
package org.springframework.data.redis.core
|
||||
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.reactive.asFlow
|
||||
import kotlinx.coroutines.reactive.asPublisher
|
||||
import kotlinx.coroutines.reactive.awaitFirstOrNull
|
||||
import kotlinx.coroutines.reactive.awaitSingle
|
||||
import org.springframework.data.redis.connection.DataType
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection
|
||||
import org.springframework.data.redis.connection.ReactiveSubscription.*
|
||||
import org.springframework.data.redis.core.script.RedisScript
|
||||
import org.springframework.data.redis.listener.Topic
|
||||
import org.springframework.data.redis.serializer.RedisElementReader
|
||||
import org.springframework.data.redis.serializer.RedisElementWriter
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveRedisOperations.execute].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any, T : Any> ReactiveRedisOperations<K, V>.executeAsFlow(action: (ReactiveRedisConnection) -> Flow<T>): Flow<T> =
|
||||
execute { action(it).asPublisher() }.asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveRedisOperations.execute].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any, T : Any> ReactiveRedisOperations<K, V>.executeAsFlow(script: RedisScript<T>, keys: List<K> = emptyList(), args: List<*> = emptyList<Any>()): Flow<T> =
|
||||
execute(script, keys, args).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveRedisOperations.execute].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any, T : Any> ReactiveRedisOperations<K, V>.executeAsFlow(script: RedisScript<T>, keys: List<K> = emptyList(), args: List<*> = emptyList<Any>(), argsWriter: RedisElementWriter<*>, resultReader: RedisElementReader<T>): Flow<T> =
|
||||
execute(script, keys, args, argsWriter, resultReader).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveRedisOperations.convertAndSend].
|
||||
*
|
||||
@@ -30,6 +70,36 @@ import java.time.Instant
|
||||
suspend fun <K : Any, V : Any> ReactiveRedisOperations<K, V>.sendAndAwait(destination: String, message: V): Long =
|
||||
convertAndSend(destination, message).awaitSingle()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveRedisOperations.listenToChannel].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveRedisOperations<K, V>.listenToChannelAsFlow(vararg channels: String): Flow<Message<String, V>> =
|
||||
listenToChannel(*channels).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveRedisOperations.listenToPattern].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveRedisOperations<K, V>.listenToPatternAsFlow(vararg patterns: String): Flow<Message<String, V>> =
|
||||
listenToPattern(*patterns).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveRedisOperations.listenTo].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveRedisOperations<K, V>.listenToAsFlow(vararg topics: Topic): Flow<Message<String, V>> =
|
||||
listenTo(*topics).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveRedisOperations.hasKey].
|
||||
*
|
||||
@@ -48,6 +118,26 @@ suspend fun <K : Any, V : Any> ReactiveRedisOperations<K, V>.hasKeyAndAwait(key:
|
||||
suspend fun <K : Any, V : Any> ReactiveRedisOperations<K, V>.typeAndAwait(key: K): DataType =
|
||||
type(key).awaitSingle()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveRedisOperations.keys].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveRedisOperations<K, V>.keysAsFlow(pattern: K): Flow<K> =
|
||||
keys(pattern).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveRedisOperations.scan].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveRedisOperations<K, V>.scanAsFlow(options: ScanOptions = ScanOptions.NONE): Flow<K> =
|
||||
scan(options).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveRedisOperations.randomKey].
|
||||
*
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.redis.core
|
||||
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.reactive.asFlow
|
||||
import kotlinx.coroutines.reactive.awaitFirstOrNull
|
||||
import kotlinx.coroutines.reactive.awaitSingle
|
||||
|
||||
@@ -45,6 +48,16 @@ suspend fun <K : Any, V : Any> ReactiveSetOperations<K, V>.removeAndAwait(key: K
|
||||
suspend fun <K : Any, V : Any> ReactiveSetOperations<K, V>.popAndAwait(key: K): V? =
|
||||
pop(key).awaitFirstOrNull()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveSetOperations.pop].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveSetOperations<K, V>.popAsFlow(key: K, count: Long): Flow<V> =
|
||||
pop(key, count).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveSetOperations.move].
|
||||
*
|
||||
@@ -72,6 +85,36 @@ suspend fun <K : Any, V : Any> ReactiveSetOperations<K, V>.sizeAndAwait(key: K):
|
||||
suspend fun <K : Any, V : Any> ReactiveSetOperations<K, V>.isMemberAndAwait(key: K, value: V): Boolean =
|
||||
isMember(key, value).awaitSingle()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveSetOperations.intersect].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveSetOperations<K, V>.intersectAsFlow(key: K, otherKey: K): Flow<V> =
|
||||
intersect(key, otherKey).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveSetOperations.intersect].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveSetOperations<K, V>.intersectAsFlow(key: K, otherKeys: Collection<K>): Flow<V> =
|
||||
intersect(key, otherKeys).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveSetOperations.intersect].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveSetOperations<K, V>.intersectAsFlow(otherKeys: Collection<K>): Flow<V> =
|
||||
intersect(otherKeys).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveSetOperations.intersectAndStore].
|
||||
*
|
||||
@@ -90,6 +133,36 @@ suspend fun <K : Any, V : Any> ReactiveSetOperations<K, V>.intersectAndStoreAndA
|
||||
suspend fun <K : Any, V : Any> ReactiveSetOperations<K, V>.intersectAndStoreAndAwait(keys: Collection<K>, destKey: K): Long =
|
||||
intersectAndStore(keys, destKey).awaitSingle()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveSetOperations.union].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveSetOperations<K, V>.unionAsFlow(key: K, otherKey: K): Flow<V> =
|
||||
union(key, otherKey).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveSetOperations.union].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveSetOperations<K, V>.unionAsFlow(key: K, otherKeys: Collection<K>): Flow<V> =
|
||||
union(key, otherKeys).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveSetOperations.union].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveSetOperations<K, V>.unionAsFlow(otherKeys: Collection<K>): Flow<V> =
|
||||
union(otherKeys).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveSetOperations.unionAndStore].
|
||||
*
|
||||
@@ -108,6 +181,36 @@ suspend fun <K : Any, V : Any> ReactiveSetOperations<K, V>.unionAndStoreAndAwait
|
||||
suspend fun <K : Any, V : Any> ReactiveSetOperations<K, V>.unionAndStoreAndAwait(keys: Collection<K>, destKey: K): Long =
|
||||
unionAndStore(keys, destKey).awaitSingle()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveSetOperations.difference].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveSetOperations<K, V>.differenceAsFlow(key: K, otherKey: K): Flow<V> =
|
||||
difference(key, otherKey).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveSetOperations.difference].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveSetOperations<K, V>.differenceAsFlow(key: K, otherKeys: Collection<K>): Flow<V> =
|
||||
difference(key, otherKeys).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveSetOperations.difference].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveSetOperations<K, V>.differenceAsFlow(otherKeys: Collection<K>): Flow<V> =
|
||||
difference(otherKeys).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveSetOperations.differenceAndStore].
|
||||
*
|
||||
@@ -126,6 +229,25 @@ suspend fun <K : Any, V : Any> ReactiveSetOperations<K, V>.differenceAndStoreAnd
|
||||
suspend fun <K : Any, V : Any> ReactiveSetOperations<K, V>.differenceAndStoreAndAwait(keys: Collection<K>, destKey: K): Long =
|
||||
differenceAndStore(keys, destKey).awaitSingle()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveSetOperations.members].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveSetOperations<K, V>.membersAsFlow(key: K): Flow<V> =
|
||||
members(key).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveHashOperations.scan].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveSetOperations<K, V>.scanAsFlow(key: K, options: ScanOptions = ScanOptions.NONE): Flow<V> =
|
||||
scan(key, options).asFlow()
|
||||
/**
|
||||
* Coroutines variant of [ReactiveSetOperations.randomMember].
|
||||
*
|
||||
@@ -135,6 +257,26 @@ suspend fun <K : Any, V : Any> ReactiveSetOperations<K, V>.differenceAndStoreAnd
|
||||
suspend fun <K : Any, V : Any> ReactiveSetOperations<K, V>.randomMemberAndAwait(key: K): V? =
|
||||
randomMember(key).awaitFirstOrNull()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveSetOperations.distinctRandomMembers].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveSetOperations<K, V>.distinctRandomMembersAsFlow(key: K, count: Long): Flow<V> =
|
||||
distinctRandomMembers(key, count).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveSetOperations.randomMembers].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveSetOperations<K, V>.randomMembersAsFlow(key: K, count: Long): Flow<V> =
|
||||
randomMembers(key, count).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveSetOperations.delete].
|
||||
*
|
||||
|
||||
@@ -15,7 +15,13 @@
|
||||
*/
|
||||
package org.springframework.data.redis.core
|
||||
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.reactive.asFlow
|
||||
import kotlinx.coroutines.reactive.asPublisher
|
||||
import kotlinx.coroutines.reactive.awaitSingle
|
||||
import org.springframework.data.domain.Range
|
||||
import org.springframework.data.redis.connection.RedisZSetCommands.*
|
||||
import org.springframework.data.redis.connection.stream.*
|
||||
|
||||
/**
|
||||
@@ -45,6 +51,16 @@ suspend fun <K : Any, HK : Any, HV : Any> ReactiveStreamOperations<K, HK, HV>.ac
|
||||
suspend fun <K : Any, HK : Any, HV : Any> ReactiveStreamOperations<K, HK, HV>.acknowledgeAndAwait(group: String, record: Record<K, *>): Long =
|
||||
acknowledge(group, record).awaitSingle()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveStreamOperations.add].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, HK : Any, HV : Any> ReactiveStreamOperations<K, HK, HV>.add(key: K, bodyFlow: Flow<Map<HK, HV>>): Flow<RecordId> =
|
||||
add(key, bodyFlow.asPublisher()).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveStreamOperations.add].
|
||||
*
|
||||
@@ -135,6 +151,128 @@ suspend fun <K : Any, HK : Any, HV : Any> ReactiveStreamOperations<K, HK, HV>.de
|
||||
suspend fun <K : Any, HK : Any, HV : Any> ReactiveStreamOperations<K, HK, HV>.sizeAndAwait(key: K): Long =
|
||||
size(key).awaitSingle()
|
||||
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveStreamOperations.range].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, HK : Any, HV : Any> ReactiveStreamOperations<K, HK, HV>.rangeAsFlow(key: K, range: Range<String>, limit: Limit = Limit.unlimited()): Flow<MapRecord<K, HK, HV>>
|
||||
= range(key, range, limit).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveStreamOperations.range].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
inline fun <K : Any, reified V : Any> ReactiveStreamOperations<K, *, *>.rangeWithTypeAsFlow(key: K, range: Range<String>, limit: Limit = Limit.unlimited()): Flow<ObjectRecord<K, V>>
|
||||
= range(V::class.java, key, range, limit).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveStreamOperations.read].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, HK : Any, HV : Any> ReactiveStreamOperations<K, HK, HV>.readAsFlow(vararg stream: StreamOffset<K>): Flow<MapRecord<K, HK, HV>> =
|
||||
read(*stream).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveStreamOperations.read].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, HK : Any, HV : Any> ReactiveStreamOperations<K, HK, HV>.readAsFlow(readOptions: StreamReadOptions, vararg stream: StreamOffset<K>): Flow<MapRecord<K, HK, HV>> =
|
||||
read(readOptions, *stream).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveStreamOperations.read].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
inline fun <K : Any, reified V : Any> ReactiveStreamOperations<K, *, *>.readWithTypeAsFlow(vararg stream: StreamOffset<K>): Flow<ObjectRecord<K, V>> =
|
||||
read(V::class.java, *stream).asFlow()
|
||||
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveStreamOperations.read].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
inline fun <K : Any, reified V : Any> ReactiveStreamOperations<K, *, *>.readWithTypeAsFlow(readOptions: StreamReadOptions, vararg stream: StreamOffset<K>): Flow<ObjectRecord<K, V>> =
|
||||
read(V::class.java, readOptions, *stream).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveStreamOperations.read].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, HK : Any, HV : Any> ReactiveStreamOperations<K, HK, HV>.readAsFlow(consumer: Consumer, vararg stream: StreamOffset<K>): Flow<MapRecord<K, HK, HV>> =
|
||||
read(consumer, *stream).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveStreamOperations.read].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, HK : Any, HV : Any> ReactiveStreamOperations<K, HK, HV>.readAsFlow(consumer: Consumer, readOptions: StreamReadOptions, vararg stream: StreamOffset<K>): Flow<MapRecord<K, HK, HV>> =
|
||||
read(consumer, readOptions, *stream).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveStreamOperations.read].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
inline fun <K : Any, reified V : Any> ReactiveStreamOperations<K, *, *>.readWithTypeAsFlow(consumer: Consumer, vararg stream: StreamOffset<K>): Flow<ObjectRecord<K, V>> =
|
||||
read(V::class.java, consumer, *stream).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveStreamOperations.read].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
inline fun <K : Any, reified V : Any> ReactiveStreamOperations<K, *, *>.readWithTypeAsFlow(consumer: Consumer, readOptions: StreamReadOptions, vararg stream: StreamOffset<K>): Flow<ObjectRecord<K, V>> =
|
||||
read(V::class.java, consumer, readOptions, *stream).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveStreamOperations.reverseRange].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, HK : Any, HV : Any> ReactiveStreamOperations<K, HK, HV>.reverseRangeAsFlow(key: K, range: Range<String>, limit: Limit = Limit.unlimited()): Flow<MapRecord<K, HK, HV>>
|
||||
= reverseRange(key, range, limit).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveStreamOperations.reverseRange].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
inline fun <K : Any, reified V : Any> ReactiveStreamOperations<K, *, *>.reverseRangeWithTypeAsFlow(key: K, range: Range<String>, limit: Limit = Limit.unlimited()): Flow<ObjectRecord<K, V>> =
|
||||
reverseRange(V::class.java, key, range, limit).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveStreamOperations.trim].
|
||||
*
|
||||
|
||||
@@ -15,10 +15,15 @@
|
||||
*/
|
||||
package org.springframework.data.redis.core
|
||||
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.reactive.asFlow
|
||||
import kotlinx.coroutines.reactive.awaitFirstOrNull
|
||||
import kotlinx.coroutines.reactive.awaitSingle
|
||||
import org.springframework.data.domain.Range
|
||||
import org.springframework.data.redis.connection.RedisZSetCommands
|
||||
import org.springframework.data.redis.connection.RedisZSetCommands.Limit
|
||||
import org.springframework.data.redis.core.ZSetOperations.*
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveZSetOperations.add].
|
||||
@@ -35,7 +40,7 @@ suspend fun <K : Any, V : Any> ReactiveZSetOperations<K, V>.addAndAwait(key: K,
|
||||
* @author Mark Paluch
|
||||
* @since 2.2
|
||||
*/
|
||||
suspend fun <K : Any, V : Any> ReactiveZSetOperations<K, V>.addAllAndAwait(key: K, values: Collection<ZSetOperations.TypedTuple<V>>): Long =
|
||||
suspend fun <K : Any, V : Any> ReactiveZSetOperations<K, V>.addAllAndAwait(key: K, values: Collection<TypedTuple<V>>): Long =
|
||||
addAll(key, values).awaitSingle()
|
||||
|
||||
/**
|
||||
@@ -74,6 +79,86 @@ suspend fun <K : Any, V : Any> ReactiveZSetOperations<K, V>.rankAndAwait(key: K,
|
||||
suspend fun <K : Any, V : Any> ReactiveZSetOperations<K, V>.reverseRankAndAwait(key: K, value: V): Long? =
|
||||
reverseRank(key, value).awaitFirstOrNull()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveZSetOperations.range].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveZSetOperations<K, V>.rangeAsFlow(key: K, range: Range<Long>): Flow<V> =
|
||||
range(key, range).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveZSetOperations.rangeWithScores].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveZSetOperations<K, V>.rangeWithScoresAsFlow(key: K, range: Range<Long>): Flow<TypedTuple<V>> =
|
||||
rangeWithScores(key, range).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveZSetOperations.rangeByScore].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveZSetOperations<K, V>.rangeByScoreAsFlow(key: K, range: Range<Double>, limit: Limit? = null): Flow<V> =
|
||||
(if (limit == null) rangeByScore(key, range) else rangeByScore(key, range, limit)).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveZSetOperations.rangeByScoreWithScores].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveZSetOperations<K, V>.rangeByScoreWithScoresAsFlow(key: K, range: Range<Double>, limit: Limit? = null): Flow<TypedTuple<V>> =
|
||||
(if (limit == null) rangeByScoreWithScores(key, range) else rangeByScoreWithScores(key, range, limit)).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveZSetOperations.reverseRange].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveZSetOperations<K, V>.reverseRangeAsFlow(key: K, range: Range<Long>): Flow<V> =
|
||||
reverseRange(key, range).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveZSetOperations.reverseRangeWithScores].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveZSetOperations<K, V>.reverseRangeWithScoresAsFlow(key: K, range: Range<Long>): Flow<TypedTuple<V>> =
|
||||
reverseRangeWithScores(key, range).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveZSetOperations.reverseRangeByScore].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveZSetOperations<K, V>.reverseRangeByScoreAsFlow(key: K, range: Range<Double>, limit: Limit? = null): Flow<V> =
|
||||
(if (limit == null) reverseRangeByScore(key, range) else reverseRangeByScore(key, range, limit)).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveZSetOperations.reverseRangeByScoreWithScores].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.2
|
||||
*/
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <K : Any, V : Any> ReactiveZSetOperations<K, V>.reverseRangeByScoreWithScoresAsFlow(key: K, range: Range<Double>, limit: Limit? = null): Flow<TypedTuple<V>> =
|
||||
(if (limit == null) reverseRangeByScoreWithScores(key, range) else reverseRangeByScoreWithScores(key, range, limit)).asFlow()
|
||||
|
||||
/**
|
||||
* Coroutines variant of [ReactiveZSetOperations.count].
|
||||
*
|
||||
|
||||
@@ -18,17 +18,26 @@ package org.springframework.data.redis.core
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
import org.reactivestreams.Publisher
|
||||
import org.springframework.data.geo.Circle
|
||||
import org.springframework.data.geo.Distance
|
||||
import org.springframework.data.geo.GeoResult
|
||||
import org.springframework.data.geo.Metrics
|
||||
import org.springframework.data.geo.Point
|
||||
import org.springframework.data.redis.connection.RedisGeoCommands
|
||||
import org.springframework.data.redis.connection.RedisGeoCommands.*
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
/**
|
||||
* Unit tests for [ReactiveGeoOperationsExtensions].
|
||||
* Unit tests for `ReactiveGeoOperationsExtensions`.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
@@ -54,14 +63,14 @@ class ReactiveGeoOperationsExtensionsUnitTests {
|
||||
fun addGeoLocation() {
|
||||
|
||||
val operations = mockk<ReactiveGeoOperations<String, String>>()
|
||||
every { operations.add(any(), any<RedisGeoCommands.GeoLocation<String>>()) } returns Mono.just(1)
|
||||
every { operations.add(any(), any<GeoLocation<String>>()) } returns Mono.just(1)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.addAndAwait("foo", RedisGeoCommands.GeoLocation("bar", Point(1.0, 2.0)))).isEqualTo(1)
|
||||
assertThat(operations.addAndAwait("foo", GeoLocation("bar", Point(1.0, 2.0)))).isEqualTo(1)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.add("foo", RedisGeoCommands.GeoLocation("bar", Point(1.0, 2.0)))
|
||||
operations.add("foo", GeoLocation("bar", Point(1.0, 2.0)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,14 +93,30 @@ class ReactiveGeoOperationsExtensionsUnitTests {
|
||||
fun addGeoLocationList() {
|
||||
|
||||
val operations = mockk<ReactiveGeoOperations<String, String>>()
|
||||
every { operations.add(any(), any<List<RedisGeoCommands.GeoLocation<String>>>()) } returns Mono.just(1)
|
||||
every { operations.add(any(), any<List<GeoLocation<String>>>()) } returns Mono.just(1)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.addAndAwait("foo", listOf(RedisGeoCommands.GeoLocation("bar", Point(1.0, 2.0))))).isEqualTo(1)
|
||||
assertThat(operations.addAndAwait("foo", listOf(GeoLocation("bar", Point(1.0, 2.0))))).isEqualTo(1)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.add("foo", listOf(RedisGeoCommands.GeoLocation("bar", Point(1.0, 2.0))))
|
||||
operations.add("foo", listOf(GeoLocation("bar", Point(1.0, 2.0))))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun addGeoLocationFlow() {
|
||||
val operations = mockk<ReactiveGeoOperations<String, String>>()
|
||||
every { operations.add(any(), any<Publisher<List<GeoLocation<String>>>>()) } returns Flux.just(1)
|
||||
val flow = flow { emit(listOf(GeoLocation("bar", Point(1.0, 2.0)))) }
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.add("foo", flow).toList()).contains(1)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.add("foo", any<Publisher<List<GeoLocation<String>>>>())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,6 +271,95 @@ class ReactiveGeoOperationsExtensionsUnitTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun radiusAsFlowCircle() {
|
||||
val operations = mockk<ReactiveGeoOperations<String, String>>()
|
||||
val result = GeoResult(GeoLocation("bar", Point(1.0, 2.0)), Distance(1.0))
|
||||
val circle = Circle(1.0, 2.0, 3.0)
|
||||
every { operations.radius(any(), any()) } returns Flux.just(result)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.radiusAsFlow("foo", circle).toList()).contains(result)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.radius("foo", circle)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun radiusAsFlowCircleAndArgs() {
|
||||
val operations = mockk<ReactiveGeoOperations<String, String>>()
|
||||
val result = GeoResult(GeoLocation("bar", Point(1.0, 2.0)), Distance(1.0))
|
||||
val circle = Circle(1.0, 2.0, 3.0)
|
||||
val args = GeoRadiusCommandArgs.newGeoRadiusArgs()
|
||||
every { operations.radius(any(), any(), args) } returns Flux.just(result)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.radiusAsFlow("foo", circle, args).toList()).contains(result)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.radius("foo", circle, args)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun radiusAsFlowMemberAndRadius() {
|
||||
val operations = mockk<ReactiveGeoOperations<String, String>>()
|
||||
val result = GeoResult(GeoLocation("bar", Point(1.0, 2.0)), Distance(1.0))
|
||||
|
||||
every { operations.radius(any(), any(), any<Double>()) } returns Flux.just(result)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.radiusAsFlow("foo", "bar", 1.0).toList()).contains(result)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.radius("foo", "bar", 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun radiusAsFlowDistance() {
|
||||
val operations = mockk<ReactiveGeoOperations<String, String>>()
|
||||
val result = GeoResult(GeoLocation("bar", Point(1.0, 2.0)), Distance(1.0))
|
||||
val distance = Distance(2.0)
|
||||
|
||||
every { operations.radius(any(), any(), any<Distance>()) } returns Flux.just(result)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.radiusAsFlow("foo", "bar", distance).toList()).contains(result)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.radius("foo", "bar", distance)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun radiusAsFlowDistanceAndArgs() {
|
||||
val operations = mockk<ReactiveGeoOperations<String, String>>()
|
||||
val result = GeoResult(GeoLocation("bar", Point(1.0, 2.0)), Distance(1.0))
|
||||
val distance = Distance(2.0)
|
||||
val args = GeoRadiusCommandArgs.newGeoRadiusArgs()
|
||||
|
||||
every { operations.radius(any(), any(), any(), any()) } returns Flux.just(result)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.radiusAsFlow("foo", "bar", distance, args).toList()).contains(result)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.radius("foo", "bar", distance, args)
|
||||
}
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-937
|
||||
fun remove() {
|
||||
|
||||
|
||||
@@ -18,13 +18,16 @@ package org.springframework.data.redis.core
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
/**
|
||||
* Unit tests for [ReactiveHashOperationsExtensions].
|
||||
* Unit tests for `ReactiveHashOperationsExtensions`.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
@@ -106,6 +109,21 @@ class ReactiveHashOperationsExtensionsUnitTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun keys() {
|
||||
val operations = mockk<ReactiveHashOperations<String, String, String>>()
|
||||
every { operations.keys(any()) } returns Flux.just("bar", "baz")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.keysAsFlow("foo").toList()).contains("bar", "baz")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.keys("foo")
|
||||
}
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-937
|
||||
fun incrementDouble() {
|
||||
|
||||
@@ -181,6 +199,56 @@ class ReactiveHashOperationsExtensionsUnitTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun values() {
|
||||
|
||||
val operations = mockk<ReactiveHashOperations<String, String, String>>()
|
||||
every { operations.values(any()) } returns Flux.just("bar", "baz")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.valuesAsFlow("foo").toList()).contains("bar","baz")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.values("foo")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun entries() {
|
||||
|
||||
val entry = java.util.AbstractMap.SimpleEntry("bar", "baz")
|
||||
val operations = mockk<ReactiveHashOperations<String, String, String>>()
|
||||
every { operations.entries(any()) } returns Flux.just(entry)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.entriesAsFlow("foo").toList()).contains(entry)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.entries("foo")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun scan() {
|
||||
|
||||
val entry = java.util.AbstractMap.SimpleEntry("bar", "baz")
|
||||
val operations = mockk<ReactiveHashOperations<String, String, String>>()
|
||||
every { operations.scan(any(), any()) } returns Flux.just(entry)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.scanAsFlow("foo").toList()).contains(entry)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.scan("foo", ScanOptions.NONE)
|
||||
}
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-937
|
||||
fun remove() {
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.junit.Test
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
/**
|
||||
* Unit tests for [ReactiveHyperLogLogOperationsExtensions]
|
||||
* Unit tests for `ReactiveHyperLogLogOperationsExtensions`
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
|
||||
@@ -18,19 +18,38 @@ package org.springframework.data.redis.core
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import java.time.Duration
|
||||
|
||||
/**
|
||||
* Unit tests for [ReactiveListOperationsExtensions]
|
||||
* Unit tests for `ReactiveListOperationsExtensions`
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class ReactiveListOperationsExtensionsUnitTests {
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun range() {
|
||||
|
||||
val operations = mockk<ReactiveListOperations<String, String>>()
|
||||
every { operations.range(any(), any(), any()) } returns Flux.just("foo", "bar")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.rangeAsFlow("foo", 2, 3).toList()).contains("foo", "bar")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.range("foo", 2, 3)
|
||||
}
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-937
|
||||
fun trim() {
|
||||
|
||||
|
||||
@@ -18,22 +18,83 @@ package org.springframework.data.redis.core
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
import org.springframework.data.redis.connection.DataType
|
||||
import org.springframework.data.redis.connection.ReactiveSubscription
|
||||
import org.springframework.data.redis.core.script.RedisScript
|
||||
import org.springframework.data.redis.listener.ChannelTopic
|
||||
import org.springframework.data.redis.serializer.RedisElementReader
|
||||
import org.springframework.data.redis.serializer.RedisElementWriter
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
|
||||
/**
|
||||
* Unit tests for [ReactiveRedisOperationsExtensions].
|
||||
* Unit tests for `ReactiveRedisOperationsExtensions`.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
class ReactiveRedisOperationsExtensionsUnitTests {
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `execute with calllback`() {
|
||||
|
||||
val operations = mockk<ReactiveRedisOperations<String, String>>()
|
||||
every { operations.execute(any<ReactiveRedisCallback<*>>()) } returns Flux.just("foo")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.executeAsFlow { flow { emit("foo")} }.toList()).contains("foo")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.execute(any<ReactiveRedisCallback<*>>())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `execute with script`() {
|
||||
|
||||
val script = RedisScript.of<String>("foo")
|
||||
val operations = mockk<ReactiveRedisOperations<String, String>>()
|
||||
every { operations.execute(any<RedisScript<*>>(), any(), any()) } returns Flux.just("foo")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.executeAsFlow(script).toList()).contains("foo")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.execute(script, any(), any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `execute with script, argsWriter and resultReader`() {
|
||||
|
||||
val script = RedisScript.of<String>("foo")
|
||||
val argsWriter = mockk<RedisElementWriter<Any>>(relaxed = true)
|
||||
val resultReader = mockk<RedisElementReader<String>>(relaxed = true)
|
||||
val operations = mockk<ReactiveRedisOperations<String, String>>()
|
||||
every { operations.execute(any<RedisScript<*>>(), any(), any(), any(), any()) } returns Flux.just("foo")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.executeAsFlow(script, argsWriter = argsWriter, resultReader = resultReader).toList()).contains("foo")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.execute(script, any(), any(), argsWriter, resultReader)
|
||||
}
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-937
|
||||
fun convertAndSend() {
|
||||
|
||||
@@ -49,6 +110,59 @@ class ReactiveRedisOperationsExtensionsUnitTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun listenToChannel() {
|
||||
|
||||
val message = ReactiveSubscription.ChannelMessage("a", "b")
|
||||
val operations = mockk<ReactiveRedisOperations<String, String>>()
|
||||
every { operations.listenToChannel(any(), any()) } returns Flux.just(message)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.listenToChannelAsFlow("foo", "bar").toList()).contains(message)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.listenToChannel("foo", "bar")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun listenToPattern() {
|
||||
|
||||
val message = ReactiveSubscription.ChannelMessage("a", "b")
|
||||
val operations = mockk<ReactiveRedisOperations<String, String>>()
|
||||
every { operations.listenToPattern(any(), any()) } returns Flux.just(message)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.listenToPatternAsFlow("foo", "bar").toList()).contains(message)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.listenToPattern("foo", "bar")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun listenTo() {
|
||||
|
||||
val topic1 = ChannelTopic.of("foo")
|
||||
val topic2 = ChannelTopic.of("bar")
|
||||
val message = ReactiveSubscription.ChannelMessage("a", "b")
|
||||
val operations = mockk<ReactiveRedisOperations<String, String>>()
|
||||
every { operations.listenTo(any(), any()) } returns Flux.just(message)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.listenToAsFlow(topic1, topic2).toList()).contains(message)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.listenTo(topic1, topic2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-937
|
||||
fun hasKey() {
|
||||
|
||||
@@ -79,6 +193,39 @@ class ReactiveRedisOperationsExtensionsUnitTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun keys() {
|
||||
|
||||
val operations = mockk<ReactiveRedisOperations<String, String>>()
|
||||
every { operations.keys(any()) } returns Flux.just("bar")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.keysAsFlow("foo").toList()).contains("bar")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.keys("foo")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun scan() {
|
||||
|
||||
val operations = mockk<ReactiveRedisOperations<String, String>>()
|
||||
every { operations.scan(ScanOptions.NONE) } returns Flux.just("foo")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.scanAsFlow().toList()).contains("foo")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.scan(ScanOptions.NONE)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test // DATAREDIS-937
|
||||
fun randomKey() {
|
||||
|
||||
|
||||
@@ -18,13 +18,16 @@ package org.springframework.data.redis.core
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
/**
|
||||
* Unit tests for [ReactiveSetOperationsExtensions].
|
||||
* Unit tests for `ReactiveSetOperationsExtensions`.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
@@ -76,6 +79,22 @@ class ReactiveSetOperationsExtensionsUnitTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `pop as Flow`() {
|
||||
|
||||
val operations = mockk<ReactiveSetOperations<String, String>>()
|
||||
every { operations.pop(any(), any()) } returns Flux.just("bar")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.popAsFlow("foo", 1).toList()).contains("bar")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.pop("foo", 1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-937
|
||||
fun `pop returning an empty Mono`() {
|
||||
|
||||
@@ -136,6 +155,51 @@ class ReactiveSetOperationsExtensionsUnitTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun intersect() {
|
||||
val operations = mockk<ReactiveSetOperations<String, String>>()
|
||||
every { operations.intersect("foo", "bar") } returns Flux.just("baz")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.intersectAsFlow("foo", "bar").toList()).contains("baz")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.intersect("foo", "bar")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `intersect with key and collection`() {
|
||||
val operations = mockk<ReactiveSetOperations<String, String>>()
|
||||
every { operations.intersect("foo", listOf("bar")) } returns Flux.just("baz")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.intersectAsFlow("foo", listOf("bar")).toList()).contains("baz")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.intersect("foo", listOf("bar"))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `intersect with collection`() {
|
||||
val operations = mockk<ReactiveSetOperations<String, String>>()
|
||||
every { operations.intersect(listOf("bar")) } returns Flux.just("baz")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.intersectAsFlow(listOf("bar")).toList()).contains("baz")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.intersect(listOf("bar"))
|
||||
}
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-937
|
||||
fun intersectAndStore() {
|
||||
|
||||
@@ -166,6 +230,51 @@ class ReactiveSetOperationsExtensionsUnitTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun union() {
|
||||
val operations = mockk<ReactiveSetOperations<String, String>>()
|
||||
every { operations.union("foo", "bar") } returns Flux.just("baz")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.unionAsFlow("foo", "bar").toList()).contains("baz")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.union("foo", "bar")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `union with key and collection`() {
|
||||
val operations = mockk<ReactiveSetOperations<String, String>>()
|
||||
every { operations.union("foo", listOf("bar")) } returns Flux.just("baz")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.unionAsFlow("foo", listOf("bar")).toList()).contains("baz")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.union("foo", listOf("bar"))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `union with collection`() {
|
||||
val operations = mockk<ReactiveSetOperations<String, String>>()
|
||||
every { operations.union(listOf("bar")) } returns Flux.just("baz")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.unionAsFlow(listOf("bar")).toList()).contains("baz")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.union(listOf("bar"))
|
||||
}
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-937
|
||||
fun unionAndStore() {
|
||||
|
||||
@@ -196,6 +305,51 @@ class ReactiveSetOperationsExtensionsUnitTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun difference() {
|
||||
val operations = mockk<ReactiveSetOperations<String, String>>()
|
||||
every { operations.difference("foo", "bar") } returns Flux.just("baz")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.differenceAsFlow("foo", "bar").toList()).contains("baz")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.difference("foo", "bar")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `difference with key and collection`() {
|
||||
val operations = mockk<ReactiveSetOperations<String, String>>()
|
||||
every { operations.difference("foo", listOf("bar")) } returns Flux.just("baz")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.differenceAsFlow("foo", listOf("bar")).toList()).contains("baz")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.difference("foo", listOf("bar"))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `difference with collection`() {
|
||||
val operations = mockk<ReactiveSetOperations<String, String>>()
|
||||
every { operations.difference(listOf("bar")) } returns Flux.just("baz")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.differenceAsFlow(listOf("bar")).toList()).contains("baz")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.difference(listOf("bar"))
|
||||
}
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-937
|
||||
fun differenceAndStore() {
|
||||
|
||||
@@ -226,6 +380,37 @@ class ReactiveSetOperationsExtensionsUnitTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun members() {
|
||||
val operations = mockk<ReactiveSetOperations<String, String>>()
|
||||
every { operations.members("foo") } returns Flux.just("baz")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.membersAsFlow("foo").toList()).contains("baz")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.members("foo")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun scan() {
|
||||
|
||||
val operations = mockk<ReactiveSetOperations<String, String>>()
|
||||
every { operations.scan(any(), any()) } returns Flux.just("bar")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.scanAsFlow("foo").toList()).contains("bar")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.scan("foo", ScanOptions.NONE)
|
||||
}
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-937
|
||||
fun randomMember() {
|
||||
|
||||
@@ -256,6 +441,38 @@ class ReactiveSetOperationsExtensionsUnitTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun distinctRandomMembers() {
|
||||
|
||||
val operations = mockk<ReactiveSetOperations<String, String>>()
|
||||
every { operations.distinctRandomMembers(any(), any()) } returns Flux.just("bar")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.distinctRandomMembersAsFlow("foo", 1).toList()).contains("bar")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.distinctRandomMembers("foo", 1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun randomMembers() {
|
||||
|
||||
val operations = mockk<ReactiveSetOperations<String, String>>()
|
||||
every { operations.randomMembers(any(), any()) } returns Flux.just("bar")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.randomMembersAsFlow("foo", 1).toList()).contains("bar")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.randomMembers("foo", 1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-937
|
||||
fun delete() {
|
||||
|
||||
|
||||
@@ -18,14 +18,21 @@ package org.springframework.data.redis.core
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
import org.reactivestreams.Publisher
|
||||
import org.springframework.data.domain.Range
|
||||
import org.springframework.data.redis.connection.RedisZSetCommands.Limit
|
||||
import org.springframework.data.redis.connection.stream.*
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
/**
|
||||
* Unit tests for [ReactiveStreamOperationsExtensions].
|
||||
* Unit tests for `ReactiveStreamOperationsExtensions`.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@@ -82,11 +89,11 @@ class ReactiveStreamOperationsExtensionsUnitTests {
|
||||
|
||||
val operations = mockk<ReactiveStreamOperations<String, String, String>>()
|
||||
val record = MapRecord.create("foo", mapOf("a" to "b"))
|
||||
val redordId = RecordId.of("0-0")
|
||||
every { operations.add(record) } returns Mono.just(redordId)
|
||||
val recordId = RecordId.of("0-0")
|
||||
every { operations.add(record) } returns Mono.just(recordId)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.addAndAwait(record)).isEqualTo(redordId)
|
||||
assertThat(operations.addAndAwait(record)).isEqualTo(recordId)
|
||||
}
|
||||
|
||||
verify {
|
||||
@@ -94,6 +101,26 @@ class ReactiveStreamOperationsExtensionsUnitTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `add as Flow`() {
|
||||
|
||||
val map = mapOf("a" to "b")
|
||||
val bodyPublisher = Mono.just(map)
|
||||
val operations = mockk<ReactiveStreamOperations<String, String, String>>()
|
||||
val recordId = RecordId.of("0-0")
|
||||
every { operations.add(any(), any<Publisher<Map<String, String>>>()) } returns Flux.just(recordId)
|
||||
|
||||
runBlocking {
|
||||
val bodyFlow = flow { emit(map) }
|
||||
assertThat(operations.add("foo", bodyFlow).toList()).contains(recordId)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.add("foo", any<Publisher<Map<String, String>>>())
|
||||
}
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-937
|
||||
fun addRecord() {
|
||||
|
||||
@@ -233,6 +260,230 @@ class ReactiveStreamOperationsExtensionsUnitTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun range() {
|
||||
|
||||
val record = MapRecord.create("foo", mapOf("a" to "b"))
|
||||
val range = Range.just("bar")
|
||||
val operations = mockk<ReactiveStreamOperations<String, String, String>>()
|
||||
every { operations.range(any(), any(), any()) } returns Flux.just(record)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.rangeAsFlow("foo", range).toList()).contains(record)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.range("foo", range, Limit.unlimited())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun rangeWithType() {
|
||||
|
||||
val record = ObjectRecord.create("a", "b")
|
||||
val range = Range.just("bar")
|
||||
val operations = mockk<ReactiveStreamOperations<String, String, String>>()
|
||||
every { operations.range(any<Class<*>>(), any(), any(), any()) } returns Flux.just(record)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.rangeWithTypeAsFlow<String, String>("foo", range).toList()).contains(record)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.range(String::class.java, "foo", range, Limit.unlimited())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `read with StreamOffset vararg`() {
|
||||
val offset1 = StreamOffset.create("foo", ReadOffset.lastConsumed())
|
||||
val offset2 = StreamOffset.create("bar", ReadOffset.lastConsumed())
|
||||
val record = MapRecord.create("foo", mapOf("a" to "b"))
|
||||
val operations = mockk<ReactiveStreamOperations<String, String, String>>()
|
||||
every { operations.read(offset1, offset2) } returns Flux.just(record)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.readAsFlow(offset1, offset2).toList()).contains(record)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.read(offset1, offset2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `read with options and StreamOffset vararg` () {
|
||||
val offset1 = StreamOffset.create("foo", ReadOffset.lastConsumed())
|
||||
val offset2 = StreamOffset.create("bar", ReadOffset.lastConsumed())
|
||||
val options = StreamReadOptions.empty()
|
||||
val record = MapRecord.create("foo", mapOf("a" to "b"))
|
||||
val operations = mockk<ReactiveStreamOperations<String, String, String>>()
|
||||
every { operations.read(options, offset1, offset2) } returns Flux.just(record)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.readAsFlow(options, offset1, offset2).toList()).contains(record)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.read(options, offset1, offset2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `read with type and StreamOffset vararg`() {
|
||||
val offset1 = StreamOffset.create("foo", ReadOffset.lastConsumed())
|
||||
val offset2 = StreamOffset.create("bar", ReadOffset.lastConsumed())
|
||||
val record = ObjectRecord.create("a", "b")
|
||||
val operations = mockk<ReactiveStreamOperations<String, String, String>>()
|
||||
every { operations.read(String::class.java, offset1, offset2) } returns Flux.just(record)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.readWithTypeAsFlow<String, String>(offset1, offset2).toList()).contains(record)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.read(String::class.java, offset1, offset2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `read with type, options and StreamOffset vararg` () {
|
||||
val offset1 = StreamOffset.create("foo", ReadOffset.lastConsumed())
|
||||
val offset2 = StreamOffset.create("bar", ReadOffset.lastConsumed())
|
||||
val options = StreamReadOptions.empty()
|
||||
val record = ObjectRecord.create("a", "b")
|
||||
val operations = mockk<ReactiveStreamOperations<String, String, String>>()
|
||||
every { operations.read(String::class.java, options, offset1, offset2) } returns Flux.just(record)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.readWithTypeAsFlow<String, String>(options, offset1, offset2).toList()).contains(record)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.read(String::class.java, options, offset1, offset2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `read with consumer and StreamOffset vararg`() {
|
||||
val consumer = Consumer.from("a", "b")
|
||||
val offset1 = StreamOffset.create("foo", ReadOffset.lastConsumed())
|
||||
val offset2 = StreamOffset.create("bar", ReadOffset.lastConsumed())
|
||||
val record = MapRecord.create("foo", mapOf("a" to "b"))
|
||||
val operations = mockk<ReactiveStreamOperations<String, String, String>>()
|
||||
every { operations.read(consumer, offset1, offset2) } returns Flux.just(record)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.readAsFlow(consumer, offset1, offset2).toList()).contains(record)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.read(consumer, offset1, offset2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `read with consumer, options and StreamOffset vararg`() {
|
||||
val consumer = Consumer.from("a", "b")
|
||||
val offset1 = StreamOffset.create("foo", ReadOffset.lastConsumed())
|
||||
val offset2 = StreamOffset.create("bar", ReadOffset.lastConsumed())
|
||||
val options = StreamReadOptions.empty()
|
||||
val record = MapRecord.create("foo", mapOf("a" to "b"))
|
||||
val operations = mockk<ReactiveStreamOperations<String, String, String>>()
|
||||
every { operations.read(consumer, options, offset1, offset2) } returns Flux.just(record)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.readAsFlow(consumer, options, offset1, offset2).toList()).contains(record)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.read(consumer, options, offset1, offset2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `read with type, consumer and StreamOffset vararg`() {
|
||||
val consumer = Consumer.from("a", "b")
|
||||
val offset1 = StreamOffset.create("foo", ReadOffset.lastConsumed())
|
||||
val offset2 = StreamOffset.create("bar", ReadOffset.lastConsumed())
|
||||
val record = ObjectRecord.create("a", "b")
|
||||
val operations = mockk<ReactiveStreamOperations<String, String, String>>()
|
||||
every { operations.read(String::class.java, consumer, offset1, offset2) } returns Flux.just(record)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.readWithTypeAsFlow<String, String>(consumer, offset1, offset2).toList()).contains(record)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.read(String::class.java, consumer, offset1, offset2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun `read with type, consumer, options and StreamOffset vararg`() {
|
||||
val consumer = Consumer.from("a", "b")
|
||||
val offset1 = StreamOffset.create("foo", ReadOffset.lastConsumed())
|
||||
val offset2 = StreamOffset.create("bar", ReadOffset.lastConsumed())
|
||||
val options = StreamReadOptions.empty()
|
||||
val record = ObjectRecord.create("a", "b")
|
||||
val operations = mockk<ReactiveStreamOperations<String, String, String>>()
|
||||
every { operations.read(String::class.java, consumer, options, offset1, offset2) } returns Flux.just(record)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.readWithTypeAsFlow<String, String>(consumer, options, offset1, offset2).toList()).contains(record)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.read(String::class.java, consumer, options, offset1, offset2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun reverseRange() {
|
||||
|
||||
val record = MapRecord.create("foo", mapOf("a" to "b"))
|
||||
val range = Range.just("bar")
|
||||
val operations = mockk<ReactiveStreamOperations<String, String, String>>()
|
||||
every { operations.reverseRange(any(), any(), any()) } returns Flux.just(record)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.reverseRangeAsFlow("foo", range).toList()).contains(record)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.reverseRange("foo", range, Limit.unlimited())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun reverseRangeWithType() {
|
||||
|
||||
val record = ObjectRecord.create("a", "b")
|
||||
val range = Range.just("bar")
|
||||
val operations = mockk<ReactiveStreamOperations<String, String, String>>()
|
||||
every { operations.reverseRange(any<Class<*>>(), any(), any(), any()) } returns Flux.just(record)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.reverseRangeWithTypeAsFlow<String, String>("foo", range).toList()).contains(record)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.reverseRange(String::class.java, "foo", range, Limit.unlimited())
|
||||
}
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-937
|
||||
fun trim() {
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import reactor.core.publisher.Mono
|
||||
import java.time.Duration
|
||||
|
||||
/**
|
||||
* Unit tests for [ReactiveValueOperationsExtensions].
|
||||
* Unit tests for `ReactiveValueOperationsExtensions`.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
|
||||
@@ -18,16 +18,20 @@ package org.springframework.data.redis.core
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
import org.springframework.data.domain.Range
|
||||
import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate
|
||||
import org.springframework.data.redis.connection.RedisZSetCommands.Weights
|
||||
import org.springframework.data.redis.core.ZSetOperations.*
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
/**
|
||||
* Unit tests for [ReactiveZSetOperationsExtensions].
|
||||
* Unit tests for `ReactiveZSetOperationsExtensions`.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
@@ -154,6 +158,146 @@ class ReactiveZSetOperationsExtensionsUnitTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun range() {
|
||||
|
||||
val range = Range.unbounded<Long>()
|
||||
val operations = mockk<ReactiveZSetOperations<String, String>>()
|
||||
every { operations.range(any(), any()) } returns Flux.just("bar")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.rangeAsFlow("foo", range).toList()).contains("bar")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.range("foo", range)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun rangeWithScores() {
|
||||
|
||||
val tuple = mockk<TypedTuple<String>>(relaxed = true)
|
||||
val range = Range.unbounded<Long>()
|
||||
val operations = mockk<ReactiveZSetOperations<String, String>>()
|
||||
every { operations.rangeWithScores(any(), any()) } returns Flux.just(tuple)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.rangeWithScoresAsFlow("foo", range).toList()).contains(tuple)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.rangeWithScores("foo", range)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun rangeByScore() {
|
||||
|
||||
val range = Range.unbounded<Double>()
|
||||
val operations = mockk<ReactiveZSetOperations<String, String>>()
|
||||
every { operations.rangeByScore(any(), any()) } returns Flux.just("bar")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.rangeByScoreAsFlow("foo", range).toList()).contains("bar")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.rangeByScore("foo", range)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun rangeByScoreWithScores() {
|
||||
|
||||
val tuple = mockk<TypedTuple<String>>(relaxed = true)
|
||||
val range = Range.unbounded<Double>()
|
||||
val operations = mockk<ReactiveZSetOperations<String, String>>()
|
||||
every { operations.rangeByScoreWithScores(any(), any()) } returns Flux.just(tuple)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.rangeByScoreWithScoresAsFlow("foo", range).toList()).contains(tuple)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.rangeByScoreWithScores("foo", range)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun reverseRange() {
|
||||
|
||||
val range = Range.unbounded<Long>()
|
||||
val operations = mockk<ReactiveZSetOperations<String, String>>()
|
||||
every { operations.reverseRange(any(), any()) } returns Flux.just("bar")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.reverseRangeAsFlow("foo", range).toList()).contains("bar")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.reverseRange("foo", range)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun reverseRangeWithScores() {
|
||||
|
||||
val tuple = mockk<TypedTuple<String>>(relaxed = true)
|
||||
val range = Range.unbounded<Long>()
|
||||
val operations = mockk<ReactiveZSetOperations<String, String>>()
|
||||
every { operations.reverseRangeWithScores(any(), any()) } returns Flux.just(tuple)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.reverseRangeWithScoresAsFlow("foo", range).toList()).contains(tuple)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.reverseRangeWithScores("foo", range)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun reverseRangeByScore() {
|
||||
|
||||
val range = Range.unbounded<Double>()
|
||||
val operations = mockk<ReactiveZSetOperations<String, String>>()
|
||||
every { operations.reverseRangeByScore(any(), any()) } returns Flux.just("bar")
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.reverseRangeByScoreAsFlow("foo", range).toList()).contains("bar")
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.reverseRangeByScore("foo", range)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
fun reverseRangeByScoreWithScores() {
|
||||
|
||||
val tuple = mockk<TypedTuple<String>>(relaxed = true)
|
||||
val range = Range.unbounded<Double>()
|
||||
val operations = mockk<ReactiveZSetOperations<String, String>>()
|
||||
every { operations.reverseRangeByScoreWithScores(any(), any()) } returns Flux.just(tuple)
|
||||
|
||||
runBlocking {
|
||||
assertThat(operations.reverseRangeByScoreWithScoresAsFlow("foo", range).toList()).contains(tuple)
|
||||
}
|
||||
|
||||
verify {
|
||||
operations.reverseRangeByScoreWithScores("foo", range)
|
||||
}
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-937
|
||||
fun count() {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user