From 4b7ca6d56585894d793ad2049414912369064af3 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 29 Jun 2022 19:29:38 +0600 Subject: [PATCH 1/6] start 0.11.10 --- CHANGELOG.md | 2 ++ gradle.properties | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 106b6be27f0..ace54eab52b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog +## 0.11.10 + ## 0.11.9 * `Versions` diff --git a/gradle.properties b/gradle.properties index a9641fc0848..368c2b7b56e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,5 +14,5 @@ crypto_js_version=4.1.1 # Project data group=dev.inmo -version=0.11.9 -android_code_version=133 +version=0.11.10 +android_code_version=134 From a548b009790c7cfb5eba3312a04d620a247234ed Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 29 Jun 2022 19:31:57 +0600 Subject: [PATCH 2/6] update repos cache --- CHANGELOG.md | 6 +++ .../micro_utils/repos/cache/CRUDCacheRepo.kt | 1 + .../inmo/micro_utils/repos/cache/KVCache.kt | 43 ++----------------- .../repos/cache/KeyValueCacheRepo.kt | 1 + .../repos/cache/KeyValuesCacheRepo.kt | 1 + .../micro_utils/repos/cache/cache/KVCache.kt | 6 +++ .../repos/cache/cache/SimpleKVCache.kt | 37 ++++++++++++++++ .../repos/cache/cache/UnlimitedKVCache.kt | 24 +++++++++++ 8 files changed, 80 insertions(+), 39 deletions(-) create mode 100644 repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/KVCache.kt create mode 100644 repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleKVCache.kt create mode 100644 repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/UnlimitedKVCache.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index ace54eab52b..2846dd6e09f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## 0.11.10 +* `Repos`: + * `Cache`: + * `KVCache` has been replaced to the package `dev.inmo.micro_utils.repos.cache` + * `SimpleKVCache` has been replaced to the package `dev.inmo.micro_utils.repos.cache` + * New `KVCache` - `UnlimitedKVCache` + ## 0.11.9 * `Versions` 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 13289e997e3..53812a575a7 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 @@ -1,6 +1,7 @@ package dev.inmo.micro_utils.repos.cache 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 diff --git a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KVCache.kt b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KVCache.kt index a7248352446..51f000ba299 100644 --- a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KVCache.kt +++ b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KVCache.kt @@ -1,41 +1,6 @@ package dev.inmo.micro_utils.repos.cache -import dev.inmo.micro_utils.repos.* -import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock - -interface KVCache : KeyValueRepo - -open class SimpleKVCache( - protected val cachedValuesCount: Int, - private val kvParent: KeyValueRepo = MapKeyValueRepo() -) : KVCache, KeyValueRepo by kvParent { - protected open val cacheStack = ArrayList(cachedValuesCount) - protected val syncMutex = Mutex() - - protected suspend fun makeUnset(toUnset: List) { - cacheStack.removeAll(toUnset) - kvParent.unset(toUnset) - } - - override suspend fun set(toSet: Map) { - syncMutex.withLock { - if (toSet.size > cachedValuesCount) { - cacheStack.clear() - - kvParent.unset(getAllWithNextPaging { kvParent.keys(it) }) - val keysToInclude = toSet.keys.drop(toSet.size - cachedValuesCount) - - cacheStack.addAll(keysToInclude) - kvParent.set(keysToInclude.associateWith { toSet.getValue(it) }) - } else { - makeUnset(cacheStack.take(toSet.size)) - } - } - } - - override suspend fun unset(toUnset: List) { - syncMutex.withLock { makeUnset(toUnset) } - } -} +@Deprecated("Replaced", ReplaceWith("KVCache", "dev.inmo.micro_utils.repos.cache.cache.KVCache")) +typealias KVCache = dev.inmo.micro_utils.repos.cache.cache.KVCache +@Deprecated("Replaced", ReplaceWith("SimpleKVCache", "dev.inmo.micro_utils.repos.cache.cache.SimpleKVCache")) +typealias SimpleKVCache = dev.inmo.micro_utils.repos.cache.cache.SimpleKVCache 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 79ae1392d1b..0f6569e83ef 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,6 +1,7 @@ package dev.inmo.micro_utils.repos.cache 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.* 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 1948279461c..cb16722f6d4 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 @@ -5,6 +5,7 @@ import dev.inmo.micro_utils.pagination.PaginationResult import dev.inmo.micro_utils.pagination.utils.paginate import dev.inmo.micro_utils.pagination.utils.reverse 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.* diff --git a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/KVCache.kt b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/KVCache.kt new file mode 100644 index 00000000000..04a4f2320f7 --- /dev/null +++ b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/KVCache.kt @@ -0,0 +1,6 @@ +package dev.inmo.micro_utils.repos.cache.cache + +import dev.inmo.micro_utils.repos.* + +interface KVCache : KeyValueRepo + diff --git a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleKVCache.kt b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleKVCache.kt new file mode 100644 index 00000000000..3469e4ccf5c --- /dev/null +++ b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleKVCache.kt @@ -0,0 +1,37 @@ +package dev.inmo.micro_utils.repos.cache.cache + +import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging +import dev.inmo.micro_utils.repos.* +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock + +open class SimpleKVCache( + protected val cachedValuesCount: Int, + private val kvParent: KeyValueRepo = MapKeyValueRepo() +) : KVCache, KeyValueRepo by kvParent { + protected open val cacheQueue = ArrayDeque(cachedValuesCount) + protected val syncMutex = Mutex() + + protected suspend fun makeUnset(toUnset: List) { + cacheQueue.removeAll(toUnset) + kvParent.unset(toUnset) + } + + override suspend fun set(toSet: Map) { + syncMutex.withLock { + for ((k, v) in toSet) { + if (cacheQueue.size >= cachedValuesCount) { + cacheQueue.removeFirstOrNull() ?.let { + kvParent.unset(it) + } + } + cacheQueue.addLast(k) + kvParent.set(k, v) + } + } + } + + override suspend fun unset(toUnset: List) { + syncMutex.withLock { makeUnset(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 new file mode 100644 index 00000000000..61e80524151 --- /dev/null +++ b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/UnlimitedKVCache.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 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) + } + } +} From 540d5cce7c042b104081c43a45eb1477a9dd1bb9 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 29 Jun 2022 19:43:58 +0600 Subject: [PATCH 3/6] start add full repos caches --- repos/cache/build.gradle | 2 +- .../repos/cache/full/FullCRUDCacheRepo.kt | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullCRUDCacheRepo.kt diff --git a/repos/cache/build.gradle b/repos/cache/build.gradle index e128b1e3cff..1ca610cbfdf 100644 --- a/repos/cache/build.gradle +++ b/repos/cache/build.gradle @@ -15,4 +15,4 @@ kotlin { } } } -} \ No newline at end of file +} 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 new file mode 100644 index 00000000000..0fa797917bc --- /dev/null +++ b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullCRUDCacheRepo.kt @@ -0,0 +1,41 @@ +package dev.inmo.micro_utils.repos.cache.full + +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.ReadCRUDCacheRepo +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 + + +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) + } + + override suspend fun count(): Long = kvCache.count() +} + +open class FullCRUDCacheRepo( + parentRepo: CRUDRepo, + kvCache: KVCache, + scope: CoroutineScope = CoroutineScope(Dispatchers.Default), + idGetter: (ObjectType) -> IdType +) : FullReadCRUDCacheRepo( + 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) +} From 0d0c16e16d8a12cb97dc01501c8b7ba742c93da1 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 29 Jun 2022 23:53:49 +0600 Subject: [PATCH 4/6] 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 From e55f60c30bf7caf995a834b42cf49b366f9798b2 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Thu, 30 Jun 2022 00:22:07 +0600 Subject: [PATCH 5/6] rename unlimited kv cache --- .../cache/{UnlimitedKVCache.kt => FullKVCache.kt} | 2 +- ...mpleUnlimitedKVCache.kt => SimpleFullKVCache.kt} | 4 ++-- .../repos/cache/full/FullCRUDCacheRepo.kt | 12 +++++------- .../repos/cache/full/FullKeyValueCacheRepo.kt | 12 ++++++------ .../repos/cache/full/FullKeyValuesCacheRepo.kt | 13 ++++++------- 5 files changed, 20 insertions(+), 23 deletions(-) rename repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/{UnlimitedKVCache.kt => FullKVCache.kt} (77%) rename repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/{SimpleUnlimitedKVCache.kt => SimpleFullKVCache.kt} (85%) 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/FullKVCache.kt similarity index 77% rename from repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/UnlimitedKVCache.kt rename to repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/FullKVCache.kt index e0eeeaf8958..73fec60cad8 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/FullKVCache.kt @@ -3,4 +3,4 @@ package dev.inmo.micro_utils.repos.cache.cache /** * This interface declares that current type of [KVCache] will contains all the data all the time of its life */ -interface UnlimitedKVCache : KVCache +interface FullKVCache : KVCache 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/SimpleFullKVCache.kt similarity index 85% rename from repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleUnlimitedKVCache.kt rename to repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleFullKVCache.kt index 2f7e9ab32c4..e15a860c27d 100644 --- 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/SimpleFullKVCache.kt @@ -5,9 +5,9 @@ import dev.inmo.micro_utils.repos.MapKeyValueRepo import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock -open class SimpleUnlimitedKVCache( +open class SimpleFullKVCache( private val kvParent: KeyValueRepo = MapKeyValueRepo() -) : UnlimitedKVCache, KeyValueRepo by kvParent { +) : FullKVCache, KeyValueRepo by kvParent { protected val syncMutex = Mutex() override suspend fun set(toSet: Map) { 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 67af0f3d43b..7a8a07a117b 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 @@ -6,22 +6,20 @@ 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.* -import dev.inmo.micro_utils.repos.cache.cache.KVCache -import dev.inmo.micro_utils.repos.cache.cache.UnlimitedKVCache +import dev.inmo.micro_utils.repos.cache.cache.FullKVCache import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.* open class FullReadCRUDCacheRepo( protected open val parentRepo: ReadCRUDRepo, - protected open val kvCache: UnlimitedKVCache, + protected open val kvCache: FullKVCache, protected open val idGetter: (ObjectType) -> IdType ) : ReadCRUDRepo { protected inline fun doOrTakeAndActualize( - action: UnlimitedKVCache.() -> Optional, + action: FullKVCache.() -> Optional, actionElse: ReadCRUDRepo.() -> T, - actualize: UnlimitedKVCache.(T) -> Unit + actualize: FullKVCache.(T) -> Unit ): T { kvCache.action().onPresented { return it @@ -67,7 +65,7 @@ open class FullReadCRUDCacheRepo( open class FullCRUDCacheRepo( override val parentRepo: CRUDRepo, - kvCache: UnlimitedKVCache, + kvCache: FullKVCache, scope: CoroutineScope = CoroutineScope(Dispatchers.Default), idGetter: (ObjectType) -> IdType ) : FullReadCRUDCacheRepo( 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 index cdcce23654d..5bdb8746ebe 100644 --- 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 @@ -4,7 +4,7 @@ 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.cache.cache.FullKVCache import dev.inmo.micro_utils.repos.pagination.getAll import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -12,12 +12,12 @@ import kotlinx.coroutines.flow.* open class FullReadKeyValueCacheRepo( protected open val parentRepo: ReadKeyValueRepo, - protected open val kvCache: UnlimitedKVCache, + protected open val kvCache: FullKVCache, ) : ReadKeyValueRepo { protected inline fun doOrTakeAndActualize( - action: UnlimitedKVCache.() -> Optional, + action: FullKVCache.() -> Optional, actionElse: ReadKeyValueRepo.() -> T, - actualize: UnlimitedKVCache.(T) -> Unit + actualize: FullKVCache.(T) -> Unit ): T { kvCache.action().onPresented { return it @@ -72,7 +72,7 @@ open class FullReadKeyValueCacheRepo( open class FullWriteKeyValueCacheRepo( protected open val parentRepo: WriteKeyValueRepo, - protected open val kvCache: UnlimitedKVCache, + protected open val kvCache: FullKVCache, scope: CoroutineScope = CoroutineScope(Dispatchers.Default) ) : WriteKeyValueRepo by parentRepo { protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, it.second) }.launchIn(scope) @@ -81,7 +81,7 @@ open class FullWriteKeyValueCacheRepo( open class FullKeyValueCacheRepo( parentRepo: KeyValueRepo, - kvCache: UnlimitedKVCache, + kvCache: FullKVCache, scope: CoroutineScope = CoroutineScope(Dispatchers.Default) ) : FullWriteKeyValueCacheRepo(parentRepo, kvCache, scope), KeyValueRepo, 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 index 19355ecc17a..311e4d40f1c 100644 --- 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 @@ -4,20 +4,19 @@ 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 dev.inmo.micro_utils.repos.cache.cache.FullKVCache 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>, + protected open val kvCache: FullKVCache>, ) : ReadKeyValuesRepo { protected inline fun doOrTakeAndActualize( - action: UnlimitedKVCache>.() -> Optional, + action: FullKVCache>.() -> Optional, actionElse: ReadKeyValuesRepo.() -> T, - actualize: UnlimitedKVCache>.(T) -> Unit + actualize: FullKVCache>.(T) -> Unit ): T { kvCache.action().onPresented { return it @@ -107,7 +106,7 @@ open class FullReadKeyValuesCacheRepo( open class FullWriteKeyValuesCacheRepo( protected open val parentRepo: WriteKeyValueRepo, - protected open val kvCache: UnlimitedKVCache, + protected open val kvCache: FullKVCache, scope: CoroutineScope = CoroutineScope(Dispatchers.Default) ) : WriteKeyValueRepo by parentRepo { protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, it.second) }.launchIn(scope) @@ -116,7 +115,7 @@ open class FullWriteKeyValuesCacheRepo( open class FullKeyValuesCacheRepo( parentRepo: KeyValueRepo, - kvCache: UnlimitedKVCache, + kvCache: FullKVCache, scope: CoroutineScope = CoroutineScope(Dispatchers.Default) ) : FullWriteKeyValueCacheRepo(parentRepo, kvCache, scope), KeyValueRepo, From 23bcb26a588033b355ddde2ae069dffc39ed6c97 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Thu, 30 Jun 2022 02:44:44 +0600 Subject: [PATCH 6/6] complete improvements in caches --- CHANGELOG.md | 4 +- .../micro_utils/repos/cache/CRUDCacheRepo.kt | 19 ++++++- .../repos/cache/KeyValueCacheRepo.kt | 9 ++++ .../repos/cache/KeyValuesCacheRepo.kt | 9 ++++ .../repos/cache/cache/FullKVCache.kt | 4 +- .../micro_utils/repos/cache/cache/KVCache.kt | 5 +- .../repos/cache/cache/SimpleFullKVCache.kt | 4 ++ .../repos/cache/cache/SimpleKVCache.kt | 5 ++ .../repos/cache/full/FullCRUDCacheRepo.kt | 21 ++++++-- .../repos/cache/full/FullKeyValueCacheRepo.kt | 14 +++++ .../cache/full/FullKeyValuesCacheRepo.kt | 54 ++++++++++++++----- 11 files changed, 127 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2846dd6e09f..ca0d593e9fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,9 @@ * `Cache`: * `KVCache` has been replaced to the package `dev.inmo.micro_utils.repos.cache` * `SimpleKVCache` has been replaced to the package `dev.inmo.micro_utils.repos.cache` - * New `KVCache` - `UnlimitedKVCache` + * New `KVCache` subtype - `FullKVCache` + * Add `Full*` variants of standard repos + * Add `cached`/`caching` (for write repos) extensions for all standard types of repos ## 0.11.9 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 d7d3fba658e..c4facb233f5 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 @@ -18,8 +18,13 @@ open class ReadCRUDCacheRepo( override suspend fun contains(id: IdType): Boolean = kvCache.contains(id) || parentRepo.contains(id) } +fun ReadCRUDRepo.cached( + kvCache: KVCache, + idGetter: (ObjectType) -> IdType +) = ReadCRUDCacheRepo(this, kvCache, idGetter) + open class WriteCRUDCacheRepo( - protected open val parentRepo: CRUDRepo, + protected open val parentRepo: WriteCRUDRepo, protected open val kvCache: KVCache, protected open val scope: CoroutineScope = CoroutineScope(Dispatchers.Default), protected open val idGetter: (ObjectType) -> IdType @@ -61,6 +66,12 @@ open class WriteCRUDCacheRepo( } } +fun WriteCRUDRepo.caching( + kvCache: KVCache, + scope: CoroutineScope, + idGetter: (ObjectType) -> IdType +) = WriteCRUDCacheRepo(this, kvCache, scope, idGetter) + open class CRUDCacheRepo( override val parentRepo: CRUDRepo, @@ -79,3 +90,9 @@ open class CRUDCacheRepo( idGetter ), CRUDRepo + +fun CRUDRepo.cached( + kvCache: KVCache, + scope: CoroutineScope, + idGetter: (ObjectType) -> IdType +) = CRUDCacheRepo(this, kvCache, scope, idGetter) 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 6123cd2b7ce..3e2265e4466 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 @@ -16,6 +16,10 @@ open class ReadKeyValueCacheRepo( override suspend fun contains(key: Key): Boolean = kvCache.contains(key) || parentRepo.contains(key) } +fun ReadKeyValueRepo.cached( + kvCache: KVCache +) = ReadKeyValueCacheRepo(this, kvCache) + open class KeyValueCacheRepo( parentRepo: KeyValueRepo, kvCache: KVCache, @@ -24,3 +28,8 @@ open class KeyValueCacheRepo( 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) } + +fun KeyValueRepo.cached( + kvCache: KVCache, + scope: CoroutineScope = CoroutineScope(Dispatchers.Default) +) = KeyValueCacheRepo(this, kvCache, scope) 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 e036b41b7ce..afe2d202d8c 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 @@ -30,6 +30,10 @@ open class ReadKeyValuesCacheRepo( override suspend fun contains(k: Key): Boolean = kvCache.contains(k) || parentRepo.contains(k) } +fun ReadKeyValuesRepo.cached( + kvCache: KVCache> +) = ReadKeyValuesCacheRepo(this, kvCache) + open class KeyValuesCacheRepo( parentRepo: KeyValuesRepo, kvCache: KVCache>, @@ -39,3 +43,8 @@ open class KeyValuesCacheRepo( protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.set(it.first, kvCache.get(it.first) ?.minus(it.second) ?: return@onEach) }.launchIn(scope) protected val onDataClearedJob = parentRepo.onDataCleared.onEach { kvCache.unset(it) }.launchIn(scope) } + +fun KeyValuesRepo.cached( + kvCache: KVCache>, + scope: CoroutineScope = CoroutineScope(Dispatchers.Default) +) = KeyValuesCacheRepo(this, kvCache, scope) diff --git a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/FullKVCache.kt b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/FullKVCache.kt index 73fec60cad8..961e687b260 100644 --- a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/FullKVCache.kt +++ b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/FullKVCache.kt @@ -3,4 +3,6 @@ package dev.inmo.micro_utils.repos.cache.cache /** * This interface declares that current type of [KVCache] will contains all the data all the time of its life */ -interface FullKVCache : KVCache +interface FullKVCache : KVCache { + companion object +} diff --git a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/KVCache.kt b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/KVCache.kt index 04a4f2320f7..4ab2c7563bc 100644 --- a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/KVCache.kt +++ b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/KVCache.kt @@ -2,5 +2,6 @@ package dev.inmo.micro_utils.repos.cache.cache import dev.inmo.micro_utils.repos.* -interface KVCache : KeyValueRepo - +interface KVCache : KeyValueRepo { + companion object +} diff --git a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleFullKVCache.kt b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleFullKVCache.kt index e15a860c27d..a5ee4639b3d 100644 --- a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleFullKVCache.kt +++ b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleFullKVCache.kt @@ -22,3 +22,7 @@ open class SimpleFullKVCache( } } } + +inline fun FullKVCache( + kvParent: KeyValueRepo = MapKeyValueRepo() +) = SimpleFullKVCache(kvParent) diff --git a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleKVCache.kt b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleKVCache.kt index 3469e4ccf5c..56fe1091383 100644 --- a/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleKVCache.kt +++ b/repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleKVCache.kt @@ -35,3 +35,8 @@ open class SimpleKVCache( syncMutex.withLock { makeUnset(toUnset) } } } + +inline fun KVCache( + cachedValuesCount: Int, + kvParent: KeyValueRepo = MapKeyValueRepo() +) = SimpleKVCache(cachedValuesCount, kvParent) 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 7a8a07a117b..f5a76e06b1d 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 @@ -7,10 +7,10 @@ import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging import dev.inmo.micro_utils.repos.* import dev.inmo.micro_utils.repos.cache.* import dev.inmo.micro_utils.repos.cache.cache.FullKVCache +import dev.inmo.micro_utils.repos.cache.cache.KVCache import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers - open class FullReadCRUDCacheRepo( protected open val parentRepo: ReadCRUDRepo, protected open val kvCache: FullKVCache, @@ -58,11 +58,18 @@ open class FullReadCRUDCacheRepo( { if (it) parentRepo.getById(id) ?.let { set(id, it) } } ) - override suspend fun getById(id: IdType): ObjectType? { - TODO("Not yet implemented") - } + override suspend fun getById(id: IdType): ObjectType? = doOrTakeAndActualize( + { get(id) ?.optional ?: Optional.absent() }, + { getById(id) }, + { it ?.let { set(idGetter(it), it) } } + ) } +fun ReadCRUDRepo.cached( + kvCache: FullKVCache, + idGetter: (ObjectType) -> IdType +) = FullReadCRUDCacheRepo(this, kvCache, idGetter) + open class FullCRUDCacheRepo( override val parentRepo: CRUDRepo, kvCache: FullKVCache, @@ -80,3 +87,9 @@ open class FullCRUDCacheRepo( idGetter ), CRUDRepo + +fun CRUDRepo.cached( + kvCache: FullKVCache, + scope: CoroutineScope = CoroutineScope(Dispatchers.Default), + idGetter: (ObjectType) -> IdType +) = FullCRUDCacheRepo(this, kvCache, scope, idGetter) 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 index 5bdb8746ebe..6e428846c25 100644 --- 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 @@ -70,6 +70,10 @@ open class FullReadKeyValueCacheRepo( ) } +fun ReadKeyValueRepo.cached( + kvCache: FullKVCache +) = FullReadKeyValueCacheRepo(this, kvCache) + open class FullWriteKeyValueCacheRepo( protected open val parentRepo: WriteKeyValueRepo, protected open val kvCache: FullKVCache, @@ -79,6 +83,11 @@ open class FullWriteKeyValueCacheRepo( protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.unset(it) }.launchIn(scope) } +fun WriteKeyValueRepo.caching( + kvCache: FullKVCache, + scope: CoroutineScope = CoroutineScope(Dispatchers.Default) +) = FullWriteKeyValueCacheRepo(this, kvCache, scope) + open class FullKeyValueCacheRepo( parentRepo: KeyValueRepo, kvCache: FullKVCache, @@ -88,3 +97,8 @@ open class FullKeyValueCacheRepo( ReadKeyValueRepo by FullReadKeyValueCacheRepo(parentRepo, kvCache) { override suspend fun unsetWithValues(toUnset: List) = parentRepo.unsetWithValues(toUnset) } + +fun KeyValueRepo.cached( + kvCache: FullKVCache, + scope: CoroutineScope = CoroutineScope(Dispatchers.Default) +) = FullKeyValueCacheRepo(this, kvCache, scope) 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 index 311e4d40f1c..014cde674e4 100644 --- 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 @@ -104,21 +104,51 @@ open class FullReadKeyValuesCacheRepo( } +fun ReadKeyValuesRepo.cached( + kvCache: FullKVCache> +) = FullReadKeyValuesCacheRepo(this, kvCache) + open class FullWriteKeyValuesCacheRepo( - protected open val parentRepo: WriteKeyValueRepo, - protected open val kvCache: FullKVCache, + protected open val parentRepo: WriteKeyValuesRepo, + protected open val kvCache: FullKVCache>, 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) +) : WriteKeyValuesRepo by parentRepo { + protected val onNewJob = parentRepo.onNewValue.onEach { + kvCache.set( + it.first, + kvCache.get(it.first) ?.plus(it.second) ?: listOf(it.second) + ) + }.launchIn(scope) + protected val onRemoveJob = parentRepo.onValueRemoved.onEach { + kvCache.set( + it.first, + kvCache.get(it.first) ?.minus(it.second) ?: return@onEach + ) + }.launchIn(scope) } -open class FullKeyValuesCacheRepo( - parentRepo: KeyValueRepo, - kvCache: FullKVCache, +fun WriteKeyValuesRepo.caching( + kvCache: FullKVCache>, scope: CoroutineScope = CoroutineScope(Dispatchers.Default) -) : FullWriteKeyValueCacheRepo(parentRepo, kvCache, scope), - KeyValueRepo, - ReadKeyValueRepo by FullReadKeyValueCacheRepo(parentRepo, kvCache) { - override suspend fun unsetWithValues(toUnset: List) = parentRepo.unsetWithValues(toUnset) +) = FullWriteKeyValuesCacheRepo(this, kvCache, scope) + +open class FullKeyValuesCacheRepo( + parentRepo: KeyValuesRepo, + kvCache: FullKVCache>, + scope: CoroutineScope = CoroutineScope(Dispatchers.Default) +) : FullWriteKeyValuesCacheRepo(parentRepo, kvCache, scope), + KeyValuesRepo, + ReadKeyValuesRepo by FullReadKeyValuesCacheRepo(parentRepo, kvCache) { + override suspend fun clearWithValue(v: Value) { + doAllWithCurrentPaging { + keys(v, it).also { + remove(it.results.associateWith { listOf(v) }) + } + } + } } + +fun KeyValuesRepo.caching( + kvCache: FullKVCache>, + scope: CoroutineScope = CoroutineScope(Dispatchers.Default) +) = FullKeyValuesCacheRepo(this, kvCache, scope)