mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2024-11-23 10:38:44 +00:00
add FullKeyValuesCacheRepoTests and small rewrite of MapWriteKeyValuesRepo.set(Map<Key, List<Value>>) function
This commit is contained in:
parent
63e8b672c5
commit
8b439724e2
@ -154,6 +154,28 @@ open class FullKeyValueCacheRepo<Key,Value>(
|
|||||||
parentRepo.clear()
|
parentRepo.clear()
|
||||||
kvCache.clear()
|
kvCache.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun set(toSet: Map<Key, Value>) {
|
||||||
|
locker.withWriteLock {
|
||||||
|
super.set(toSet)
|
||||||
|
kvCache.set(
|
||||||
|
toSet.filter {
|
||||||
|
parentRepo.contains(it.key)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun unset(toUnset: List<Key>) {
|
||||||
|
locker.withWriteLock {
|
||||||
|
super.unset(toUnset)
|
||||||
|
kvCache.unset(
|
||||||
|
toUnset.filter {
|
||||||
|
!parentRepo.contains(it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <Key, Value> KeyValueRepo<Key, Value>.fullyCached(
|
fun <Key, Value> KeyValueRepo<Key, Value>.fullyCached(
|
||||||
|
@ -65,6 +65,42 @@ open class FullReadKeyValuesCacheRepo<Key,Value>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getAll(k: Key, reversed: Boolean): List<Value> {
|
||||||
|
return doOrTakeAndActualizeWithWriteLock(
|
||||||
|
{
|
||||||
|
get(k) ?.optionallyReverse(reversed).optionalOrAbsentIfNull
|
||||||
|
},
|
||||||
|
{ getAll(k, reversed) },
|
||||||
|
{ kvCache.set(k, it.optionallyReverse(reversed)) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getAll(reverseLists: Boolean): Map<Key, List<Value>> {
|
||||||
|
return doOrTakeAndActualizeWithWriteLock(
|
||||||
|
{
|
||||||
|
getAll().takeIf { it.isNotEmpty() } ?.let {
|
||||||
|
if (reverseLists) {
|
||||||
|
it.mapValues { it.value.reversed() }
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}.optionalOrAbsentIfNull
|
||||||
|
},
|
||||||
|
{ getAll(reverseLists) },
|
||||||
|
{
|
||||||
|
kvCache.set(
|
||||||
|
it.let {
|
||||||
|
if (reverseLists) {
|
||||||
|
it.mapValues { it.value.reversed() }
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> {
|
override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> {
|
||||||
return doOrTakeAndActualize(
|
return doOrTakeAndActualize(
|
||||||
{
|
{
|
||||||
@ -163,14 +199,15 @@ fun <Key, Value> WriteKeyValuesRepo<Key, Value>.caching(
|
|||||||
) = FullWriteKeyValuesCacheRepo(this, kvCache, scope, locker)
|
) = FullWriteKeyValuesCacheRepo(this, kvCache, scope, locker)
|
||||||
|
|
||||||
open class FullKeyValuesCacheRepo<Key,Value>(
|
open class FullKeyValuesCacheRepo<Key,Value>(
|
||||||
protected open val parentRepo: KeyValuesRepo<Key, Value>,
|
override val parentRepo: KeyValuesRepo<Key, Value>,
|
||||||
kvCache: KeyValueRepo<Key, List<Value>>,
|
kvCache: KeyValueRepo<Key, List<Value>>,
|
||||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||||
skipStartInvalidate: Boolean = false,
|
skipStartInvalidate: Boolean = false,
|
||||||
locker: SmartRWLocker = SmartRWLocker(),
|
locker: SmartRWLocker = SmartRWLocker(),
|
||||||
) : FullWriteKeyValuesCacheRepo<Key, Value>(parentRepo, kvCache, scope, locker),
|
) : //FullWriteKeyValuesCacheRepo<Key, Value>(parentRepo, kvCache, scope, locker),
|
||||||
KeyValuesRepo<Key, Value>,
|
KeyValuesRepo<Key, Value>,
|
||||||
ReadKeyValuesRepo<Key, Value> by FullReadKeyValuesCacheRepo(parentRepo, kvCache, locker) {
|
FullReadKeyValuesCacheRepo<Key, Value>(parentRepo, kvCache, locker),
|
||||||
|
WriteKeyValuesRepo<Key, Value> by parentRepo {
|
||||||
init {
|
init {
|
||||||
if (!skipStartInvalidate) {
|
if (!skipStartInvalidate) {
|
||||||
scope.launchSafelyWithoutExceptions { invalidate() }
|
scope.launchSafelyWithoutExceptions { invalidate() }
|
||||||
@ -190,11 +227,63 @@ open class FullKeyValuesCacheRepo<Key,Value>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun set(toSet: Map<Key, List<Value>>) {
|
override suspend fun set(toSet: Map<Key, List<Value>>) {
|
||||||
super<KeyValuesRepo>.set(toSet)
|
locker.withWriteLock {
|
||||||
|
parentRepo.set(toSet)
|
||||||
|
kvCache.set(
|
||||||
|
toSet.filter {
|
||||||
|
parentRepo.contains(it.key)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun removeWithValue(v: Value) {
|
override suspend fun add(toAdd: Map<Key, List<Value>>) {
|
||||||
super<FullWriteKeyValuesCacheRepo>.removeWithValue(v)
|
locker.withWriteLock {
|
||||||
|
parentRepo.add(toAdd)
|
||||||
|
toAdd.forEach {
|
||||||
|
val filtered = it.value.filter { v ->
|
||||||
|
parentRepo.contains(it.key, v)
|
||||||
|
}.ifEmpty {
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
kvCache.set(
|
||||||
|
it.key,
|
||||||
|
(kvCache.get(it.key) ?: emptyList()) + filtered
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun remove(toRemove: Map<Key, List<Value>>) {
|
||||||
|
locker.withWriteLock {
|
||||||
|
parentRepo.remove(toRemove)
|
||||||
|
toRemove.forEach {
|
||||||
|
val filtered = it.value.filter { v ->
|
||||||
|
!parentRepo.contains(it.key, v)
|
||||||
|
}.ifEmpty {
|
||||||
|
return@forEach
|
||||||
|
}.toSet()
|
||||||
|
val resultList = (kvCache.get(it.key) ?: emptyList()) - filtered
|
||||||
|
if (resultList.isEmpty()) {
|
||||||
|
kvCache.unset(it.key)
|
||||||
|
} else {
|
||||||
|
kvCache.set(
|
||||||
|
it.key,
|
||||||
|
resultList
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun clear(k: Key) {
|
||||||
|
locker.withWriteLock {
|
||||||
|
parentRepo.clear(k)
|
||||||
|
if (parentRepo.contains(k)) {
|
||||||
|
return@withWriteLock
|
||||||
|
}
|
||||||
|
kvCache.unset(k)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
56
repos/cache/src/commonTest/kotlin/full/FullKeyValuesCacheRepoTests.kt
vendored
Normal file
56
repos/cache/src/commonTest/kotlin/full/FullKeyValuesCacheRepoTests.kt
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package full
|
||||||
|
|
||||||
|
import com.benasher44.uuid.uuid4
|
||||||
|
import dev.inmo.micro_utils.repos.*
|
||||||
|
import dev.inmo.micro_utils.repos.cache.full.FullKeyValuesCacheRepo
|
||||||
|
import korlibs.time.days
|
||||||
|
import korlibs.time.years
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
class FullKeyValuesCacheRepoTests {
|
||||||
|
@Test
|
||||||
|
fun creatingWorksProperly() = runTest(timeout = 1.days) {
|
||||||
|
val testData = (0 until 1000).associate {
|
||||||
|
(it.toString() + uuid4().toString()) to (0 until 1000).map {
|
||||||
|
uuid4().toString()
|
||||||
|
}.sorted()
|
||||||
|
}
|
||||||
|
val updatedTestData = testData.keys.associateWith {
|
||||||
|
(0 until 1000).map {
|
||||||
|
uuid4().toString()
|
||||||
|
}.sorted()
|
||||||
|
}
|
||||||
|
val addedData = testData.keys.associateWith {
|
||||||
|
uuid4().toString()
|
||||||
|
}
|
||||||
|
val kvCache = MapKeyValueRepo<String, List<String>>()
|
||||||
|
val kvRepo = MapKeyValuesRepo<String, String>()
|
||||||
|
|
||||||
|
val cacheRepo = FullKeyValuesCacheRepo(
|
||||||
|
kvRepo,
|
||||||
|
kvCache
|
||||||
|
)
|
||||||
|
|
||||||
|
testData.forEach {
|
||||||
|
cacheRepo.set(it.key, it.value)
|
||||||
|
assertContentEquals(it.value, cacheRepo.getAll(it.key))
|
||||||
|
assertContentEquals(it.value, kvRepo.getAll(it.key))
|
||||||
|
assertContentEquals(it.value, kvCache.get(it.key) ?.sorted())
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedTestData.forEach {
|
||||||
|
cacheRepo.set(it.key, it.value)
|
||||||
|
assertContentEquals(it.value, cacheRepo.getAll(it.key))
|
||||||
|
assertContentEquals(it.value, kvRepo.getAll(it.key))
|
||||||
|
assertContentEquals(it.value, kvCache.get(it.key) ?.sorted())
|
||||||
|
}
|
||||||
|
|
||||||
|
addedData.forEach {
|
||||||
|
cacheRepo.add(it.key, it.value)
|
||||||
|
assertTrue(cacheRepo.contains(it.key, it.value))
|
||||||
|
assertTrue(kvRepo.contains(it.key, it.value))
|
||||||
|
assertTrue(kvCache.get(it.key) !!.contains(it.value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -108,6 +108,19 @@ class MapWriteKeyValuesRepo<Key, Value>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun set(toSet: Map<Key, List<Value>>) {
|
||||||
|
locker.withWriteLock {
|
||||||
|
toSet.forEach {
|
||||||
|
map[it.key] = it.value.toMutableList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
toSet.forEach { (k, v) ->
|
||||||
|
v.forEach {
|
||||||
|
_onNewValue.emit(k to it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun remove(toRemove: Map<Key, List<Value>>) {
|
override suspend fun remove(toRemove: Map<Key, List<Value>>) {
|
||||||
val removed = mutableListOf<Pair<Key, Value>>()
|
val removed = mutableListOf<Pair<Key, Value>>()
|
||||||
val cleared = mutableListOf<Key>()
|
val cleared = mutableListOf<Key>()
|
||||||
|
Loading…
Reference in New Issue
Block a user