From 0d0c16e16d8a12cb97dc01501c8b7ba742c93da1 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 29 Jun 2022 23:53:49 +0600 Subject: [PATCH] add full cache repos --- .../dev/inmo/micro_utils/common/Optional.kt | 7 + .../micro_utils/repos/cache/CRUDCacheRepo.kt | 68 ++++++++-- .../repos/cache/KeyValueCacheRepo.kt | 6 +- .../repos/cache/KeyValuesCacheRepo.kt | 4 +- .../cache/cache/SimpleUnlimitedKVCache.kt | 24 ++++ .../repos/cache/cache/UnlimitedKVCache.kt | 26 +--- .../repos/cache/full/FullCRUDCacheRepo.kt | 79 ++++++++--- .../repos/cache/full/FullKeyValueCacheRepo.kt | 90 +++++++++++++ .../cache/full/FullKeyValuesCacheRepo.kt | 125 ++++++++++++++++++ .../micro_utils/repos/StandartKeyValueRepo.kt | 4 + 10 files changed, 378 insertions(+), 55 deletions(-) create mode 100644 repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleUnlimitedKVCache.kt create mode 100644 repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullKeyValueCacheRepo.kt create mode 100644 repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullKeyValuesCacheRepo.kt diff --git a/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/Optional.kt b/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/Optional.kt index 0c3a67521d0..4cb3e2eefd6 100644 --- a/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/Optional.kt +++ b/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/Optional.kt @@ -41,6 +41,13 @@ data class Optional internal constructor( inline val T.optional get() = Optional.presented(this) +inline val T?.optionalOrAbsentIfNull + get() = if (this == null) { + Optional.absent() + } else { + Optional.presented(this) + } + /** * Will call [block] when data presented ([Optional.dataPresented] == true) */ diff --git a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/CRUDCacheRepo.kt b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/CRUDCacheRepo.kt index 53812a575a7..d7d3fba658e 100644 --- a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/CRUDCacheRepo.kt +++ b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/CRUDCacheRepo.kt @@ -4,13 +4,12 @@ import dev.inmo.micro_utils.repos.* import dev.inmo.micro_utils.repos.cache.cache.KVCache import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.* open class ReadCRUDCacheRepo( - protected val parentRepo: ReadCRUDRepo, - protected val kvCache: KVCache, - protected val idGetter: (ObjectType) -> IdType + protected open val parentRepo: ReadCRUDRepo, + protected open val kvCache: KVCache, + protected open val idGetter: (ObjectType) -> IdType ) : ReadCRUDRepo by parentRepo { override suspend fun getById(id: IdType): ObjectType? = kvCache.get(id) ?: (parentRepo.getById(id) ?.also { kvCache.set(id, it) @@ -19,8 +18,52 @@ open class ReadCRUDCacheRepo( override suspend fun contains(id: IdType): Boolean = kvCache.contains(id) || parentRepo.contains(id) } +open class WriteCRUDCacheRepo( + protected open val parentRepo: CRUDRepo, + protected open val kvCache: KVCache, + protected open val scope: CoroutineScope = CoroutineScope(Dispatchers.Default), + protected open val idGetter: (ObjectType) -> IdType +) : WriteCRUDRepo { + override val newObjectsFlow: Flow by parentRepo::newObjectsFlow + override val updatedObjectsFlow: Flow by parentRepo::updatedObjectsFlow + override val deletedObjectsIdsFlow: Flow by parentRepo::deletedObjectsIdsFlow + + val deletedObjectsFlowJob = parentRepo.deletedObjectsIdsFlow.onEach { + kvCache.unset(it) + }.launchIn(scope) + + override suspend fun deleteById(ids: List) = parentRepo.deleteById(ids) + + override suspend fun update(values: List>): List { + val updated = parentRepo.update(values) + + kvCache.unset(values.map { it.id }) + kvCache.set(updated.associateBy { idGetter(it) }) + + return updated + } + + override suspend fun update(id: IdType, value: InputValueType): ObjectType? { + return parentRepo.update(id, value) ?.also { + kvCache.unset(id) + kvCache.set(idGetter(it), it) + } + } + + override suspend fun create(values: List): List { + val created = parentRepo.create(values) + + kvCache.set( + created.associateBy { idGetter(it) } + ) + + return created + } +} + + open class CRUDCacheRepo( - parentRepo: CRUDRepo, + override val parentRepo: CRUDRepo, kvCache: KVCache, scope: CoroutineScope = CoroutineScope(Dispatchers.Default), idGetter: (ObjectType) -> IdType @@ -28,8 +71,11 @@ open class CRUDCacheRepo( parentRepo, kvCache, idGetter -), CRUDRepo, WriteCRUDRepo by parentRepo { - protected val onNewJob = parentRepo.newObjectsFlow.onEach { kvCache.set(idGetter(it), it) }.launchIn(scope) - protected val onUpdatedJob = parentRepo.updatedObjectsFlow.onEach { kvCache.set(idGetter(it), it) }.launchIn(scope) - protected val onRemoveJob = parentRepo.deletedObjectsIdsFlow.onEach { kvCache.unset(it) }.launchIn(scope) -} +), + WriteCRUDRepo by WriteCRUDCacheRepo( + parentRepo, + kvCache, + scope, + idGetter +), + CRUDRepo diff --git a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KeyValueCacheRepo.kt b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KeyValueCacheRepo.kt index 0f6569e83ef..6123cd2b7ce 100644 --- a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KeyValueCacheRepo.kt +++ b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KeyValueCacheRepo.kt @@ -1,5 +1,7 @@ package dev.inmo.micro_utils.repos.cache +import dev.inmo.micro_utils.pagination.Pagination +import dev.inmo.micro_utils.pagination.PaginationResult import dev.inmo.micro_utils.repos.* import dev.inmo.micro_utils.repos.cache.cache.KVCache import kotlinx.coroutines.CoroutineScope @@ -7,8 +9,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.* open class ReadKeyValueCacheRepo( - protected val parentRepo: ReadKeyValueRepo, - protected val kvCache: KVCache, + protected open val parentRepo: ReadKeyValueRepo, + protected open val kvCache: KVCache, ) : ReadKeyValueRepo by parentRepo { override suspend fun get(k: Key): Value? = kvCache.get(k) ?: parentRepo.get(k) ?.also { kvCache.set(k, it) } override suspend fun contains(key: Key): Boolean = kvCache.contains(key) || parentRepo.contains(key) diff --git a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KeyValuesCacheRepo.kt b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KeyValuesCacheRepo.kt index cb16722f6d4..e036b41b7ce 100644 --- a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KeyValuesCacheRepo.kt +++ b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KeyValuesCacheRepo.kt @@ -11,8 +11,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.* open class ReadKeyValuesCacheRepo( - protected val parentRepo: ReadKeyValuesRepo, - protected val kvCache: KVCache> + protected open val parentRepo: ReadKeyValuesRepo, + protected open val kvCache: KVCache> ) : ReadKeyValuesRepo by parentRepo { override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult { return kvCache.get(k) ?.paginate( diff --git a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleUnlimitedKVCache.kt b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleUnlimitedKVCache.kt new file mode 100644 index 00000000000..2f7e9ab32c4 --- /dev/null +++ b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleUnlimitedKVCache.kt @@ -0,0 +1,24 @@ +package dev.inmo.micro_utils.repos.cache.cache + +import dev.inmo.micro_utils.repos.KeyValueRepo +import dev.inmo.micro_utils.repos.MapKeyValueRepo +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock + +open class SimpleUnlimitedKVCache( + private val kvParent: KeyValueRepo = MapKeyValueRepo() +) : UnlimitedKVCache, KeyValueRepo by kvParent { + protected val syncMutex = Mutex() + + override suspend fun set(toSet: Map) { + syncMutex.withLock { + kvParent.set(toSet) + } + } + + override suspend fun unset(toUnset: List) { + syncMutex.withLock { + kvParent.unset(toUnset) + } + } +} diff --git a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/UnlimitedKVCache.kt b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/UnlimitedKVCache.kt index 61e80524151..e0eeeaf8958 100644 --- a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/UnlimitedKVCache.kt +++ b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/UnlimitedKVCache.kt @@ -1,24 +1,6 @@ package dev.inmo.micro_utils.repos.cache.cache -import dev.inmo.micro_utils.repos.KeyValueRepo -import dev.inmo.micro_utils.repos.MapKeyValueRepo -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock - -open class UnlimitedKVCache( - private val kvParent: KeyValueRepo = MapKeyValueRepo() -) : KVCache, KeyValueRepo by kvParent { - protected val syncMutex = Mutex() - - override suspend fun set(toSet: Map) { - syncMutex.withLock { - kvParent.set(toSet) - } - } - - override suspend fun unset(toUnset: List) { - syncMutex.withLock { - kvParent.unset(toUnset) - } - } -} +/** + * This interface declares that current type of [KVCache] will contains all the data all the time of its life + */ +interface UnlimitedKVCache : KVCache diff --git a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullCRUDCacheRepo.kt b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullCRUDCacheRepo.kt index 0fa797917bc..67af0f3d43b 100644 --- a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullCRUDCacheRepo.kt +++ b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullCRUDCacheRepo.kt @@ -1,31 +1,73 @@ package dev.inmo.micro_utils.repos.cache.full +import dev.inmo.micro_utils.common.* import dev.inmo.micro_utils.pagination.Pagination import dev.inmo.micro_utils.pagination.PaginationResult +import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging import dev.inmo.micro_utils.repos.* -import dev.inmo.micro_utils.repos.cache.ReadCRUDCacheRepo +import dev.inmo.micro_utils.repos.cache.* import dev.inmo.micro_utils.repos.cache.cache.KVCache +import dev.inmo.micro_utils.repos.cache.cache.UnlimitedKVCache import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.* open class FullReadCRUDCacheRepo( - parentRepo: ReadCRUDRepo, - kvCache: KVCache, - idGetter: (ObjectType) -> IdType -) : ReadCRUDRepo, ReadCRUDCacheRepo(parentRepo, kvCache, idGetter) { - override suspend fun getByPagination(pagination: Pagination): PaginationResult { - return kvCache.values(pagination) + protected open val parentRepo: ReadCRUDRepo, + protected open val kvCache: UnlimitedKVCache, + protected open val idGetter: (ObjectType) -> IdType +) : ReadCRUDRepo { + protected inline fun doOrTakeAndActualize( + action: UnlimitedKVCache.() -> Optional, + actionElse: ReadCRUDRepo.() -> T, + actualize: UnlimitedKVCache.(T) -> Unit + ): T { + kvCache.action().onPresented { + return it + }.onAbsent { + return parentRepo.actionElse().also { + kvCache.actualize(it) + } + } + error("The result should be returned above") } - override suspend fun count(): Long = kvCache.count() + protected suspend fun actualizeAll() { + kvCache.clear() + doForAllWithNextPaging { + parentRepo.getByPagination(it).also { + kvCache.set(it.results.associateBy { idGetter(it) }) + } + } + } + + override suspend fun getByPagination(pagination: Pagination): PaginationResult = doOrTakeAndActualize( + { values(pagination).takeIf { it.results.isNotEmpty() }.optionalOrAbsentIfNull }, + { getByPagination(pagination) }, + { if (it.results.isNotEmpty()) actualizeAll() } + ) + + override suspend fun count(): Long = doOrTakeAndActualize( + { count().takeIf { it != 0L }.optionalOrAbsentIfNull }, + { count() }, + { if (it != 0L) actualizeAll() } + ) + + override suspend fun contains(id: IdType): Boolean = doOrTakeAndActualize( + { contains(id).takeIf { it }.optionalOrAbsentIfNull }, + { contains(id) }, + { if (it) parentRepo.getById(id) ?.let { set(id, it) } } + ) + + override suspend fun getById(id: IdType): ObjectType? { + TODO("Not yet implemented") + } } open class FullCRUDCacheRepo( - parentRepo: CRUDRepo, - kvCache: KVCache, + override val parentRepo: CRUDRepo, + kvCache: UnlimitedKVCache, scope: CoroutineScope = CoroutineScope(Dispatchers.Default), idGetter: (ObjectType) -> IdType ) : FullReadCRUDCacheRepo( @@ -33,9 +75,10 @@ open class FullCRUDCacheRepo( kvCache, idGetter ), - CRUDRepo, - WriteCRUDRepo by parentRepo { - protected val onNewJob = parentRepo.newObjectsFlow.onEach { kvCache.set(idGetter(it), it) }.launchIn(scope) - protected val onUpdatedJob = parentRepo.updatedObjectsFlow.onEach { kvCache.set(idGetter(it), it) }.launchIn(scope) - protected val onRemoveJob = parentRepo.deletedObjectsIdsFlow.onEach { kvCache.unset(it) }.launchIn(scope) -} + WriteCRUDRepo by WriteCRUDCacheRepo( + parentRepo, + kvCache, + scope, + idGetter + ), + CRUDRepo diff --git a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullKeyValueCacheRepo.kt b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullKeyValueCacheRepo.kt new file mode 100644 index 00000000000..cdcce23654d --- /dev/null +++ b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullKeyValueCacheRepo.kt @@ -0,0 +1,90 @@ +package dev.inmo.micro_utils.repos.cache.full + +import dev.inmo.micro_utils.common.* +import dev.inmo.micro_utils.pagination.Pagination +import dev.inmo.micro_utils.pagination.PaginationResult +import dev.inmo.micro_utils.repos.* +import dev.inmo.micro_utils.repos.cache.cache.UnlimitedKVCache +import dev.inmo.micro_utils.repos.pagination.getAll +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.* + +open class FullReadKeyValueCacheRepo( + protected open val parentRepo: ReadKeyValueRepo, + protected open val kvCache: UnlimitedKVCache, +) : ReadKeyValueRepo { + protected inline fun doOrTakeAndActualize( + action: UnlimitedKVCache.() -> Optional, + actionElse: ReadKeyValueRepo.() -> T, + actualize: UnlimitedKVCache.(T) -> Unit + ): T { + kvCache.action().onPresented { + return it + }.onAbsent { + return parentRepo.actionElse().also { + kvCache.actualize(it) + } + } + error("The result should be returned above") + } + protected suspend fun actualizeAll() { + kvCache.clear() + kvCache.set(parentRepo.getAll { keys(it) }.toMap()) + } + + override suspend fun get(k: Key): Value? = doOrTakeAndActualize( + { get(k) ?.optional ?: Optional.absent() }, + { get(k) }, + { set(k, it ?: return@doOrTakeAndActualize) } + ) + + override suspend fun values(pagination: Pagination, reversed: Boolean): PaginationResult = doOrTakeAndActualize( + { values(pagination, reversed).takeIf { it.results.isNotEmpty() }.optionalOrAbsentIfNull }, + { values(pagination, reversed) }, + { if (it.results.isNotEmpty()) actualizeAll() } + ) + + override suspend fun count(): Long = doOrTakeAndActualize( + { count().takeIf { it != 0L }.optionalOrAbsentIfNull }, + { count() }, + { if (it != 0L) actualizeAll() } + ) + + override suspend fun contains(key: Key): Boolean = doOrTakeAndActualize( + { contains(key).takeIf { it }.optionalOrAbsentIfNull }, + { contains(key) }, + { if (it) parentRepo.get(key) ?.also { kvCache.set(key, it) } } + ) + + override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult = doOrTakeAndActualize( + { keys(pagination, reversed).takeIf { it.results.isNotEmpty() }.optionalOrAbsentIfNull }, + { keys(pagination, reversed) }, + { if (it.results.isNotEmpty()) actualizeAll() } + ) + + override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult = doOrTakeAndActualize( + { keys(v, pagination, reversed).takeIf { it.results.isNotEmpty() }.optionalOrAbsentIfNull }, + { parentRepo.keys(v, pagination, reversed) }, + { if (it.results.isNotEmpty()) actualizeAll() } + ) +} + +open class FullWriteKeyValueCacheRepo( + protected open val parentRepo: WriteKeyValueRepo, + protected open val kvCache: UnlimitedKVCache, + scope: CoroutineScope = CoroutineScope(Dispatchers.Default) +) : WriteKeyValueRepo by parentRepo { + protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, it.second) }.launchIn(scope) + protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.unset(it) }.launchIn(scope) +} + +open class FullKeyValueCacheRepo( + parentRepo: KeyValueRepo, + kvCache: UnlimitedKVCache, + scope: CoroutineScope = CoroutineScope(Dispatchers.Default) +) : FullWriteKeyValueCacheRepo(parentRepo, kvCache, scope), + KeyValueRepo, + ReadKeyValueRepo by FullReadKeyValueCacheRepo(parentRepo, kvCache) { + override suspend fun unsetWithValues(toUnset: List) = parentRepo.unsetWithValues(toUnset) +} diff --git a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullKeyValuesCacheRepo.kt b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullKeyValuesCacheRepo.kt new file mode 100644 index 00000000000..19355ecc17a --- /dev/null +++ b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullKeyValuesCacheRepo.kt @@ -0,0 +1,125 @@ +package dev.inmo.micro_utils.repos.cache.full + +import dev.inmo.micro_utils.common.* +import dev.inmo.micro_utils.pagination.* +import dev.inmo.micro_utils.pagination.utils.* +import dev.inmo.micro_utils.repos.* +import dev.inmo.micro_utils.repos.cache.cache.UnlimitedKVCache +import dev.inmo.micro_utils.repos.pagination.getAll +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.* + +open class FullReadKeyValuesCacheRepo( + protected open val parentRepo: ReadKeyValuesRepo, + protected open val kvCache: UnlimitedKVCache>, +) : ReadKeyValuesRepo { + protected inline fun doOrTakeAndActualize( + action: UnlimitedKVCache>.() -> Optional, + actionElse: ReadKeyValuesRepo.() -> T, + actualize: UnlimitedKVCache>.(T) -> Unit + ): T { + kvCache.action().onPresented { + return it + }.onAbsent { + return parentRepo.actionElse().also { + kvCache.actualize(it) + } + } + error("The result should be returned above") + } + + protected suspend fun actualizeKey(k: Key) { + kvCache.set(k, parentRepo.getAll(k)) + } + + protected suspend fun actualizeAll() { + doAllWithCurrentPaging { kvCache.keys(it).also { kvCache.unset(it.results) } } + kvCache.set(parentRepo.getAll()) + } + + override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult { + return doOrTakeAndActualize( + { + get(k) ?.paginate( + pagination.let { if (reversed) it.reverse(count(k)) else it } + ) ?.let { + if (reversed) it.copy(results = it.results.reversed()) else it + }.optionalOrAbsentIfNull + }, + { get(k, pagination, reversed) }, + { actualizeKey(k) } + ) + } + + override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult { + return doOrTakeAndActualize( + { + kvCache.keys(pagination, reversed).takeIf { it.results.isNotEmpty() }.optionalOrAbsentIfNull + }, + { parentRepo.keys(pagination, reversed) }, + { actualizeAll() } + ) + } + + override suspend fun count(): Long = doOrTakeAndActualize( + { count().takeIf { it != 0L }.optionalOrAbsentIfNull }, + { count() }, + { if (it != 0L) actualizeAll() } + ) + + override suspend fun count(k: Key): Long = doOrTakeAndActualize( + { count().takeIf { it != 0L }.optionalOrAbsentIfNull }, + { count() }, + { if (it != 0L) actualizeKey(k) } + ) + + override suspend fun contains(k: Key, v: Value): Boolean = doOrTakeAndActualize( + { get(k) ?.contains(v).takeIf { it == true }.optionalOrAbsentIfNull }, + { contains(k, v) }, + { if (it) actualizeKey(k) } + ) + + override suspend fun contains(k: Key): Boolean = doOrTakeAndActualize( + { contains(k).takeIf { it }.optionalOrAbsentIfNull }, + { contains(k) }, + { if (it) actualizeKey(k) } + ) + + override suspend fun keys( + v: Value, + pagination: Pagination, + reversed: Boolean + ): PaginationResult = doOrTakeAndActualize( + { + val keys = getAllWithNextPaging { keys(it) }.filter { get(it) ?.contains(v) == true }.optionallyReverse(reversed) + if (keys.isNotEmpty()) { + keys.paginate(pagination.optionallyReverse(keys.size, reversed)).takeIf { it.results.isNotEmpty() }.optionalOrAbsentIfNull + } else { + Optional.absent() + } + }, + { parentRepo.keys(v, pagination, reversed) }, + { if (it.results.isNotEmpty()) actualizeAll() } + ) + +} + +open class FullWriteKeyValuesCacheRepo( + protected open val parentRepo: WriteKeyValueRepo, + protected open val kvCache: UnlimitedKVCache, + scope: CoroutineScope = CoroutineScope(Dispatchers.Default) +) : WriteKeyValueRepo by parentRepo { + protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, it.second) }.launchIn(scope) + protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.unset(it) }.launchIn(scope) +} + +open class FullKeyValuesCacheRepo( + parentRepo: KeyValueRepo, + kvCache: UnlimitedKVCache, + scope: CoroutineScope = CoroutineScope(Dispatchers.Default) +) : FullWriteKeyValueCacheRepo(parentRepo, kvCache, scope), + KeyValueRepo, + ReadKeyValueRepo by FullReadKeyValueCacheRepo(parentRepo, kvCache) { + override suspend fun unsetWithValues(toUnset: List) = parentRepo.unsetWithValues(toUnset) +} diff --git a/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/StandartKeyValueRepo.kt b/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/StandartKeyValueRepo.kt index 8ffe9094719..7a418269693 100644 --- a/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/StandartKeyValueRepo.kt +++ b/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/StandartKeyValueRepo.kt @@ -48,6 +48,10 @@ interface KeyValueRepo : ReadKeyValueRepo, WriteKeyValue } } } + + suspend fun clear() { + doAllWithCurrentPaging { keys(it).also { unset(it.results) } } + } } typealias StandardKeyValueRepo = KeyValueRepo