mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-11-04 14:14:51 +00:00 
			
		
		
		
	start 0.20.2 and all main repos uses 'SmartRWLocker'
This commit is contained in:
		@@ -1,5 +1,9 @@
 | 
				
			|||||||
# Changelog
 | 
					# Changelog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* All main repos uses `SmartRWLocker`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 0.20.1
 | 
					## 0.20.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* `SmallTextField`:
 | 
					* `SmallTextField`:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,5 +15,5 @@ crypto_js_version=4.1.1
 | 
				
			|||||||
# Project data
 | 
					# Project data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
group=dev.inmo
 | 
					group=dev.inmo
 | 
				
			||||||
version=0.20.1
 | 
					version=0.20.2
 | 
				
			||||||
android_code_version=207
 | 
					android_code_version=208
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,8 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.cache
 | 
					package dev.inmo.micro_utils.repos.cache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.SmartRWLocker
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.withReadAcquire
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.withWriteLock
 | 
				
			||||||
import dev.inmo.micro_utils.repos.*
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.cache.KVCache
 | 
					import dev.inmo.micro_utils.repos.cache.cache.KVCache
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
					import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
				
			||||||
@@ -10,32 +13,47 @@ import kotlinx.coroutines.flow.*
 | 
				
			|||||||
open class ReadCRUDCacheRepo<ObjectType, IdType>(
 | 
					open class ReadCRUDCacheRepo<ObjectType, IdType>(
 | 
				
			||||||
    protected open val parentRepo: ReadCRUDRepo<ObjectType, IdType>,
 | 
					    protected open val parentRepo: ReadCRUDRepo<ObjectType, IdType>,
 | 
				
			||||||
    protected open val kvCache: KVCache<IdType, ObjectType>,
 | 
					    protected open val kvCache: KVCache<IdType, ObjectType>,
 | 
				
			||||||
 | 
					    protected val locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
    protected open val idGetter: (ObjectType) -> IdType
 | 
					    protected open val idGetter: (ObjectType) -> IdType
 | 
				
			||||||
) : ReadCRUDRepo<ObjectType, IdType> by parentRepo, CommonCacheRepo {
 | 
					) : ReadCRUDRepo<ObjectType, IdType> by parentRepo, CommonCacheRepo {
 | 
				
			||||||
    override suspend fun getById(id: IdType): ObjectType? = kvCache.get(id) ?: (parentRepo.getById(id) ?.also {
 | 
					    override suspend fun getById(id: IdType): ObjectType? = locker.withReadAcquire {
 | 
				
			||||||
        kvCache.set(id, it)
 | 
					        kvCache.get(id)
 | 
				
			||||||
 | 
					    } ?: (parentRepo.getById(id) ?.also {
 | 
				
			||||||
 | 
					        locker.withWriteLock {
 | 
				
			||||||
 | 
					            kvCache.set(id, it)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun getAll(): Map<IdType, ObjectType> {
 | 
					    override suspend fun getAll(): Map<IdType, ObjectType> {
 | 
				
			||||||
        return kvCache.getAll().takeIf { it.size.toLong() == count() } ?: parentRepo.getAll().also {
 | 
					        return locker.withReadAcquire {
 | 
				
			||||||
            kvCache.actualizeAll(true) { it }
 | 
					            kvCache.getAll()
 | 
				
			||||||
 | 
					        }.takeIf { it.size.toLong() == count() } ?: parentRepo.getAll().also {
 | 
				
			||||||
 | 
					            locker.withWriteLock {
 | 
				
			||||||
 | 
					                kvCache.actualizeAll(true) { it }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun contains(id: IdType): Boolean = kvCache.contains(id) || parentRepo.contains(id)
 | 
					    override suspend fun contains(id: IdType): Boolean = locker.withReadAcquire {
 | 
				
			||||||
 | 
					        kvCache.contains(id)
 | 
				
			||||||
 | 
					    } || parentRepo.contains(id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun invalidate() = kvCache.clear()
 | 
					    override suspend fun invalidate() = locker.withWriteLock {
 | 
				
			||||||
 | 
					        kvCache.clear()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <ObjectType, IdType> ReadCRUDRepo<ObjectType, IdType>.cached(
 | 
					fun <ObjectType, IdType> ReadCRUDRepo<ObjectType, IdType>.cached(
 | 
				
			||||||
    kvCache: KVCache<IdType, ObjectType>,
 | 
					    kvCache: KVCache<IdType, ObjectType>,
 | 
				
			||||||
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
    idGetter: (ObjectType) -> IdType
 | 
					    idGetter: (ObjectType) -> IdType
 | 
				
			||||||
) = ReadCRUDCacheRepo(this, kvCache, idGetter)
 | 
					) = ReadCRUDCacheRepo(this, kvCache, locker, idGetter)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
open class WriteCRUDCacheRepo<ObjectType, IdType, InputValueType>(
 | 
					open class WriteCRUDCacheRepo<ObjectType, IdType, InputValueType>(
 | 
				
			||||||
    protected open val parentRepo: WriteCRUDRepo<ObjectType, IdType, InputValueType>,
 | 
					    protected open val parentRepo: WriteCRUDRepo<ObjectType, IdType, InputValueType>,
 | 
				
			||||||
    protected open val kvCache: KVCache<IdType, ObjectType>,
 | 
					    protected open val kvCache: KeyValueRepo<IdType, ObjectType>,
 | 
				
			||||||
    protected open val scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
					    protected open val scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
				
			||||||
 | 
					    protected val locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
    protected open val idGetter: (ObjectType) -> IdType
 | 
					    protected open val idGetter: (ObjectType) -> IdType
 | 
				
			||||||
) : WriteCRUDRepo<ObjectType, IdType, InputValueType>, CommonCacheRepo {
 | 
					) : WriteCRUDRepo<ObjectType, IdType, InputValueType>, CommonCacheRepo {
 | 
				
			||||||
    override val newObjectsFlow: Flow<ObjectType> by parentRepo::newObjectsFlow
 | 
					    override val newObjectsFlow: Flow<ObjectType> by parentRepo::newObjectsFlow
 | 
				
			||||||
@@ -43,15 +61,15 @@ open class WriteCRUDCacheRepo<ObjectType, IdType, InputValueType>(
 | 
				
			|||||||
    override val deletedObjectsIdsFlow: Flow<IdType> by parentRepo::deletedObjectsIdsFlow
 | 
					    override val deletedObjectsIdsFlow: Flow<IdType> by parentRepo::deletedObjectsIdsFlow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val createdObjectsFlowJob = parentRepo.newObjectsFlow.onEach {
 | 
					    val createdObjectsFlowJob = parentRepo.newObjectsFlow.onEach {
 | 
				
			||||||
        kvCache.set(idGetter(it), it)
 | 
					        locker.withWriteLock { kvCache.set(idGetter(it), it) }
 | 
				
			||||||
    }.launchIn(scope)
 | 
					    }.launchIn(scope)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val updatedObjectsFlowJob = parentRepo.updatedObjectsFlow.onEach {
 | 
					    val updatedObjectsFlowJob = parentRepo.updatedObjectsFlow.onEach {
 | 
				
			||||||
        kvCache.set(idGetter(it), it)
 | 
					        locker.withWriteLock { kvCache.set(idGetter(it), it) }
 | 
				
			||||||
    }.launchIn(scope)
 | 
					    }.launchIn(scope)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val deletedObjectsFlowJob = parentRepo.deletedObjectsIdsFlow.onEach {
 | 
					    val deletedObjectsFlowJob = parentRepo.deletedObjectsIdsFlow.onEach {
 | 
				
			||||||
        kvCache.unset(it)
 | 
					        locker.withWriteLock { kvCache.unset(it) }
 | 
				
			||||||
    }.launchIn(scope)
 | 
					    }.launchIn(scope)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun deleteById(ids: List<IdType>) = parentRepo.deleteById(ids)
 | 
					    override suspend fun deleteById(ids: List<IdType>) = parentRepo.deleteById(ids)
 | 
				
			||||||
@@ -59,53 +77,65 @@ open class WriteCRUDCacheRepo<ObjectType, IdType, InputValueType>(
 | 
				
			|||||||
    override suspend fun update(values: List<UpdatedValuePair<IdType, InputValueType>>): List<ObjectType> {
 | 
					    override suspend fun update(values: List<UpdatedValuePair<IdType, InputValueType>>): List<ObjectType> {
 | 
				
			||||||
        val updated = parentRepo.update(values)
 | 
					        val updated = parentRepo.update(values)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        kvCache.unset(values.map { it.id })
 | 
					        locker.withWriteLock {
 | 
				
			||||||
        kvCache.set(updated.associateBy { idGetter(it) })
 | 
					            kvCache.unset(values.map { it.id })
 | 
				
			||||||
 | 
					            kvCache.set(updated.associateBy { idGetter(it) })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return updated
 | 
					        return updated
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun update(id: IdType, value: InputValueType): ObjectType? {
 | 
					    override suspend fun update(id: IdType, value: InputValueType): ObjectType? {
 | 
				
			||||||
        return parentRepo.update(id, value) ?.also {
 | 
					        return parentRepo.update(id, value) ?.also {
 | 
				
			||||||
            kvCache.unset(id)
 | 
					            locker.withWriteLock {
 | 
				
			||||||
            kvCache.set(idGetter(it), it)
 | 
					                kvCache.unset(id)
 | 
				
			||||||
 | 
					                kvCache.set(idGetter(it), it)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun create(values: List<InputValueType>): List<ObjectType> {
 | 
					    override suspend fun create(values: List<InputValueType>): List<ObjectType> {
 | 
				
			||||||
        val created = parentRepo.create(values)
 | 
					        val created = parentRepo.create(values)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        kvCache.set(
 | 
					        locker.withWriteLock {
 | 
				
			||||||
            created.associateBy { idGetter(it) }
 | 
					            kvCache.set(
 | 
				
			||||||
        )
 | 
					                created.associateBy { idGetter(it) }
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return created
 | 
					        return created
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun invalidate() = kvCache.clear()
 | 
					    override suspend fun invalidate() = locker.withWriteLock {
 | 
				
			||||||
 | 
					        kvCache.clear()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <ObjectType, IdType, InputType> WriteCRUDRepo<ObjectType, IdType, InputType>.caching(
 | 
					fun <ObjectType, IdType, InputType> WriteCRUDRepo<ObjectType, IdType, InputType>.caching(
 | 
				
			||||||
    kvCache: KVCache<IdType, ObjectType>,
 | 
					    kvCache: KVCache<IdType, ObjectType>,
 | 
				
			||||||
    scope: CoroutineScope,
 | 
					    scope: CoroutineScope,
 | 
				
			||||||
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
    idGetter: (ObjectType) -> IdType
 | 
					    idGetter: (ObjectType) -> IdType
 | 
				
			||||||
) = WriteCRUDCacheRepo(this, kvCache, scope, idGetter)
 | 
					) = WriteCRUDCacheRepo(this, kvCache, scope, locker, idGetter)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
open class CRUDCacheRepo<ObjectType, IdType, InputValueType>(
 | 
					open class CRUDCacheRepo<ObjectType, IdType, InputValueType>(
 | 
				
			||||||
    override val parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>,
 | 
					    override val parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>,
 | 
				
			||||||
    kvCache: KVCache<IdType, ObjectType>,
 | 
					    kvCache: KVCache<IdType, ObjectType>,
 | 
				
			||||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
				
			||||||
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
    idGetter: (ObjectType) -> IdType
 | 
					    idGetter: (ObjectType) -> IdType
 | 
				
			||||||
) : ReadCRUDCacheRepo<ObjectType, IdType>(
 | 
					) : ReadCRUDCacheRepo<ObjectType, IdType>(
 | 
				
			||||||
    parentRepo,
 | 
					    parentRepo,
 | 
				
			||||||
    kvCache,
 | 
					    kvCache,
 | 
				
			||||||
 | 
					    locker,
 | 
				
			||||||
    idGetter
 | 
					    idGetter
 | 
				
			||||||
),
 | 
					),
 | 
				
			||||||
    WriteCRUDRepo<ObjectType, IdType, InputValueType> by WriteCRUDCacheRepo(
 | 
					    WriteCRUDRepo<ObjectType, IdType, InputValueType> by WriteCRUDCacheRepo(
 | 
				
			||||||
    parentRepo,
 | 
					    parentRepo,
 | 
				
			||||||
    kvCache,
 | 
					    kvCache,
 | 
				
			||||||
    scope,
 | 
					    scope,
 | 
				
			||||||
 | 
					    locker,
 | 
				
			||||||
    idGetter
 | 
					    idGetter
 | 
				
			||||||
),
 | 
					),
 | 
				
			||||||
    CRUDRepo<ObjectType, IdType, InputValueType>
 | 
					    CRUDRepo<ObjectType, IdType, InputValueType>
 | 
				
			||||||
@@ -113,5 +143,6 @@ open class CRUDCacheRepo<ObjectType, IdType, InputValueType>(
 | 
				
			|||||||
fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.cached(
 | 
					fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.cached(
 | 
				
			||||||
    kvCache: KVCache<IdType, ObjectType>,
 | 
					    kvCache: KVCache<IdType, ObjectType>,
 | 
				
			||||||
    scope: CoroutineScope,
 | 
					    scope: CoroutineScope,
 | 
				
			||||||
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
    idGetter: (ObjectType) -> IdType
 | 
					    idGetter: (ObjectType) -> IdType
 | 
				
			||||||
) = CRUDCacheRepo(this, kvCache, scope, idGetter)
 | 
					) = CRUDCacheRepo(this, kvCache, scope, locker, idGetter)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,8 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.cache
 | 
					package dev.inmo.micro_utils.repos.cache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.SmartRWLocker
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.withReadAcquire
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.withWriteLock
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.*
 | 
					import dev.inmo.micro_utils.pagination.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.*
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.cache.KVCache
 | 
					import dev.inmo.micro_utils.repos.cache.cache.KVCache
 | 
				
			||||||
@@ -10,50 +13,82 @@ import kotlinx.coroutines.flow.*
 | 
				
			|||||||
open class ReadKeyValueCacheRepo<Key,Value>(
 | 
					open class ReadKeyValueCacheRepo<Key,Value>(
 | 
				
			||||||
    protected open val parentRepo: ReadKeyValueRepo<Key, Value>,
 | 
					    protected open val parentRepo: ReadKeyValueRepo<Key, Value>,
 | 
				
			||||||
    protected open val kvCache: KVCache<Key, Value>,
 | 
					    protected open val kvCache: KVCache<Key, Value>,
 | 
				
			||||||
 | 
					    protected val locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
) : ReadKeyValueRepo<Key,Value> by parentRepo, CommonCacheRepo {
 | 
					) : ReadKeyValueRepo<Key,Value> by parentRepo, CommonCacheRepo {
 | 
				
			||||||
    override suspend fun get(k: Key): Value? = kvCache.get(k) ?: parentRepo.get(k) ?.also { kvCache.set(k, it) }
 | 
					    override suspend fun get(k: Key): Value? = locker.withReadAcquire {
 | 
				
			||||||
    override suspend fun contains(key: Key): Boolean = kvCache.contains(key) || parentRepo.contains(key)
 | 
					        kvCache.get(k)
 | 
				
			||||||
 | 
					    } ?: parentRepo.get(k) ?.also {
 | 
				
			||||||
 | 
					        locker.withWriteLock {
 | 
				
			||||||
 | 
					            kvCache.set(k, it)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    override suspend fun contains(key: Key): Boolean = locker.withReadAcquire {
 | 
				
			||||||
 | 
					        kvCache.contains(key)
 | 
				
			||||||
 | 
					    } || parentRepo.contains(key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun values(pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
 | 
					    override suspend fun values(pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
 | 
				
			||||||
        return keys(pagination, reversed).let {
 | 
					        return locker.withReadAcquire {
 | 
				
			||||||
            it.changeResultsUnchecked(
 | 
					            keys(pagination, reversed).let {
 | 
				
			||||||
                it.results.mapNotNull {
 | 
					                it.changeResultsUnchecked(
 | 
				
			||||||
                    get(it)
 | 
					                    it.results.mapNotNull {
 | 
				
			||||||
                }
 | 
					                        get(it)
 | 
				
			||||||
            )
 | 
					                    }
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun getAll(): Map<Key, Value> = kvCache.getAll().takeIf {
 | 
					    override suspend fun getAll(): Map<Key, Value> = locker.withReadAcquire {
 | 
				
			||||||
 | 
					        kvCache.getAll()
 | 
				
			||||||
 | 
					    }.takeIf {
 | 
				
			||||||
        it.size.toLong() == count()
 | 
					        it.size.toLong() == count()
 | 
				
			||||||
    } ?: parentRepo.getAll().also {
 | 
					    } ?: parentRepo.getAll().also {
 | 
				
			||||||
        kvCache.set(it)
 | 
					        locker.withWriteLock {
 | 
				
			||||||
 | 
					            kvCache.set(it)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun invalidate() = kvCache.clear()
 | 
					    override suspend fun invalidate() = locker.withWriteLock {
 | 
				
			||||||
 | 
					        kvCache.clear()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <Key, Value> ReadKeyValueRepo<Key, Value>.cached(
 | 
					fun <Key, Value> ReadKeyValueRepo<Key, Value>.cached(
 | 
				
			||||||
    kvCache: KVCache<Key, Value>
 | 
					    kvCache: KVCache<Key, Value>,
 | 
				
			||||||
) = ReadKeyValueCacheRepo(this, kvCache)
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
 | 
					) = ReadKeyValueCacheRepo(this, kvCache, locker)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
open class KeyValueCacheRepo<Key,Value>(
 | 
					open class KeyValueCacheRepo<Key,Value>(
 | 
				
			||||||
    override val parentRepo: KeyValueRepo<Key, Value>,
 | 
					    override val parentRepo: KeyValueRepo<Key, Value>,
 | 
				
			||||||
    kvCache: KVCache<Key, Value>,
 | 
					    kvCache: KVCache<Key, Value>,
 | 
				
			||||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
				
			||||||
) : ReadKeyValueCacheRepo<Key,Value>(parentRepo, kvCache), KeyValueRepo<Key,Value>, WriteKeyValueRepo<Key, Value> by parentRepo, CommonCacheRepo {
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
    protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, it.second) }.launchIn(scope)
 | 
					) : ReadKeyValueCacheRepo<Key,Value>(parentRepo, kvCache, locker), KeyValueRepo<Key,Value>, WriteKeyValueRepo<Key, Value> by parentRepo, CommonCacheRepo {
 | 
				
			||||||
    protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.unset(it) }.launchIn(scope)
 | 
					    protected val onNewJob = parentRepo.onNewValue.onEach {
 | 
				
			||||||
 | 
					        locker.withWriteLock {
 | 
				
			||||||
 | 
					            kvCache.set(it.first, it.second)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }.launchIn(scope)
 | 
				
			||||||
 | 
					    protected val onRemoveJob = parentRepo.onValueRemoved.onEach {
 | 
				
			||||||
 | 
					        locker.withWriteLock {
 | 
				
			||||||
 | 
					            kvCache.unset(it)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }.launchIn(scope)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun invalidate() = kvCache.clear()
 | 
					    override suspend fun invalidate() = locker.withWriteLock {
 | 
				
			||||||
 | 
					        kvCache.clear()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun clear() {
 | 
					    override suspend fun clear() {
 | 
				
			||||||
        parentRepo.clear()
 | 
					        parentRepo.clear()
 | 
				
			||||||
        kvCache.clear()
 | 
					        locker.withWriteLock {
 | 
				
			||||||
 | 
					            kvCache.clear()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <Key, Value> KeyValueRepo<Key, Value>.cached(
 | 
					fun <Key, Value> KeyValueRepo<Key, Value>.cached(
 | 
				
			||||||
    kvCache: KVCache<Key, Value>,
 | 
					    kvCache: KVCache<Key, Value>,
 | 
				
			||||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
				
			||||||
) = KeyValueCacheRepo(this, kvCache, scope)
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
 | 
					) = KeyValueCacheRepo(this, kvCache, scope, locker)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,8 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.cache
 | 
					package dev.inmo.micro_utils.repos.cache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.SmartRWLocker
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.withReadAcquire
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.withWriteLock
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.*
 | 
					import dev.inmo.micro_utils.pagination.*
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.utils.*
 | 
					import dev.inmo.micro_utils.pagination.utils.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.*
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
@@ -10,59 +13,85 @@ import kotlinx.coroutines.flow.*
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
open class ReadKeyValuesCacheRepo<Key,Value>(
 | 
					open class ReadKeyValuesCacheRepo<Key,Value>(
 | 
				
			||||||
    protected open val parentRepo: ReadKeyValuesRepo<Key, Value>,
 | 
					    protected open val parentRepo: ReadKeyValuesRepo<Key, Value>,
 | 
				
			||||||
    protected open val kvCache: KVCache<Key, List<Value>>
 | 
					    protected open val kvCache: KVCache<Key, List<Value>>,
 | 
				
			||||||
 | 
					    protected val locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
) : ReadKeyValuesRepo<Key,Value> by parentRepo, CommonCacheRepo {
 | 
					) : ReadKeyValuesRepo<Key,Value> by parentRepo, CommonCacheRepo {
 | 
				
			||||||
    override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
 | 
					    override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
 | 
				
			||||||
        return getAll(k, reversed).paginate(
 | 
					        return locker.withReadAcquire {
 | 
				
			||||||
 | 
					            getAll(k, reversed)
 | 
				
			||||||
 | 
					        }.paginate(
 | 
				
			||||||
            pagination
 | 
					            pagination
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    override suspend fun getAll(k: Key, reversed: Boolean): List<Value> {
 | 
					    override suspend fun getAll(k: Key, reversed: Boolean): List<Value> {
 | 
				
			||||||
        return kvCache.get(k) ?.let {
 | 
					        return locker.withReadAcquire {
 | 
				
			||||||
 | 
					            kvCache.get(k)
 | 
				
			||||||
 | 
					        } ?.let {
 | 
				
			||||||
            if (reversed) it.reversed() else it
 | 
					            if (reversed) it.reversed() else it
 | 
				
			||||||
        } ?: parentRepo.getAll(k, reversed).also {
 | 
					        } ?: parentRepo.getAll(k, reversed).also {
 | 
				
			||||||
            kvCache.set(k, it)
 | 
					            locker.withWriteLock {
 | 
				
			||||||
 | 
					                kvCache.set(k, it)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    override suspend fun contains(k: Key, v: Value): Boolean = kvCache.get(k) ?.contains(v) ?: (parentRepo.contains(k, v).also {
 | 
					    override suspend fun contains(k: Key, v: Value): Boolean = locker.withReadAcquire {
 | 
				
			||||||
 | 
					        kvCache.get(k)
 | 
				
			||||||
 | 
					    } ?.contains(v) ?: (parentRepo.contains(k, v).also {
 | 
				
			||||||
        if (it) {
 | 
					        if (it) {
 | 
				
			||||||
            kvCache.unset(k) // clear as invalid
 | 
					            locker.withWriteLock {
 | 
				
			||||||
 | 
					                kvCache.unset(k) // clear as invalid
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    override suspend fun contains(k: Key): Boolean = kvCache.contains(k) || parentRepo.contains(k)
 | 
					    override suspend fun contains(k: Key): Boolean = locker.withReadAcquire {
 | 
				
			||||||
 | 
					        kvCache.contains(k)
 | 
				
			||||||
 | 
					    } || parentRepo.contains(k)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun invalidate() = kvCache.clear()
 | 
					    override suspend fun invalidate() = locker.withWriteLock {
 | 
				
			||||||
 | 
					        kvCache.clear()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <Key, Value> ReadKeyValuesRepo<Key, Value>.cached(
 | 
					fun <Key, Value> ReadKeyValuesRepo<Key, Value>.cached(
 | 
				
			||||||
    kvCache: KVCache<Key, List<Value>>
 | 
					    kvCache: KVCache<Key, List<Value>>,
 | 
				
			||||||
) = ReadKeyValuesCacheRepo(this, kvCache)
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
 | 
					) = ReadKeyValuesCacheRepo(this, kvCache, locker)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
open class KeyValuesCacheRepo<Key,Value>(
 | 
					open class KeyValuesCacheRepo<Key,Value>(
 | 
				
			||||||
    parentRepo: KeyValuesRepo<Key, Value>,
 | 
					    parentRepo: KeyValuesRepo<Key, Value>,
 | 
				
			||||||
    kvCache: KVCache<Key, List<Value>>,
 | 
					    kvCache: KVCache<Key, List<Value>>,
 | 
				
			||||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
				
			||||||
) : ReadKeyValuesCacheRepo<Key,Value>(parentRepo, kvCache), KeyValuesRepo<Key,Value>, WriteKeyValuesRepo<Key,Value> by parentRepo, CommonCacheRepo {
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
 | 
					) : ReadKeyValuesCacheRepo<Key,Value>(parentRepo, kvCache, locker), KeyValuesRepo<Key,Value>, WriteKeyValuesRepo<Key,Value> by parentRepo, CommonCacheRepo {
 | 
				
			||||||
    protected val onNewJob = parentRepo.onNewValue.onEach { (k, v) ->
 | 
					    protected val onNewJob = parentRepo.onNewValue.onEach { (k, v) ->
 | 
				
			||||||
        kvCache.set(
 | 
					        locker.withWriteLock {
 | 
				
			||||||
            k,
 | 
					            kvCache.set(
 | 
				
			||||||
            kvCache.get(k) ?.plus(v) ?: return@onEach
 | 
					                k,
 | 
				
			||||||
        )
 | 
					                kvCache.get(k) ?.plus(v) ?: return@onEach
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }.launchIn(scope)
 | 
					    }.launchIn(scope)
 | 
				
			||||||
    protected val onRemoveJob = parentRepo.onValueRemoved.onEach { (k, v) ->
 | 
					    protected val onRemoveJob = parentRepo.onValueRemoved.onEach { (k, v) ->
 | 
				
			||||||
        kvCache.set(
 | 
					        locker.withWriteLock {
 | 
				
			||||||
            k,
 | 
					            kvCache.set(
 | 
				
			||||||
            kvCache.get(k) ?.minus(v) ?: return@onEach
 | 
					                k,
 | 
				
			||||||
        )
 | 
					                kvCache.get(k)?.minus(v) ?: return@onEach
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }.launchIn(scope)
 | 
					    }.launchIn(scope)
 | 
				
			||||||
    protected val onDataClearedJob = parentRepo.onDataCleared.onEach {
 | 
					    protected val onDataClearedJob = parentRepo.onDataCleared.onEach {
 | 
				
			||||||
        kvCache.unset(it)
 | 
					        locker.withWriteLock {
 | 
				
			||||||
 | 
					            kvCache.unset(it)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }.launchIn(scope)
 | 
					    }.launchIn(scope)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun invalidate() = kvCache.clear()
 | 
					    override suspend fun invalidate() = locker.withWriteLock {
 | 
				
			||||||
 | 
					        kvCache.clear()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <Key, Value> KeyValuesRepo<Key, Value>.cached(
 | 
					fun <Key, Value> KeyValuesRepo<Key, Value>.cached(
 | 
				
			||||||
    kvCache: KVCache<Key, List<Value>>,
 | 
					    kvCache: KVCache<Key, List<Value>>,
 | 
				
			||||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
				
			||||||
) = KeyValuesCacheRepo(this, kvCache, scope)
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
 | 
					) = KeyValuesCacheRepo(this, kvCache, scope, locker)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ 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
 | 
					 * This interface declares that current type of [KVCache] will contains all the data all the time of its life
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					@Deprecated("This type of KV repos is obsolete and will be removed soon", ReplaceWith("KeyValueRepo<K, V>", "dev.inmo.micro_utils.repos.KeyValueRepo"))
 | 
				
			||||||
interface FullKVCache<K, V> : KVCache<K, V> {
 | 
					interface FullKVCache<K, V> : KVCache<K, V> {
 | 
				
			||||||
    companion object
 | 
					    companion object
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,9 @@ import dev.inmo.micro_utils.repos.MapKeyValueRepo
 | 
				
			|||||||
import kotlinx.coroutines.sync.Mutex
 | 
					import kotlinx.coroutines.sync.Mutex
 | 
				
			||||||
import kotlinx.coroutines.sync.withLock
 | 
					import kotlinx.coroutines.sync.withLock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
open class SimpleFullKVCache<K, V>(
 | 
					@Deprecated("This type of KV repos is obsolete and will be removed soon", ReplaceWith("MapKeyValueRepo<K, V>()", "dev.inmo.micro_utils.repos.MapKeyValueRepo"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SimpleFullKVCache<K, V>(
 | 
				
			||||||
    private val kvParent: KeyValueRepo<K, V> = MapKeyValueRepo<K, V>()
 | 
					    private val kvParent: KeyValueRepo<K, V> = MapKeyValueRepo<K, V>()
 | 
				
			||||||
) : FullKVCache<K, V>, KeyValueRepo<K, V> by kvParent {
 | 
					) : FullKVCache<K, V>, KeyValueRepo<K, V> by kvParent {
 | 
				
			||||||
    protected val syncMutex = Mutex()
 | 
					    protected val syncMutex = Mutex()
 | 
				
			||||||
@@ -29,6 +31,7 @@ open class SimpleFullKVCache<K, V>(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("This type of KV repos is obsolete and will be removed soon", ReplaceWith("kvParent", "dev.inmo.micro_utils.repos.MapKeyValueRepo"))
 | 
				
			||||||
inline fun <K, V> FullKVCache(
 | 
					inline fun <K, V> FullKVCache(
 | 
				
			||||||
    kvParent: KeyValueRepo<K, V> = MapKeyValueRepo<K, V>()
 | 
					    kvParent: KeyValueRepo<K, V> = MapKeyValueRepo<K, V>()
 | 
				
			||||||
) = SimpleFullKVCache<K, V>(kvParent)
 | 
					) = SimpleFullKVCache<K, V>(kvParent)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,9 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.cache.fallback.crud
 | 
					package dev.inmo.micro_utils.repos.cache.fallback.crud
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.inmo.micro_utils.repos.CRUDRepo
 | 
					import dev.inmo.micro_utils.repos.CRUDRepo
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.KeyValueRepo
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.MapKeyValueRepo
 | 
				
			||||||
import dev.inmo.micro_utils.repos.WriteCRUDRepo
 | 
					import dev.inmo.micro_utils.repos.WriteCRUDRepo
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
 | 
					import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
 | 
				
			||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
import kotlin.time.Duration.Companion.seconds
 | 
					import kotlin.time.Duration.Companion.seconds
 | 
				
			||||||
@@ -10,7 +11,7 @@ import kotlin.time.Duration.Companion.seconds
 | 
				
			|||||||
open class AutoRecacheCRUDRepo<RegisteredObject, Id, InputObject>(
 | 
					open class AutoRecacheCRUDRepo<RegisteredObject, Id, InputObject>(
 | 
				
			||||||
    originalRepo: CRUDRepo<RegisteredObject, Id, InputObject>,
 | 
					    originalRepo: CRUDRepo<RegisteredObject, Id, InputObject>,
 | 
				
			||||||
    scope: CoroutineScope,
 | 
					    scope: CoroutineScope,
 | 
				
			||||||
    kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache(),
 | 
					    kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo(),
 | 
				
			||||||
    recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
					    recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
				
			||||||
    actionWrapper: ActionWrapper = ActionWrapper.Direct,
 | 
					    actionWrapper: ActionWrapper = ActionWrapper.Direct,
 | 
				
			||||||
    idGetter: (RegisteredObject) -> Id
 | 
					    idGetter: (RegisteredObject) -> Id
 | 
				
			||||||
@@ -29,7 +30,7 @@ open class AutoRecacheCRUDRepo<RegisteredObject, Id, InputObject>(
 | 
				
			|||||||
        originalRepo: CRUDRepo<RegisteredObject, Id, InputObject>,
 | 
					        originalRepo: CRUDRepo<RegisteredObject, Id, InputObject>,
 | 
				
			||||||
        scope: CoroutineScope,
 | 
					        scope: CoroutineScope,
 | 
				
			||||||
        originalCallTimeoutMillis: Long,
 | 
					        originalCallTimeoutMillis: Long,
 | 
				
			||||||
        kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache(),
 | 
					        kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo(),
 | 
				
			||||||
        recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
					        recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
				
			||||||
        idGetter: (RegisteredObject) -> Id
 | 
					        idGetter: (RegisteredObject) -> Id
 | 
				
			||||||
    ) : this(originalRepo, scope, kvCache, recacheDelay, ActionWrapper.Timeouted(originalCallTimeoutMillis), idGetter)
 | 
					    ) : this(originalRepo, scope, kvCache, recacheDelay, ActionWrapper.Timeouted(originalCallTimeoutMillis), idGetter)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,8 +3,9 @@ package dev.inmo.micro_utils.repos.cache.fallback.crud
 | 
				
			|||||||
import dev.inmo.micro_utils.coroutines.runCatchingSafely
 | 
					import dev.inmo.micro_utils.coroutines.runCatchingSafely
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.Pagination
 | 
					import dev.inmo.micro_utils.pagination.Pagination
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.PaginationResult
 | 
					import dev.inmo.micro_utils.pagination.PaginationResult
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.KeyValueRepo
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.MapKeyValueRepo
 | 
				
			||||||
import dev.inmo.micro_utils.repos.ReadCRUDRepo
 | 
					import dev.inmo.micro_utils.repos.ReadCRUDRepo
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
 | 
					import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
					import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
 | 
					import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
 | 
				
			||||||
@@ -18,7 +19,7 @@ import kotlin.time.Duration.Companion.seconds
 | 
				
			|||||||
open class AutoRecacheReadCRUDRepo<RegisteredObject, Id>(
 | 
					open class AutoRecacheReadCRUDRepo<RegisteredObject, Id>(
 | 
				
			||||||
    protected open val originalRepo: ReadCRUDRepo<RegisteredObject, Id>,
 | 
					    protected open val originalRepo: ReadCRUDRepo<RegisteredObject, Id>,
 | 
				
			||||||
    protected val scope: CoroutineScope,
 | 
					    protected val scope: CoroutineScope,
 | 
				
			||||||
    protected val kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache(),
 | 
					    protected val kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo(),
 | 
				
			||||||
    protected val recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
					    protected val recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
				
			||||||
    protected val actionWrapper: ActionWrapper = ActionWrapper.Direct,
 | 
					    protected val actionWrapper: ActionWrapper = ActionWrapper.Direct,
 | 
				
			||||||
    protected val idGetter: (RegisteredObject) -> Id
 | 
					    protected val idGetter: (RegisteredObject) -> Id
 | 
				
			||||||
@@ -35,7 +36,7 @@ open class AutoRecacheReadCRUDRepo<RegisteredObject, Id>(
 | 
				
			|||||||
        originalRepo: ReadCRUDRepo<RegisteredObject, Id>,
 | 
					        originalRepo: ReadCRUDRepo<RegisteredObject, Id>,
 | 
				
			||||||
        scope: CoroutineScope,
 | 
					        scope: CoroutineScope,
 | 
				
			||||||
        originalCallTimeoutMillis: Long,
 | 
					        originalCallTimeoutMillis: Long,
 | 
				
			||||||
        kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache(),
 | 
					        kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo(),
 | 
				
			||||||
        recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
					        recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
				
			||||||
        idGetter: (RegisteredObject) -> Id
 | 
					        idGetter: (RegisteredObject) -> Id
 | 
				
			||||||
    ) : this(originalRepo, scope, kvCache, recacheDelay, ActionWrapper.Timeouted(originalCallTimeoutMillis), idGetter)
 | 
					    ) : this(originalRepo, scope, kvCache, recacheDelay, ActionWrapper.Timeouted(originalCallTimeoutMillis), idGetter)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,23 +1,17 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.cache.fallback.crud
 | 
					package dev.inmo.micro_utils.repos.cache.fallback.crud
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.inmo.micro_utils.coroutines.plus
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
 | 
					import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
 | 
				
			||||||
import dev.inmo.micro_utils.repos.UpdatedValuePair
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.WriteCRUDRepo
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
 | 
					import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
 | 
				
			||||||
import dev.inmo.micro_utils.repos.set
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.unset
 | 
					 | 
				
			||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
import kotlinx.coroutines.flow.Flow
 | 
					import kotlinx.coroutines.flow.Flow
 | 
				
			||||||
import kotlinx.coroutines.flow.distinctUntilChanged
 | 
					import kotlinx.coroutines.flow.distinctUntilChanged
 | 
				
			||||||
import kotlinx.coroutines.flow.map
 | 
					 | 
				
			||||||
import kotlinx.coroutines.flow.merge
 | 
					import kotlinx.coroutines.flow.merge
 | 
				
			||||||
 | 
					
 | 
				
			||||||
open class AutoRecacheWriteCRUDRepo<RegisteredObject, Id, InputObject>(
 | 
					open class AutoRecacheWriteCRUDRepo<RegisteredObject, Id, InputObject>(
 | 
				
			||||||
    protected val originalRepo: WriteCRUDRepo<RegisteredObject, Id, InputObject>,
 | 
					    protected val originalRepo: WriteCRUDRepo<RegisteredObject, Id, InputObject>,
 | 
				
			||||||
    protected val scope: CoroutineScope,
 | 
					    protected val scope: CoroutineScope,
 | 
				
			||||||
    protected val kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache(),
 | 
					    protected val kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo(),
 | 
				
			||||||
    protected val idGetter: (RegisteredObject) -> Id
 | 
					    protected val idGetter: (RegisteredObject) -> Id
 | 
				
			||||||
) : WriteCRUDRepo<RegisteredObject, Id, InputObject>, FallbackCacheRepo {
 | 
					) : WriteCRUDRepo<RegisteredObject, Id, InputObject>, FallbackCacheRepo {
 | 
				
			||||||
    override val deletedObjectsIdsFlow: Flow<Id>
 | 
					    override val deletedObjectsIdsFlow: Flow<Id>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.cache.fallback.keyvalue
 | 
					package dev.inmo.micro_utils.repos.cache.fallback.keyvalue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.inmo.micro_utils.repos.KeyValueRepo
 | 
					import dev.inmo.micro_utils.repos.KeyValueRepo
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.MapKeyValueRepo
 | 
				
			||||||
import dev.inmo.micro_utils.repos.WriteKeyValueRepo
 | 
					import dev.inmo.micro_utils.repos.WriteKeyValueRepo
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
 | 
					import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
 | 
				
			||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
import kotlin.time.Duration.Companion.seconds
 | 
					import kotlin.time.Duration.Companion.seconds
 | 
				
			||||||
@@ -10,7 +10,7 @@ import kotlin.time.Duration.Companion.seconds
 | 
				
			|||||||
open class AutoRecacheKeyValueRepo<Id, RegisteredObject>(
 | 
					open class AutoRecacheKeyValueRepo<Id, RegisteredObject>(
 | 
				
			||||||
    override val originalRepo: KeyValueRepo<Id, RegisteredObject>,
 | 
					    override val originalRepo: KeyValueRepo<Id, RegisteredObject>,
 | 
				
			||||||
    scope: CoroutineScope,
 | 
					    scope: CoroutineScope,
 | 
				
			||||||
    kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache(),
 | 
					    kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo(),
 | 
				
			||||||
    recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
					    recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
				
			||||||
    actionWrapper: ActionWrapper = ActionWrapper.Direct,
 | 
					    actionWrapper: ActionWrapper = ActionWrapper.Direct,
 | 
				
			||||||
    idGetter: (RegisteredObject) -> Id
 | 
					    idGetter: (RegisteredObject) -> Id
 | 
				
			||||||
@@ -29,7 +29,7 @@ open class AutoRecacheKeyValueRepo<Id, RegisteredObject>(
 | 
				
			|||||||
        originalRepo: KeyValueRepo<Id, RegisteredObject>,
 | 
					        originalRepo: KeyValueRepo<Id, RegisteredObject>,
 | 
				
			||||||
        scope: CoroutineScope,
 | 
					        scope: CoroutineScope,
 | 
				
			||||||
        originalCallTimeoutMillis: Long,
 | 
					        originalCallTimeoutMillis: Long,
 | 
				
			||||||
        kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache(),
 | 
					        kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo(),
 | 
				
			||||||
        recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
					        recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
				
			||||||
        idGetter: (RegisteredObject) -> Id
 | 
					        idGetter: (RegisteredObject) -> Id
 | 
				
			||||||
    ) : this(originalRepo, scope, kvCache, recacheDelay, ActionWrapper.Timeouted(originalCallTimeoutMillis), idGetter)
 | 
					    ) : this(originalRepo, scope, kvCache, recacheDelay, ActionWrapper.Timeouted(originalCallTimeoutMillis), idGetter)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,8 +3,9 @@ package dev.inmo.micro_utils.repos.cache.fallback.keyvalue
 | 
				
			|||||||
import dev.inmo.micro_utils.coroutines.runCatchingSafely
 | 
					import dev.inmo.micro_utils.coroutines.runCatchingSafely
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.Pagination
 | 
					import dev.inmo.micro_utils.pagination.Pagination
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.PaginationResult
 | 
					import dev.inmo.micro_utils.pagination.PaginationResult
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.KeyValueRepo
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.MapKeyValueRepo
 | 
				
			||||||
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
 | 
					import dev.inmo.micro_utils.repos.ReadKeyValueRepo
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
 | 
					import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
					import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
 | 
					import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
 | 
				
			||||||
@@ -18,7 +19,7 @@ import kotlin.time.Duration.Companion.seconds
 | 
				
			|||||||
open class AutoRecacheReadKeyValueRepo<Id, RegisteredObject>(
 | 
					open class AutoRecacheReadKeyValueRepo<Id, RegisteredObject>(
 | 
				
			||||||
    protected open val originalRepo: ReadKeyValueRepo<Id, RegisteredObject>,
 | 
					    protected open val originalRepo: ReadKeyValueRepo<Id, RegisteredObject>,
 | 
				
			||||||
    protected val scope: CoroutineScope,
 | 
					    protected val scope: CoroutineScope,
 | 
				
			||||||
    protected val kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache(),
 | 
					    protected val kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo(),
 | 
				
			||||||
    protected val recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
					    protected val recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
				
			||||||
    protected val actionWrapper: ActionWrapper = ActionWrapper.Direct,
 | 
					    protected val actionWrapper: ActionWrapper = ActionWrapper.Direct,
 | 
				
			||||||
    protected val idGetter: (RegisteredObject) -> Id
 | 
					    protected val idGetter: (RegisteredObject) -> Id
 | 
				
			||||||
@@ -35,7 +36,7 @@ open class AutoRecacheReadKeyValueRepo<Id, RegisteredObject>(
 | 
				
			|||||||
        originalRepo: ReadKeyValueRepo<Id, RegisteredObject>,
 | 
					        originalRepo: ReadKeyValueRepo<Id, RegisteredObject>,
 | 
				
			||||||
        scope: CoroutineScope,
 | 
					        scope: CoroutineScope,
 | 
				
			||||||
        originalCallTimeoutMillis: Long,
 | 
					        originalCallTimeoutMillis: Long,
 | 
				
			||||||
        kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache(),
 | 
					        kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo(),
 | 
				
			||||||
        recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
					        recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
				
			||||||
        idGetter: (RegisteredObject) -> Id
 | 
					        idGetter: (RegisteredObject) -> Id
 | 
				
			||||||
    ) : this(originalRepo, scope, kvCache, recacheDelay, ActionWrapper.Timeouted(originalCallTimeoutMillis), idGetter)
 | 
					    ) : this(originalRepo, scope, kvCache, recacheDelay, ActionWrapper.Timeouted(originalCallTimeoutMillis), idGetter)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,8 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.cache.fallback.keyvalue
 | 
					package dev.inmo.micro_utils.repos.cache.fallback.keyvalue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.inmo.micro_utils.coroutines.plus
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
 | 
					import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
 | 
				
			||||||
import dev.inmo.micro_utils.repos.WriteKeyValueRepo
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
 | 
					import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
 | 
				
			||||||
import dev.inmo.micro_utils.repos.set
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.unset
 | 
					 | 
				
			||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
import kotlinx.coroutines.flow.Flow
 | 
					import kotlinx.coroutines.flow.Flow
 | 
				
			||||||
import kotlinx.coroutines.flow.distinctUntilChanged
 | 
					import kotlinx.coroutines.flow.distinctUntilChanged
 | 
				
			||||||
@@ -14,7 +10,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged
 | 
				
			|||||||
open class AutoRecacheWriteKeyValueRepo<Id, RegisteredObject>(
 | 
					open class AutoRecacheWriteKeyValueRepo<Id, RegisteredObject>(
 | 
				
			||||||
    protected val originalRepo: WriteKeyValueRepo<Id, RegisteredObject>,
 | 
					    protected val originalRepo: WriteKeyValueRepo<Id, RegisteredObject>,
 | 
				
			||||||
    protected val scope: CoroutineScope,
 | 
					    protected val scope: CoroutineScope,
 | 
				
			||||||
    protected val kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache()
 | 
					    protected val kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo()
 | 
				
			||||||
) : WriteKeyValueRepo<Id, RegisteredObject>, FallbackCacheRepo {
 | 
					) : WriteKeyValueRepo<Id, RegisteredObject>, FallbackCacheRepo {
 | 
				
			||||||
    override val onValueRemoved: Flow<Id>
 | 
					    override val onValueRemoved: Flow<Id>
 | 
				
			||||||
        get() = (originalRepo.onValueRemoved).distinctUntilChanged()
 | 
					        get() = (originalRepo.onValueRemoved).distinctUntilChanged()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,9 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.cache.fallback.keyvalues
 | 
					package dev.inmo.micro_utils.repos.cache.fallback.keyvalues
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.KeyValueRepo
 | 
				
			||||||
import dev.inmo.micro_utils.repos.KeyValuesRepo
 | 
					import dev.inmo.micro_utils.repos.KeyValuesRepo
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.MapKeyValueRepo
 | 
				
			||||||
import dev.inmo.micro_utils.repos.WriteKeyValuesRepo
 | 
					import dev.inmo.micro_utils.repos.WriteKeyValuesRepo
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
 | 
					import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
 | 
				
			||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
import kotlin.time.Duration.Companion.seconds
 | 
					import kotlin.time.Duration.Companion.seconds
 | 
				
			||||||
@@ -10,7 +11,7 @@ import kotlin.time.Duration.Companion.seconds
 | 
				
			|||||||
open class AutoRecacheKeyValuesRepo<Id, RegisteredObject>(
 | 
					open class AutoRecacheKeyValuesRepo<Id, RegisteredObject>(
 | 
				
			||||||
    override val originalRepo: KeyValuesRepo<Id, RegisteredObject>,
 | 
					    override val originalRepo: KeyValuesRepo<Id, RegisteredObject>,
 | 
				
			||||||
    scope: CoroutineScope,
 | 
					    scope: CoroutineScope,
 | 
				
			||||||
    kvCache: FullKVCache<Id, List<RegisteredObject>> = FullKVCache(),
 | 
					    kvCache: KeyValueRepo<Id, List<RegisteredObject>> = MapKeyValueRepo(),
 | 
				
			||||||
    recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
					    recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
				
			||||||
    actionWrapper: ActionWrapper = ActionWrapper.Direct
 | 
					    actionWrapper: ActionWrapper = ActionWrapper.Direct
 | 
				
			||||||
) : AutoRecacheReadKeyValuesRepo<Id, RegisteredObject> (
 | 
					) : AutoRecacheReadKeyValuesRepo<Id, RegisteredObject> (
 | 
				
			||||||
@@ -27,7 +28,7 @@ open class AutoRecacheKeyValuesRepo<Id, RegisteredObject>(
 | 
				
			|||||||
        originalRepo: KeyValuesRepo<Id, RegisteredObject>,
 | 
					        originalRepo: KeyValuesRepo<Id, RegisteredObject>,
 | 
				
			||||||
        scope: CoroutineScope,
 | 
					        scope: CoroutineScope,
 | 
				
			||||||
        originalCallTimeoutMillis: Long,
 | 
					        originalCallTimeoutMillis: Long,
 | 
				
			||||||
        kvCache: FullKVCache<Id, List<RegisteredObject>> = FullKVCache(),
 | 
					        kvCache: KeyValueRepo<Id, List<RegisteredObject>> = MapKeyValueRepo(),
 | 
				
			||||||
        recacheDelay: Long = 60.seconds.inWholeMilliseconds
 | 
					        recacheDelay: Long = 60.seconds.inWholeMilliseconds
 | 
				
			||||||
    ) : this(originalRepo, scope, kvCache, recacheDelay, ActionWrapper.Timeouted(originalCallTimeoutMillis))
 | 
					    ) : this(originalRepo, scope, kvCache, recacheDelay, ActionWrapper.Timeouted(originalCallTimeoutMillis))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,8 +10,9 @@ import dev.inmo.micro_utils.pagination.firstIndex
 | 
				
			|||||||
import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging
 | 
					import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.utils.optionallyReverse
 | 
					import dev.inmo.micro_utils.pagination.utils.optionallyReverse
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.utils.paginate
 | 
					import dev.inmo.micro_utils.pagination.utils.paginate
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.KeyValueRepo
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.MapKeyValueRepo
 | 
				
			||||||
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
 | 
					import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
 | 
					import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
					import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
 | 
					import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
 | 
				
			||||||
@@ -25,7 +26,7 @@ import kotlin.time.Duration.Companion.seconds
 | 
				
			|||||||
open class AutoRecacheReadKeyValuesRepo<Id, RegisteredObject>(
 | 
					open class AutoRecacheReadKeyValuesRepo<Id, RegisteredObject>(
 | 
				
			||||||
    protected open val originalRepo: ReadKeyValuesRepo<Id, RegisteredObject>,
 | 
					    protected open val originalRepo: ReadKeyValuesRepo<Id, RegisteredObject>,
 | 
				
			||||||
    protected val scope: CoroutineScope,
 | 
					    protected val scope: CoroutineScope,
 | 
				
			||||||
    protected val kvCache: FullKVCache<Id, List<RegisteredObject>> = FullKVCache(),
 | 
					    protected val kvCache: KeyValueRepo<Id, List<RegisteredObject>> = MapKeyValueRepo(),
 | 
				
			||||||
    protected val recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
					    protected val recacheDelay: Long = 60.seconds.inWholeMilliseconds,
 | 
				
			||||||
    protected val actionWrapper: ActionWrapper = ActionWrapper.Direct
 | 
					    protected val actionWrapper: ActionWrapper = ActionWrapper.Direct
 | 
				
			||||||
) : ReadKeyValuesRepo<Id, RegisteredObject>, FallbackCacheRepo {
 | 
					) : ReadKeyValuesRepo<Id, RegisteredObject>, FallbackCacheRepo {
 | 
				
			||||||
@@ -41,7 +42,7 @@ open class AutoRecacheReadKeyValuesRepo<Id, RegisteredObject>(
 | 
				
			|||||||
        originalRepo: ReadKeyValuesRepo<Id, RegisteredObject>,
 | 
					        originalRepo: ReadKeyValuesRepo<Id, RegisteredObject>,
 | 
				
			||||||
        scope: CoroutineScope,
 | 
					        scope: CoroutineScope,
 | 
				
			||||||
        originalCallTimeoutMillis: Long,
 | 
					        originalCallTimeoutMillis: Long,
 | 
				
			||||||
        kvCache: FullKVCache<Id, List<RegisteredObject>> = FullKVCache(),
 | 
					        kvCache: KeyValueRepo<Id, List<RegisteredObject>> = MapKeyValueRepo(),
 | 
				
			||||||
        recacheDelay: Long = 60.seconds.inWholeMilliseconds
 | 
					        recacheDelay: Long = 60.seconds.inWholeMilliseconds
 | 
				
			||||||
    ) : this(originalRepo, scope, kvCache, recacheDelay, ActionWrapper.Timeouted(originalCallTimeoutMillis))
 | 
					    ) : this(originalRepo, scope, kvCache, recacheDelay, ActionWrapper.Timeouted(originalCallTimeoutMillis))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +1,10 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.cache.fallback.keyvalues
 | 
					package dev.inmo.micro_utils.repos.cache.fallback.keyvalues
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.inmo.micro_utils.coroutines.plus
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
 | 
					import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.FirstPagePagination
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging
 | 
					import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging
 | 
				
			||||||
import dev.inmo.micro_utils.repos.WriteKeyValuesRepo
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
 | 
					import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
 | 
				
			||||||
import dev.inmo.micro_utils.repos.pagination.maxPagePagination
 | 
					import dev.inmo.micro_utils.repos.pagination.maxPagePagination
 | 
				
			||||||
import dev.inmo.micro_utils.repos.set
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.unset
 | 
					 | 
				
			||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
import kotlinx.coroutines.flow.Flow
 | 
					import kotlinx.coroutines.flow.Flow
 | 
				
			||||||
import kotlinx.coroutines.flow.distinctUntilChanged
 | 
					import kotlinx.coroutines.flow.distinctUntilChanged
 | 
				
			||||||
@@ -17,7 +12,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged
 | 
				
			|||||||
open class AutoRecacheWriteKeyValuesRepo<Id, RegisteredObject>(
 | 
					open class AutoRecacheWriteKeyValuesRepo<Id, RegisteredObject>(
 | 
				
			||||||
    protected val originalRepo: WriteKeyValuesRepo<Id, RegisteredObject>,
 | 
					    protected val originalRepo: WriteKeyValuesRepo<Id, RegisteredObject>,
 | 
				
			||||||
    protected val scope: CoroutineScope,
 | 
					    protected val scope: CoroutineScope,
 | 
				
			||||||
    protected val kvCache: FullKVCache<Id, List<RegisteredObject>> = FullKVCache()
 | 
					    protected val kvCache: KeyValueRepo<Id, List<RegisteredObject>> = MapKeyValueRepo()
 | 
				
			||||||
) : WriteKeyValuesRepo<Id, RegisteredObject>, FallbackCacheRepo {
 | 
					) : WriteKeyValuesRepo<Id, RegisteredObject>, FallbackCacheRepo {
 | 
				
			||||||
    override val onValueRemoved: Flow<Pair<Id, RegisteredObject>>
 | 
					    override val onValueRemoved: Flow<Pair<Id, RegisteredObject>>
 | 
				
			||||||
        get() = originalRepo.onValueRemoved
 | 
					        get() = originalRepo.onValueRemoved
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,38 +1,39 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.cache.full
 | 
					package dev.inmo.micro_utils.repos.cache.full
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.inmo.micro_utils.common.*
 | 
					import dev.inmo.micro_utils.common.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.SmartRWLocker
 | 
				
			||||||
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
 | 
					import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.withReadAcquire
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.withWriteLock
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.Pagination
 | 
					import dev.inmo.micro_utils.pagination.Pagination
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.PaginationResult
 | 
					import dev.inmo.micro_utils.pagination.PaginationResult
 | 
				
			||||||
import dev.inmo.micro_utils.repos.*
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.*
 | 
					import dev.inmo.micro_utils.repos.cache.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
					import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
				
			||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
import kotlinx.coroutines.Dispatchers
 | 
					import kotlinx.coroutines.Dispatchers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
open class FullReadCRUDCacheRepo<ObjectType, IdType>(
 | 
					open class FullReadCRUDCacheRepo<ObjectType, IdType>(
 | 
				
			||||||
    protected open val parentRepo: ReadCRUDRepo<ObjectType, IdType>,
 | 
					    protected open val parentRepo: ReadCRUDRepo<ObjectType, IdType>,
 | 
				
			||||||
    protected open val kvCache: FullKVCache<IdType, ObjectType>,
 | 
					    protected open val kvCache: KeyValueRepo<IdType, ObjectType>,
 | 
				
			||||||
 | 
					    protected val locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
    protected open val idGetter: (ObjectType) -> IdType
 | 
					    protected open val idGetter: (ObjectType) -> IdType
 | 
				
			||||||
) : ReadCRUDRepo<ObjectType, IdType>, FullCacheRepo {
 | 
					) : ReadCRUDRepo<ObjectType, IdType>, FullCacheRepo {
 | 
				
			||||||
    protected inline fun <T> doOrTakeAndActualize(
 | 
					    protected suspend inline fun <T> doOrTakeAndActualize(
 | 
				
			||||||
        action: FullKVCache<IdType, ObjectType>.() -> Optional<T>,
 | 
					        action: KeyValueRepo<IdType, ObjectType>.() -> Optional<T>,
 | 
				
			||||||
        actionElse: ReadCRUDRepo<ObjectType, IdType>.() -> T,
 | 
					        actionElse: ReadCRUDRepo<ObjectType, IdType>.() -> T,
 | 
				
			||||||
        actualize: FullKVCache<IdType, ObjectType>.(T) -> Unit
 | 
					        actualize: KeyValueRepo<IdType, ObjectType>.(T) -> Unit
 | 
				
			||||||
    ): T {
 | 
					    ): T {
 | 
				
			||||||
        kvCache.action().onPresented {
 | 
					        locker.withReadAcquire {
 | 
				
			||||||
            return it
 | 
					            kvCache.action().onPresented { return it }
 | 
				
			||||||
        }.onAbsent {
 | 
					        }
 | 
				
			||||||
            return parentRepo.actionElse().also {
 | 
					        return parentRepo.actionElse().also {
 | 
				
			||||||
                kvCache.actualize(it)
 | 
					            locker.withWriteLock { kvCache.actualize(it) }
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        error("The result should be returned above")
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected open suspend fun actualizeAll() {
 | 
					    protected open suspend fun actualizeAll() {
 | 
				
			||||||
        kvCache.actualizeAll(parentRepo)
 | 
					        locker.withWriteLock { kvCache.actualizeAll(parentRepo) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> = doOrTakeAndActualize(
 | 
					    override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> = doOrTakeAndActualize(
 | 
				
			||||||
@@ -77,25 +78,29 @@ open class FullReadCRUDCacheRepo<ObjectType, IdType>(
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <ObjectType, IdType> ReadCRUDRepo<ObjectType, IdType>.cached(
 | 
					fun <ObjectType, IdType> ReadCRUDRepo<ObjectType, IdType>.cached(
 | 
				
			||||||
    kvCache: FullKVCache<IdType, ObjectType>,
 | 
					    kvCache: KeyValueRepo<IdType, ObjectType>,
 | 
				
			||||||
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
    idGetter: (ObjectType) -> IdType
 | 
					    idGetter: (ObjectType) -> IdType
 | 
				
			||||||
) = FullReadCRUDCacheRepo(this, kvCache, idGetter)
 | 
					) = FullReadCRUDCacheRepo(this, kvCache, locker, idGetter)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
open class FullCRUDCacheRepo<ObjectType, IdType, InputValueType>(
 | 
					open class FullCRUDCacheRepo<ObjectType, IdType, InputValueType>(
 | 
				
			||||||
    override val parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>,
 | 
					    override val parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>,
 | 
				
			||||||
    kvCache: FullKVCache<IdType, ObjectType>,
 | 
					    kvCache: KeyValueRepo<IdType, ObjectType>,
 | 
				
			||||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
				
			||||||
    skipStartInvalidate: Boolean = false,
 | 
					    skipStartInvalidate: Boolean = false,
 | 
				
			||||||
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
    idGetter: (ObjectType) -> IdType
 | 
					    idGetter: (ObjectType) -> IdType
 | 
				
			||||||
) : FullReadCRUDCacheRepo<ObjectType, IdType>(
 | 
					) : FullReadCRUDCacheRepo<ObjectType, IdType>(
 | 
				
			||||||
    parentRepo,
 | 
					    parentRepo,
 | 
				
			||||||
    kvCache,
 | 
					    kvCache,
 | 
				
			||||||
 | 
					    locker,
 | 
				
			||||||
    idGetter
 | 
					    idGetter
 | 
				
			||||||
),
 | 
					),
 | 
				
			||||||
    WriteCRUDRepo<ObjectType, IdType, InputValueType> by WriteCRUDCacheRepo(
 | 
					    WriteCRUDRepo<ObjectType, IdType, InputValueType> by WriteCRUDCacheRepo(
 | 
				
			||||||
        parentRepo,
 | 
					        parentRepo,
 | 
				
			||||||
        kvCache,
 | 
					        kvCache,
 | 
				
			||||||
        scope,
 | 
					        scope,
 | 
				
			||||||
 | 
					        locker,
 | 
				
			||||||
        idGetter
 | 
					        idGetter
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
    CRUDRepo<ObjectType, IdType, InputValueType> {
 | 
					    CRUDRepo<ObjectType, IdType, InputValueType> {
 | 
				
			||||||
@@ -111,16 +116,18 @@ open class FullCRUDCacheRepo<ObjectType, IdType, InputValueType>(
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.fullyCached(
 | 
					fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.fullyCached(
 | 
				
			||||||
    kvCache: FullKVCache<IdType, ObjectType> = FullKVCache(),
 | 
					    kvCache: KeyValueRepo<IdType, ObjectType> = MapKeyValueRepo(),
 | 
				
			||||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
				
			||||||
    skipStartInvalidate: Boolean = false,
 | 
					    skipStartInvalidate: Boolean = false,
 | 
				
			||||||
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
    idGetter: (ObjectType) -> IdType
 | 
					    idGetter: (ObjectType) -> IdType
 | 
				
			||||||
) = FullCRUDCacheRepo(this, kvCache, scope, skipStartInvalidate, idGetter)
 | 
					) = FullCRUDCacheRepo(this, kvCache, scope, skipStartInvalidate, locker, idGetter)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Deprecated("Renamed", ReplaceWith("this.fullyCached(kvCache, scope, idGetter)", "dev.inmo.micro_utils.repos.cache.full.fullyCached"))
 | 
					@Deprecated("Renamed", ReplaceWith("this.fullyCached(kvCache, scope, idGetter)", "dev.inmo.micro_utils.repos.cache.full.fullyCached"))
 | 
				
			||||||
fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.cached(
 | 
					fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.cached(
 | 
				
			||||||
    kvCache: FullKVCache<IdType, ObjectType>,
 | 
					    kvCache: KeyValueRepo<IdType, ObjectType>,
 | 
				
			||||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
				
			||||||
    skipStartInvalidate: Boolean = false,
 | 
					    skipStartInvalidate: Boolean = false,
 | 
				
			||||||
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
    idGetter: (ObjectType) -> IdType
 | 
					    idGetter: (ObjectType) -> IdType
 | 
				
			||||||
) = fullyCached(kvCache, scope, skipStartInvalidate, idGetter)
 | 
					) = fullyCached(kvCache, scope, skipStartInvalidate, locker, idGetter)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,13 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.cache.full
 | 
					package dev.inmo.micro_utils.repos.cache.full
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.inmo.micro_utils.common.*
 | 
					import dev.inmo.micro_utils.common.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.SmartRWLocker
 | 
				
			||||||
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
 | 
					import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.withReadAcquire
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.withWriteLock
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.Pagination
 | 
					import dev.inmo.micro_utils.pagination.Pagination
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.PaginationResult
 | 
					import dev.inmo.micro_utils.pagination.PaginationResult
 | 
				
			||||||
import dev.inmo.micro_utils.repos.*
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
					import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
				
			||||||
import dev.inmo.micro_utils.repos.pagination.getAll
 | 
					import dev.inmo.micro_utils.repos.pagination.getAll
 | 
				
			||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
@@ -14,25 +16,26 @@ import kotlinx.coroutines.flow.*
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
open class FullReadKeyValueCacheRepo<Key,Value>(
 | 
					open class FullReadKeyValueCacheRepo<Key,Value>(
 | 
				
			||||||
    protected open val parentRepo: ReadKeyValueRepo<Key, Value>,
 | 
					    protected open val parentRepo: ReadKeyValueRepo<Key, Value>,
 | 
				
			||||||
    protected open val kvCache: FullKVCache<Key, Value>,
 | 
					    protected open val kvCache: KeyValueRepo<Key, Value>,
 | 
				
			||||||
 | 
					    protected val locker: SmartRWLocker = SmartRWLocker()
 | 
				
			||||||
) : ReadKeyValueRepo<Key, Value>, FullCacheRepo {
 | 
					) : ReadKeyValueRepo<Key, Value>, FullCacheRepo {
 | 
				
			||||||
    protected inline fun <T> doOrTakeAndActualize(
 | 
					    protected suspend inline fun <T> doOrTakeAndActualize(
 | 
				
			||||||
        action: FullKVCache<Key, Value>.() -> Optional<T>,
 | 
					        action: KeyValueRepo<Key, Value>.() -> Optional<T>,
 | 
				
			||||||
        actionElse: ReadKeyValueRepo<Key, Value>.() -> T,
 | 
					        actionElse: ReadKeyValueRepo<Key, Value>.() -> T,
 | 
				
			||||||
        actualize: FullKVCache<Key, Value>.(T) -> Unit
 | 
					        actualize: KeyValueRepo<Key, Value>.(T) -> Unit
 | 
				
			||||||
    ): T {
 | 
					    ): T {
 | 
				
			||||||
        kvCache.action().onPresented {
 | 
					        locker.withReadAcquire {
 | 
				
			||||||
            return it
 | 
					            kvCache.action().onPresented { return it }
 | 
				
			||||||
        }.onAbsent {
 | 
					        }
 | 
				
			||||||
            return parentRepo.actionElse().also {
 | 
					        return parentRepo.actionElse().also {
 | 
				
			||||||
                kvCache.actualize(it)
 | 
					            locker.withWriteLock { kvCache.actualize(it) }
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        error("The result should be returned above")
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    protected open suspend fun actualizeAll() {
 | 
					    protected open suspend fun actualizeAll() {
 | 
				
			||||||
        kvCache.clear()
 | 
					        locker.withWriteLock {
 | 
				
			||||||
        kvCache.set(parentRepo.getAll { keys(it) }.toMap())
 | 
					            kvCache.clear()
 | 
				
			||||||
 | 
					            kvCache.set(parentRepo.getAll { keys(it) }.toMap())
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun get(k: Key): Value? = doOrTakeAndActualize(
 | 
					    override suspend fun get(k: Key): Value? = doOrTakeAndActualize(
 | 
				
			||||||
@@ -83,37 +86,51 @@ open class FullReadKeyValueCacheRepo<Key,Value>(
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <Key, Value> ReadKeyValueRepo<Key, Value>.cached(
 | 
					fun <Key, Value> ReadKeyValueRepo<Key, Value>.cached(
 | 
				
			||||||
    kvCache: FullKVCache<Key, Value>
 | 
					    kvCache: KeyValueRepo<Key, Value>,
 | 
				
			||||||
) = FullReadKeyValueCacheRepo(this, kvCache)
 | 
					    locker: SmartRWLocker = SmartRWLocker()
 | 
				
			||||||
 | 
					) = FullReadKeyValueCacheRepo(this, kvCache, locker)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
open class FullWriteKeyValueCacheRepo<Key,Value>(
 | 
					open class FullWriteKeyValueCacheRepo<Key,Value>(
 | 
				
			||||||
    parentRepo: WriteKeyValueRepo<Key, Value>,
 | 
					    parentRepo: WriteKeyValueRepo<Key, Value>,
 | 
				
			||||||
    protected open val kvCache: FullKVCache<Key, Value>,
 | 
					    protected open val kvCache: KeyValueRepo<Key, Value>,
 | 
				
			||||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
				
			||||||
 | 
					    protected val locker: SmartRWLocker = SmartRWLocker()
 | 
				
			||||||
) : WriteKeyValueRepo<Key, Value> by parentRepo, FullCacheRepo {
 | 
					) : WriteKeyValueRepo<Key, Value> by parentRepo, FullCacheRepo {
 | 
				
			||||||
    protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, it.second) }.launchIn(scope)
 | 
					    protected val onNewJob = parentRepo.onNewValue.onEach {
 | 
				
			||||||
    protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.unset(it) }.launchIn(scope)
 | 
					        locker.withWriteLock {
 | 
				
			||||||
 | 
					            kvCache.set(it.first, it.second)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }.launchIn(scope)
 | 
				
			||||||
 | 
					    protected val onRemoveJob = parentRepo.onValueRemoved.onEach {
 | 
				
			||||||
 | 
					        locker.withWriteLock {
 | 
				
			||||||
 | 
					            kvCache.unset(it)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }.launchIn(scope)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun invalidate() {
 | 
					    override suspend fun invalidate() {
 | 
				
			||||||
        kvCache.clear()
 | 
					        locker.withWriteLock {
 | 
				
			||||||
 | 
					            kvCache.clear()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <Key, Value> WriteKeyValueRepo<Key, Value>.caching(
 | 
					fun <Key, Value> WriteKeyValueRepo<Key, Value>.caching(
 | 
				
			||||||
    kvCache: FullKVCache<Key, Value>,
 | 
					    kvCache: KeyValueRepo<Key, Value>,
 | 
				
			||||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
				
			||||||
) = FullWriteKeyValueCacheRepo(this, kvCache, scope)
 | 
					) = FullWriteKeyValueCacheRepo(this, kvCache, scope)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
open class FullKeyValueCacheRepo<Key,Value>(
 | 
					open class FullKeyValueCacheRepo<Key,Value>(
 | 
				
			||||||
    protected open val parentRepo: KeyValueRepo<Key, Value>,
 | 
					    protected open val parentRepo: KeyValueRepo<Key, Value>,
 | 
				
			||||||
    kvCache: FullKVCache<Key, Value>,
 | 
					    kvCache: KeyValueRepo<Key, Value>,
 | 
				
			||||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
				
			||||||
    skipStartInvalidate: Boolean = false
 | 
					    skipStartInvalidate: Boolean = false,
 | 
				
			||||||
 | 
					    locker: SmartRWLocker = SmartRWLocker()
 | 
				
			||||||
) : FullWriteKeyValueCacheRepo<Key,Value>(parentRepo, kvCache, scope),
 | 
					) : FullWriteKeyValueCacheRepo<Key,Value>(parentRepo, kvCache, scope),
 | 
				
			||||||
    KeyValueRepo<Key,Value>,
 | 
					    KeyValueRepo<Key,Value>,
 | 
				
			||||||
    ReadKeyValueRepo<Key, Value> by FullReadKeyValueCacheRepo(
 | 
					    ReadKeyValueRepo<Key, Value> by FullReadKeyValueCacheRepo(
 | 
				
			||||||
        parentRepo,
 | 
					        parentRepo,
 | 
				
			||||||
        kvCache
 | 
					        kvCache,
 | 
				
			||||||
 | 
					        locker
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    init {
 | 
					    init {
 | 
				
			||||||
        if (!skipStartInvalidate) {
 | 
					        if (!skipStartInvalidate) {
 | 
				
			||||||
@@ -124,7 +141,9 @@ open class FullKeyValueCacheRepo<Key,Value>(
 | 
				
			|||||||
    override suspend fun unsetWithValues(toUnset: List<Value>) = parentRepo.unsetWithValues(toUnset)
 | 
					    override suspend fun unsetWithValues(toUnset: List<Value>) = parentRepo.unsetWithValues(toUnset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun invalidate() {
 | 
					    override suspend fun invalidate() {
 | 
				
			||||||
        kvCache.actualizeAll(parentRepo)
 | 
					        locker.withWriteLock {
 | 
				
			||||||
 | 
					            kvCache.actualizeAll(parentRepo)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun clear() {
 | 
					    override suspend fun clear() {
 | 
				
			||||||
@@ -134,12 +153,16 @@ open class FullKeyValueCacheRepo<Key,Value>(
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <Key, Value> KeyValueRepo<Key, Value>.fullyCached(
 | 
					fun <Key, Value> KeyValueRepo<Key, Value>.fullyCached(
 | 
				
			||||||
    kvCache: FullKVCache<Key, Value> = FullKVCache(),
 | 
					    kvCache: KeyValueRepo<Key, Value> = MapKeyValueRepo(),
 | 
				
			||||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
				
			||||||
) = FullKeyValueCacheRepo(this, kvCache, scope)
 | 
					    skipStartInvalidate: Boolean = false,
 | 
				
			||||||
 | 
					    locker: SmartRWLocker = SmartRWLocker()
 | 
				
			||||||
 | 
					) = FullKeyValueCacheRepo(this, kvCache, scope, skipStartInvalidate, locker)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Deprecated("Renamed", ReplaceWith("this.fullyCached(kvCache, scope)", "dev.inmo.micro_utils.repos.cache.full.fullyCached"))
 | 
					@Deprecated("Renamed", ReplaceWith("this.fullyCached(kvCache, scope)", "dev.inmo.micro_utils.repos.cache.full.fullyCached"))
 | 
				
			||||||
fun <Key, Value> KeyValueRepo<Key, Value>.cached(
 | 
					fun <Key, Value> KeyValueRepo<Key, Value>.cached(
 | 
				
			||||||
    kvCache: FullKVCache<Key, Value>,
 | 
					    kvCache: KeyValueRepo<Key, Value>,
 | 
				
			||||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
				
			||||||
) = fullyCached(kvCache, scope)
 | 
					    skipStartInvalidate: Boolean = false,
 | 
				
			||||||
 | 
					    locker: SmartRWLocker = SmartRWLocker()
 | 
				
			||||||
 | 
					) = fullyCached(kvCache, scope, skipStartInvalidate, locker)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,13 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.cache.full
 | 
					package dev.inmo.micro_utils.repos.cache.full
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.inmo.micro_utils.common.*
 | 
					import dev.inmo.micro_utils.common.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.SmartRWLocker
 | 
				
			||||||
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
 | 
					import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.withReadAcquire
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.withWriteLock
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.*
 | 
					import dev.inmo.micro_utils.pagination.*
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.utils.*
 | 
					import dev.inmo.micro_utils.pagination.utils.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.*
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
					import dev.inmo.micro_utils.repos.cache.util.actualizeAll
 | 
				
			||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
import kotlinx.coroutines.Dispatchers
 | 
					import kotlinx.coroutines.Dispatchers
 | 
				
			||||||
@@ -13,29 +15,32 @@ import kotlinx.coroutines.flow.*
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
open class FullReadKeyValuesCacheRepo<Key,Value>(
 | 
					open class FullReadKeyValuesCacheRepo<Key,Value>(
 | 
				
			||||||
    protected open val parentRepo: ReadKeyValuesRepo<Key, Value>,
 | 
					    protected open val parentRepo: ReadKeyValuesRepo<Key, Value>,
 | 
				
			||||||
    protected open val kvCache: FullKVCache<Key, List<Value>>,
 | 
					    protected open val kvCache: KeyValueRepo<Key, List<Value>>,
 | 
				
			||||||
 | 
					    protected val locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
) : ReadKeyValuesRepo<Key, Value>, FullCacheRepo {
 | 
					) : ReadKeyValuesRepo<Key, Value>, FullCacheRepo {
 | 
				
			||||||
    protected inline fun <T> doOrTakeAndActualize(
 | 
					    protected suspend inline fun <T> doOrTakeAndActualize(
 | 
				
			||||||
        action: FullKVCache<Key, List<Value>>.() -> Optional<T>,
 | 
					        action: KeyValueRepo<Key, List<Value>>.() -> Optional<T>,
 | 
				
			||||||
        actionElse: ReadKeyValuesRepo<Key, Value>.() -> T,
 | 
					        actionElse: ReadKeyValuesRepo<Key, Value>.() -> T,
 | 
				
			||||||
        actualize: FullKVCache<Key, List<Value>>.(T) -> Unit
 | 
					        actualize: KeyValueRepo<Key, List<Value>>.(T) -> Unit
 | 
				
			||||||
    ): T {
 | 
					    ): T {
 | 
				
			||||||
        kvCache.action().onPresented {
 | 
					        locker.withReadAcquire {
 | 
				
			||||||
            return it
 | 
					            kvCache.action().onPresented { return it }
 | 
				
			||||||
        }.onAbsent {
 | 
					        }
 | 
				
			||||||
            return parentRepo.actionElse().also {
 | 
					        return parentRepo.actionElse().also {
 | 
				
			||||||
                kvCache.actualize(it)
 | 
					            locker.withWriteLock { kvCache.actualize(it) }
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        error("The result should be returned above")
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected open suspend fun actualizeKey(k: Key) {
 | 
					    protected open suspend fun actualizeKey(k: Key) {
 | 
				
			||||||
        kvCache.set(k, parentRepo.getAll(k))
 | 
					        locker.withWriteLock {
 | 
				
			||||||
 | 
					            kvCache.set(k, parentRepo.getAll(k))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected open suspend fun actualizeAll() {
 | 
					    protected open suspend fun actualizeAll() {
 | 
				
			||||||
        kvCache.actualizeAll(parentRepo)
 | 
					        locker.withWriteLock {
 | 
				
			||||||
 | 
					            kvCache.actualizeAll(parentRepo)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
 | 
					    override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
 | 
				
			||||||
@@ -109,45 +114,55 @@ open class FullReadKeyValuesCacheRepo<Key,Value>(
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <Key, Value> ReadKeyValuesRepo<Key, Value>.cached(
 | 
					fun <Key, Value> ReadKeyValuesRepo<Key, Value>.cached(
 | 
				
			||||||
    kvCache: FullKVCache<Key, List<Value>>
 | 
					    kvCache: KeyValueRepo<Key, List<Value>>,
 | 
				
			||||||
) = FullReadKeyValuesCacheRepo(this, kvCache)
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
 | 
					) = FullReadKeyValuesCacheRepo(this, kvCache, locker)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
open class FullWriteKeyValuesCacheRepo<Key,Value>(
 | 
					open class FullWriteKeyValuesCacheRepo<Key,Value>(
 | 
				
			||||||
    parentRepo: WriteKeyValuesRepo<Key, Value>,
 | 
					    parentRepo: WriteKeyValuesRepo<Key, Value>,
 | 
				
			||||||
    protected open val kvCache: FullKVCache<Key, List<Value>>,
 | 
					    protected open val kvCache: KeyValueRepo<Key, List<Value>>,
 | 
				
			||||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
				
			||||||
 | 
					    protected val locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
) : WriteKeyValuesRepo<Key, Value> by parentRepo, FullCacheRepo {
 | 
					) : WriteKeyValuesRepo<Key, Value> by parentRepo, FullCacheRepo {
 | 
				
			||||||
    protected val onNewJob = parentRepo.onNewValue.onEach {
 | 
					    protected val onNewJob = parentRepo.onNewValue.onEach {
 | 
				
			||||||
        kvCache.set(
 | 
					        locker.withWriteLock {
 | 
				
			||||||
            it.first,
 | 
					            kvCache.set(
 | 
				
			||||||
            kvCache.get(it.first) ?.plus(it.second) ?: listOf(it.second)
 | 
					                it.first,
 | 
				
			||||||
        )
 | 
					                kvCache.get(it.first) ?.plus(it.second) ?: listOf(it.second)
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }.launchIn(scope)
 | 
					    }.launchIn(scope)
 | 
				
			||||||
    protected val onRemoveJob = parentRepo.onValueRemoved.onEach {
 | 
					    protected val onRemoveJob = parentRepo.onValueRemoved.onEach {
 | 
				
			||||||
        kvCache.set(
 | 
					        locker.withWriteLock {
 | 
				
			||||||
            it.first,
 | 
					            kvCache.set(
 | 
				
			||||||
            kvCache.get(it.first) ?.minus(it.second) ?: return@onEach
 | 
					                it.first,
 | 
				
			||||||
        )
 | 
					                kvCache.get(it.first)?.minus(it.second) ?: return@onEach
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }.launchIn(scope)
 | 
					    }.launchIn(scope)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun invalidate() {
 | 
					    override suspend fun invalidate() {
 | 
				
			||||||
        kvCache.clear()
 | 
					        locker.withWriteLock {
 | 
				
			||||||
 | 
					            kvCache.clear()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <Key, Value> WriteKeyValuesRepo<Key, Value>.caching(
 | 
					fun <Key, Value> WriteKeyValuesRepo<Key, Value>.caching(
 | 
				
			||||||
    kvCache: FullKVCache<Key, List<Value>>,
 | 
					    kvCache: KeyValueRepo<Key, List<Value>>,
 | 
				
			||||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
				
			||||||
) = FullWriteKeyValuesCacheRepo(this, kvCache, scope)
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
 | 
					) = FullWriteKeyValuesCacheRepo(this, kvCache, scope, locker)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
open class FullKeyValuesCacheRepo<Key,Value>(
 | 
					open class FullKeyValuesCacheRepo<Key,Value>(
 | 
				
			||||||
    protected open val parentRepo: KeyValuesRepo<Key, Value>,
 | 
					    protected open val parentRepo: KeyValuesRepo<Key, Value>,
 | 
				
			||||||
    kvCache: FullKVCache<Key, List<Value>>,
 | 
					    kvCache: KeyValueRepo<Key, List<Value>>,
 | 
				
			||||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
				
			||||||
    skipStartInvalidate: Boolean = false
 | 
					    skipStartInvalidate: Boolean = false,
 | 
				
			||||||
) : FullWriteKeyValuesCacheRepo<Key, Value>(parentRepo, kvCache, scope),
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
 | 
					) : FullWriteKeyValuesCacheRepo<Key, Value>(parentRepo, kvCache, scope, locker),
 | 
				
			||||||
    KeyValuesRepo<Key, Value>,
 | 
					    KeyValuesRepo<Key, Value>,
 | 
				
			||||||
    ReadKeyValuesRepo<Key, Value> by FullReadKeyValuesCacheRepo(parentRepo, kvCache) {
 | 
					    ReadKeyValuesRepo<Key, Value> by FullReadKeyValuesCacheRepo(parentRepo, kvCache, locker) {
 | 
				
			||||||
    init {
 | 
					    init {
 | 
				
			||||||
        if (!skipStartInvalidate) {
 | 
					        if (!skipStartInvalidate) {
 | 
				
			||||||
            scope.launchSafelyWithoutExceptions { invalidate() }
 | 
					            scope.launchSafelyWithoutExceptions { invalidate() }
 | 
				
			||||||
@@ -163,7 +178,9 @@ open class FullKeyValuesCacheRepo<Key,Value>(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun invalidate() {
 | 
					    override suspend fun invalidate() {
 | 
				
			||||||
        kvCache.actualizeAll(parentRepo)
 | 
					        locker.withWriteLock {
 | 
				
			||||||
 | 
					            kvCache.actualizeAll(parentRepo)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun removeWithValue(v: Value) {
 | 
					    override suspend fun removeWithValue(v: Value) {
 | 
				
			||||||
@@ -172,12 +189,16 @@ open class FullKeyValuesCacheRepo<Key,Value>(
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <Key, Value> KeyValuesRepo<Key, Value>.fullyCached(
 | 
					fun <Key, Value> KeyValuesRepo<Key, Value>.fullyCached(
 | 
				
			||||||
    kvCache: FullKVCache<Key, List<Value>> = FullKVCache(),
 | 
					    kvCache: KeyValueRepo<Key, List<Value>> = MapKeyValueRepo(),
 | 
				
			||||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
				
			||||||
) = FullKeyValuesCacheRepo(this, kvCache, scope)
 | 
					    skipStartInvalidate: Boolean = false,
 | 
				
			||||||
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
 | 
					) = FullKeyValuesCacheRepo(this, kvCache, scope, skipStartInvalidate, locker)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Deprecated("Renamed", ReplaceWith("this.fullyCached(kvCache, scope)", "dev.inmo.micro_utils.repos.cache.full.fullyCached"))
 | 
					@Deprecated("Renamed", ReplaceWith("this.fullyCached(kvCache, scope)", "dev.inmo.micro_utils.repos.cache.full.fullyCached"))
 | 
				
			||||||
fun <Key, Value> KeyValuesRepo<Key, Value>.caching(
 | 
					fun <Key, Value> KeyValuesRepo<Key, Value>.caching(
 | 
				
			||||||
    kvCache: FullKVCache<Key, List<Value>>,
 | 
					    kvCache: KeyValueRepo<Key, List<Value>>,
 | 
				
			||||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
					    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 | 
				
			||||||
) = FullKeyValuesCacheRepo(this, kvCache, scope)
 | 
					    skipStartInvalidate: Boolean = false,
 | 
				
			||||||
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
 | 
					) = FullKeyValuesCacheRepo(this, kvCache, scope, skipStartInvalidate, locker)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,8 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.cache.util
 | 
					package dev.inmo.micro_utils.repos.cache.util
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.FirstPagePagination
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.pagination.utils.getAllByWithNextPaging
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.ReadCRUDRepo
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.cache.cache.KVCache
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.pagination.getAll
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.set
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
suspend inline fun <K, V> KVCache<K, V>.actualizeAll(
 | 
					suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAll(
 | 
				
			||||||
    clear: Boolean = true,
 | 
					    clear: Boolean = true,
 | 
				
			||||||
    getAll: () -> Map<K, V>
 | 
					    getAll: () -> Map<K, V>
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
@@ -23,7 +15,7 @@ suspend inline fun <K, V> KVCache<K, V>.actualizeAll(
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
suspend inline fun <K, V> KVCache<K, V>.actualizeAll(
 | 
					suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAll(
 | 
				
			||||||
    repo: ReadKeyValueRepo<K, V>,
 | 
					    repo: ReadKeyValueRepo<K, V>,
 | 
				
			||||||
    clear: Boolean = true,
 | 
					    clear: Boolean = true,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
@@ -32,7 +24,7 @@ suspend inline fun <K, V> KVCache<K, V>.actualizeAll(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
suspend inline fun <K, V> KVCache<K, List<V>>.actualizeAll(
 | 
					suspend inline fun <K, V> KeyValueRepo<K, List<V>>.actualizeAll(
 | 
				
			||||||
    repo: ReadKeyValuesRepo<K, V>,
 | 
					    repo: ReadKeyValuesRepo<K, V>,
 | 
				
			||||||
    clear: Boolean = true,
 | 
					    clear: Boolean = true,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
@@ -41,7 +33,7 @@ suspend inline fun <K, V> KVCache<K, List<V>>.actualizeAll(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
suspend inline fun <K, V> KVCache<K, V>.actualizeAll(
 | 
					suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAll(
 | 
				
			||||||
    repo: ReadCRUDRepo<V, K>,
 | 
					    repo: ReadCRUDRepo<V, K>,
 | 
				
			||||||
    clear: Boolean = true,
 | 
					    clear: Boolean = true,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,38 +1,55 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos
 | 
					package dev.inmo.micro_utils.repos
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.SmartRWLocker
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.withReadAcquire
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.withWriteLock
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.*
 | 
					import dev.inmo.micro_utils.pagination.*
 | 
				
			||||||
import kotlinx.coroutines.flow.*
 | 
					import kotlinx.coroutines.flow.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ReadMapCRUDRepo<ObjectType, IdType>(
 | 
					class ReadMapCRUDRepo<ObjectType, IdType>(
 | 
				
			||||||
    private val map: Map<IdType, ObjectType> = emptyMap()
 | 
					    private val map: Map<IdType, ObjectType> = emptyMap(),
 | 
				
			||||||
 | 
					    private val locker: SmartRWLocker = SmartRWLocker()
 | 
				
			||||||
) : ReadCRUDRepo<ObjectType, IdType> {
 | 
					) : ReadCRUDRepo<ObjectType, IdType> {
 | 
				
			||||||
    override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> {
 | 
					    override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> {
 | 
				
			||||||
        return map.keys.drop(pagination.firstIndex).take(pagination.size).mapNotNull {
 | 
					        return locker.withReadAcquire {
 | 
				
			||||||
            map[it]
 | 
					            map.keys.drop(pagination.firstIndex).take(pagination.size).mapNotNull {
 | 
				
			||||||
        }.createPaginationResult(
 | 
					                map[it]
 | 
				
			||||||
            pagination,
 | 
					            }.createPaginationResult(
 | 
				
			||||||
            count()
 | 
					                pagination,
 | 
				
			||||||
        )
 | 
					                count()
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun getIdsByPagination(pagination: Pagination): PaginationResult<IdType> {
 | 
					    override suspend fun getIdsByPagination(pagination: Pagination): PaginationResult<IdType> {
 | 
				
			||||||
        return map.keys.drop(pagination.firstIndex).take(pagination.size).createPaginationResult(
 | 
					        return locker.withReadAcquire {
 | 
				
			||||||
            pagination,
 | 
					            map.keys.drop(pagination.firstIndex).take(pagination.size).createPaginationResult(
 | 
				
			||||||
            count()
 | 
					                pagination,
 | 
				
			||||||
        )
 | 
					                count()
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun getById(id: IdType): ObjectType? = map[id]
 | 
					    override suspend fun getById(id: IdType): ObjectType? = locker.withReadAcquire {
 | 
				
			||||||
 | 
					        map[id]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun contains(id: IdType): Boolean = map.containsKey(id)
 | 
					    override suspend fun contains(id: IdType): Boolean = locker.withReadAcquire {
 | 
				
			||||||
 | 
					        map.containsKey(id)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun getAll(): Map<IdType, ObjectType> = map.toMap()
 | 
					    override suspend fun getAll(): Map<IdType, ObjectType> = locker.withReadAcquire {
 | 
				
			||||||
 | 
					        map.toMap()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun count(): Long = map.size.toLong()
 | 
					    override suspend fun count(): Long = locker.withReadAcquire {
 | 
				
			||||||
 | 
					        map.size.toLong()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
abstract class WriteMapCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
					abstract class WriteMapCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
				
			||||||
    protected val map: MutableMap<IdType, ObjectType> = mutableMapOf()
 | 
					    protected val map: MutableMap<IdType, ObjectType> = mutableMapOf(),
 | 
				
			||||||
 | 
					    protected val locker: SmartRWLocker = SmartRWLocker()
 | 
				
			||||||
) : WriteCRUDRepo<ObjectType, IdType, InputValueType> {
 | 
					) : WriteCRUDRepo<ObjectType, IdType, InputValueType> {
 | 
				
			||||||
    protected val _newObjectsFlow: MutableSharedFlow<ObjectType> = MutableSharedFlow()
 | 
					    protected val _newObjectsFlow: MutableSharedFlow<ObjectType> = MutableSharedFlow()
 | 
				
			||||||
    override val newObjectsFlow: Flow<ObjectType> = _newObjectsFlow.asSharedFlow()
 | 
					    override val newObjectsFlow: Flow<ObjectType> = _newObjectsFlow.asSharedFlow()
 | 
				
			||||||
@@ -45,21 +62,25 @@ abstract class WriteMapCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
				
			|||||||
    protected abstract suspend fun createObject(newValue: InputValueType): Pair<IdType, ObjectType>
 | 
					    protected abstract suspend fun createObject(newValue: InputValueType): Pair<IdType, ObjectType>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun create(values: List<InputValueType>): List<ObjectType> {
 | 
					    override suspend fun create(values: List<InputValueType>): List<ObjectType> {
 | 
				
			||||||
        return values.map {
 | 
					        return locker.withWriteLock {
 | 
				
			||||||
            val (id, newObject) = createObject(it)
 | 
					            values.map {
 | 
				
			||||||
            map[id] = newObject
 | 
					                val (id, newObject) = createObject(it)
 | 
				
			||||||
            newObject.also { _ ->
 | 
					                map[id] = newObject
 | 
				
			||||||
                _newObjectsFlow.emit(newObject)
 | 
					                newObject.also { _ ->
 | 
				
			||||||
 | 
					                    _newObjectsFlow.emit(newObject)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun update(id: IdType, value: InputValueType): ObjectType? {
 | 
					    override suspend fun update(id: IdType, value: InputValueType): ObjectType? {
 | 
				
			||||||
        val newValue = updateObject(value, id, map[id] ?: return null)
 | 
					        return locker.withWriteLock {
 | 
				
			||||||
 | 
					            val newValue = updateObject(value, id, map[id] ?: return@withWriteLock null)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return newValue.also {
 | 
					            newValue.also {
 | 
				
			||||||
            map[id] = it
 | 
					                map[id] = it
 | 
				
			||||||
            _updatedObjectsFlow.emit(it)
 | 
					                _updatedObjectsFlow.emit(it)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -68,24 +89,28 @@ abstract class WriteMapCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun deleteById(ids: List<IdType>) {
 | 
					    override suspend fun deleteById(ids: List<IdType>) {
 | 
				
			||||||
        ids.forEach {
 | 
					        locker.withWriteLock {
 | 
				
			||||||
            map.remove(it) ?.also { _ -> _deletedObjectsIdsFlow.emit(it) }
 | 
					            ids.forEach {
 | 
				
			||||||
 | 
					                map.remove(it) ?.also { _ -> _deletedObjectsIdsFlow.emit(it) }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
abstract class MapCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
					abstract class MapCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
				
			||||||
    map: MutableMap<IdType, ObjectType>
 | 
					    map: MutableMap<IdType, ObjectType>,
 | 
				
			||||||
 | 
					    locker: SmartRWLocker = SmartRWLocker()
 | 
				
			||||||
) : CRUDRepo<ObjectType, IdType, InputValueType>,
 | 
					) : CRUDRepo<ObjectType, IdType, InputValueType>,
 | 
				
			||||||
    ReadCRUDRepo<ObjectType, IdType> by ReadMapCRUDRepo(map),
 | 
					    ReadCRUDRepo<ObjectType, IdType> by ReadMapCRUDRepo(map, locker),
 | 
				
			||||||
    WriteMapCRUDRepo<ObjectType, IdType, InputValueType>(map)
 | 
					    WriteMapCRUDRepo<ObjectType, IdType, InputValueType>(map, locker)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <ObjectType, IdType, InputValueType> MapCRUDRepo(
 | 
					fun <ObjectType, IdType, InputValueType> MapCRUDRepo(
 | 
				
			||||||
    map: MutableMap<IdType, ObjectType>,
 | 
					    map: MutableMap<IdType, ObjectType>,
 | 
				
			||||||
    updateCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType,
 | 
					    updateCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType,
 | 
				
			||||||
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
    createCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType) -> Pair<IdType, ObjectType>
 | 
					    createCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType) -> Pair<IdType, ObjectType>
 | 
				
			||||||
) = object : MapCRUDRepo<ObjectType, IdType, InputValueType>(map) {
 | 
					) = object : MapCRUDRepo<ObjectType, IdType, InputValueType>(map, locker) {
 | 
				
			||||||
    override suspend fun updateObject(
 | 
					    override suspend fun updateObject(
 | 
				
			||||||
        newValue: InputValueType,
 | 
					        newValue: InputValueType,
 | 
				
			||||||
        id: IdType,
 | 
					        id: IdType,
 | 
				
			||||||
@@ -97,10 +122,12 @@ fun <ObjectType, IdType, InputValueType> MapCRUDRepo(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
fun <ObjectType, IdType, InputValueType> MapCRUDRepo(
 | 
					fun <ObjectType, IdType, InputValueType> MapCRUDRepo(
 | 
				
			||||||
    updateCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType,
 | 
					    updateCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType,
 | 
				
			||||||
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
    createCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType) -> Pair<IdType, ObjectType>
 | 
					    createCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType) -> Pair<IdType, ObjectType>
 | 
				
			||||||
) = MapCRUDRepo(mutableMapOf(), updateCallback, createCallback)
 | 
					) = MapCRUDRepo(mutableMapOf(), updateCallback, locker, createCallback)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <ObjectType, IdType, InputValueType> MutableMap<IdType, ObjectType>.asCrudRepo(
 | 
					fun <ObjectType, IdType, InputValueType> MutableMap<IdType, ObjectType>.asCrudRepo(
 | 
				
			||||||
    updateCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType,
 | 
					    updateCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType,
 | 
				
			||||||
 | 
					    locker: SmartRWLocker = SmartRWLocker(),
 | 
				
			||||||
    createCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType) -> Pair<IdType, ObjectType>
 | 
					    createCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType) -> Pair<IdType, ObjectType>
 | 
				
			||||||
) = MapCRUDRepo(this, updateCallback, createCallback)
 | 
					) = MapCRUDRepo(this, updateCallback, locker, createCallback)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,8 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos
 | 
					package dev.inmo.micro_utils.repos
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.SmartRWLocker
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.withReadAcquire
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.withWriteLock
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.Pagination
 | 
					import dev.inmo.micro_utils.pagination.Pagination
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.PaginationResult
 | 
					import dev.inmo.micro_utils.pagination.PaginationResult
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.utils.paginate
 | 
					import dev.inmo.micro_utils.pagination.utils.paginate
 | 
				
			||||||
@@ -8,58 +11,68 @@ import kotlinx.coroutines.flow.Flow
 | 
				
			|||||||
import kotlinx.coroutines.flow.MutableSharedFlow
 | 
					import kotlinx.coroutines.flow.MutableSharedFlow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ReadMapKeyValueRepo<Key, Value>(
 | 
					class ReadMapKeyValueRepo<Key, Value>(
 | 
				
			||||||
    protected val map: Map<Key, Value> = emptyMap()
 | 
					    protected val map: Map<Key, Value>,
 | 
				
			||||||
 | 
					    private val locker: SmartRWLocker
 | 
				
			||||||
) : ReadKeyValueRepo<Key, Value> {
 | 
					) : ReadKeyValueRepo<Key, Value> {
 | 
				
			||||||
    override suspend fun get(k: Key): Value? = map[k]
 | 
					    constructor(map: Map<Key, Value> = emptyMap()) : this(map, SmartRWLocker())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override suspend fun get(k: Key): Value? = locker.withReadAcquire { map[k] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun values(
 | 
					    override suspend fun values(
 | 
				
			||||||
        pagination: Pagination,
 | 
					        pagination: Pagination,
 | 
				
			||||||
        reversed: Boolean
 | 
					        reversed: Boolean
 | 
				
			||||||
    ): PaginationResult<Value> {
 | 
					    ): PaginationResult<Value> {
 | 
				
			||||||
        val values = map.values
 | 
					        return locker.withReadAcquire {
 | 
				
			||||||
        val actualPagination = if (reversed) pagination.reverse(values.size) else pagination
 | 
					            val values = map.values
 | 
				
			||||||
        return values.paginate(actualPagination).let {
 | 
					            val actualPagination = if (reversed) pagination.reverse(values.size) else pagination
 | 
				
			||||||
            if (reversed) {
 | 
					            values.paginate(actualPagination).let {
 | 
				
			||||||
                it.copy(results = it.results.reversed())
 | 
					                if (reversed) {
 | 
				
			||||||
            } else {
 | 
					                    it.copy(results = it.results.reversed())
 | 
				
			||||||
                it
 | 
					                } else {
 | 
				
			||||||
 | 
					                    it
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> {
 | 
					    override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> {
 | 
				
			||||||
        val keys = map.keys
 | 
					        return locker.withReadAcquire {
 | 
				
			||||||
        val actualPagination = if (reversed) pagination.reverse(keys.size) else pagination
 | 
					            val keys = map.keys
 | 
				
			||||||
        return keys.paginate(actualPagination).let {
 | 
					            val actualPagination = if (reversed) pagination.reverse(keys.size) else pagination
 | 
				
			||||||
            if (reversed) {
 | 
					            keys.paginate(actualPagination).let {
 | 
				
			||||||
                it.copy(results = it.results.reversed())
 | 
					                if (reversed) {
 | 
				
			||||||
            } else {
 | 
					                    it.copy(results = it.results.reversed())
 | 
				
			||||||
                it
 | 
					                } else {
 | 
				
			||||||
 | 
					                    it
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult<Key> {
 | 
					    override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult<Key> {
 | 
				
			||||||
        val keys: List<Key> = map.mapNotNull { (k, value) -> if (v == value) k else null }
 | 
					        return locker.withReadAcquire {
 | 
				
			||||||
        val actualPagination = if (reversed) pagination.reverse(keys.size) else pagination
 | 
					            val keys: List<Key> = map.mapNotNull { (k, value) -> if (v == value) k else null }
 | 
				
			||||||
        return keys.paginate(actualPagination).let {
 | 
					            val actualPagination = if (reversed) pagination.reverse(keys.size) else pagination
 | 
				
			||||||
            if (reversed) {
 | 
					            keys.paginate(actualPagination).let {
 | 
				
			||||||
                it.copy(results = it.results.reversed())
 | 
					                if (reversed) {
 | 
				
			||||||
            } else {
 | 
					                    it.copy(results = it.results.reversed())
 | 
				
			||||||
                it
 | 
					                } else {
 | 
				
			||||||
 | 
					                    it
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun getAll(): Map<Key, Value> = map.toMap()
 | 
					    override suspend fun getAll(): Map<Key, Value> = locker.withReadAcquire { map.toMap() }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun contains(key: Key): Boolean = map.containsKey(key)
 | 
					    override suspend fun contains(key: Key): Boolean = locker.withReadAcquire { map.containsKey(key) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun count(): Long = map.size.toLong()
 | 
					    override suspend fun count(): Long = locker.withReadAcquire { map.size.toLong() }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class WriteMapKeyValueRepo<Key, Value>(
 | 
					class WriteMapKeyValueRepo<Key, Value>(
 | 
				
			||||||
    private val map: MutableMap<Key, Value> = mutableMapOf()
 | 
					    private val map: MutableMap<Key, Value>,
 | 
				
			||||||
 | 
					    private val locker: SmartRWLocker
 | 
				
			||||||
) : WriteKeyValueRepo<Key, Value> {
 | 
					) : WriteKeyValueRepo<Key, Value> {
 | 
				
			||||||
    private val _onNewValue: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow()
 | 
					    private val _onNewValue: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow()
 | 
				
			||||||
    override val onNewValue: Flow<Pair<Key, Value>>
 | 
					    override val onNewValue: Flow<Pair<Key, Value>>
 | 
				
			||||||
@@ -67,37 +80,44 @@ class WriteMapKeyValueRepo<Key, Value>(
 | 
				
			|||||||
    private val _onValueRemoved: MutableSharedFlow<Key> = MutableSharedFlow()
 | 
					    private val _onValueRemoved: MutableSharedFlow<Key> = MutableSharedFlow()
 | 
				
			||||||
    override val onValueRemoved: Flow<Key>
 | 
					    override val onValueRemoved: Flow<Key>
 | 
				
			||||||
        get() = _onValueRemoved
 | 
					        get() = _onValueRemoved
 | 
				
			||||||
 | 
					    constructor(map: MutableMap<Key, Value> = mutableMapOf()) : this(map, SmartRWLocker())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun set(toSet: Map<Key, Value>) {
 | 
					    override suspend fun set(toSet: Map<Key, Value>) {
 | 
				
			||||||
        map.putAll(toSet)
 | 
					        locker.withWriteLock { map.putAll(toSet) }
 | 
				
			||||||
        toSet.forEach { (k, v) -> _onNewValue.emit(k to v) }
 | 
					        toSet.forEach { (k, v) -> _onNewValue.emit(k to v) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun unset(toUnset: List<Key>) {
 | 
					    override suspend fun unset(toUnset: List<Key>) {
 | 
				
			||||||
        toUnset.forEach { k ->
 | 
					        locker.withWriteLock {
 | 
				
			||||||
            map.remove(k) ?.also { _ -> _onValueRemoved.emit(k) }
 | 
					            toUnset.forEach { k ->
 | 
				
			||||||
 | 
					                map.remove(k) ?.also { _ -> _onValueRemoved.emit(k) }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun unsetWithValues(toUnset: List<Value>) {
 | 
					    override suspend fun unsetWithValues(toUnset: List<Value>) {
 | 
				
			||||||
        map.mapNotNull { (k, v) ->
 | 
					        locker.withWriteLock {
 | 
				
			||||||
            k.takeIf { v in toUnset }
 | 
					            map.mapNotNull { (k, v) ->
 | 
				
			||||||
        }.forEach {
 | 
					                k.takeIf { v in toUnset }
 | 
				
			||||||
            map.remove(it)
 | 
					            }.forEach {
 | 
				
			||||||
            _onValueRemoved.emit(it)
 | 
					                map.remove(it)
 | 
				
			||||||
 | 
					                _onValueRemoved.emit(it)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE")
 | 
					@Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE")
 | 
				
			||||||
class MapKeyValueRepo<Key, Value>(
 | 
					class MapKeyValueRepo<Key, Value>(
 | 
				
			||||||
    private val map: MutableMap<Key, Value> = mutableMapOf()
 | 
					    private val map: MutableMap<Key, Value>,
 | 
				
			||||||
 | 
					    private val locker: SmartRWLocker
 | 
				
			||||||
) : KeyValueRepo<Key, Value>,
 | 
					) : KeyValueRepo<Key, Value>,
 | 
				
			||||||
    ReadKeyValueRepo<Key, Value> by ReadMapKeyValueRepo(map),
 | 
					    ReadKeyValueRepo<Key, Value> by ReadMapKeyValueRepo(map, locker),
 | 
				
			||||||
    WriteKeyValueRepo<Key, Value> by WriteMapKeyValueRepo(map) {
 | 
					    WriteKeyValueRepo<Key, Value> by WriteMapKeyValueRepo(map, locker) {
 | 
				
			||||||
 | 
					    constructor(map: MutableMap<Key, Value> = mutableMapOf()) : this(map, SmartRWLocker())
 | 
				
			||||||
    override suspend fun clear() {
 | 
					    override suspend fun clear() {
 | 
				
			||||||
        map.clear()
 | 
					        locker.withWriteLock { map.clear() }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <K, V> MutableMap<K, V>.asKeyValueRepo(): KeyValueRepo<K, V> = MapKeyValueRepo(this)
 | 
					fun <K, V> MutableMap<K, V>.asKeyValueRepo(locker: SmartRWLocker = SmartRWLocker()): KeyValueRepo<K, V> = MapKeyValueRepo(this, locker)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +1,21 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos
 | 
					package dev.inmo.micro_utils.repos
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.SmartRWLocker
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.withReadAcquire
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.coroutines.withWriteLock
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.*
 | 
					import dev.inmo.micro_utils.pagination.*
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.utils.paginate
 | 
					import dev.inmo.micro_utils.pagination.utils.paginate
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.utils.reverse
 | 
					import dev.inmo.micro_utils.pagination.utils.reverse
 | 
				
			||||||
import kotlinx.coroutines.flow.*
 | 
					import kotlinx.coroutines.flow.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MapReadKeyValuesRepo<Key, Value>(
 | 
					class MapReadKeyValuesRepo<Key, Value>(
 | 
				
			||||||
    private val map: Map<Key, List<Value>> = emptyMap()
 | 
					    private val map: Map<Key, List<Value>> = emptyMap(),
 | 
				
			||||||
 | 
					    private val locker: SmartRWLocker = SmartRWLocker()
 | 
				
			||||||
) : ReadKeyValuesRepo<Key, Value> {
 | 
					) : ReadKeyValuesRepo<Key, Value> {
 | 
				
			||||||
    override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
 | 
					    override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
 | 
				
			||||||
        val list = map[k] ?: return emptyPaginationResult()
 | 
					        val list = locker.withReadAcquire {
 | 
				
			||||||
 | 
					            map[k] ?: return emptyPaginationResult()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return list.paginate(
 | 
					        return list.paginate(
 | 
				
			||||||
            if (reversed) {
 | 
					            if (reversed) {
 | 
				
			||||||
@@ -21,7 +27,9 @@ class MapReadKeyValuesRepo<Key, Value>(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> {
 | 
					    override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> {
 | 
				
			||||||
        val keys = map.keys
 | 
					        val keys = locker.withReadAcquire {
 | 
				
			||||||
 | 
					            map.keys
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        val actualPagination = if (reversed) pagination.reverse(keys.size) else pagination
 | 
					        val actualPagination = if (reversed) pagination.reverse(keys.size) else pagination
 | 
				
			||||||
        return keys.paginate(actualPagination).let {
 | 
					        return keys.paginate(actualPagination).let {
 | 
				
			||||||
            if (reversed) {
 | 
					            if (reversed) {
 | 
				
			||||||
@@ -33,7 +41,9 @@ class MapReadKeyValuesRepo<Key, Value>(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult<Key> {
 | 
					    override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult<Key> {
 | 
				
			||||||
        val keys = map.keys.filter { map[it] ?.contains(v) == true }
 | 
					        val keys = locker.withReadAcquire {
 | 
				
			||||||
 | 
					            map.keys.filter { map[it] ?.contains(v) == true }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        val actualPagination = if (reversed) pagination.reverse(keys.size) else pagination
 | 
					        val actualPagination = if (reversed) pagination.reverse(keys.size) else pagination
 | 
				
			||||||
        return keys.paginate(actualPagination).let {
 | 
					        return keys.paginate(actualPagination).let {
 | 
				
			||||||
            if (reversed) {
 | 
					            if (reversed) {
 | 
				
			||||||
@@ -44,17 +54,18 @@ class MapReadKeyValuesRepo<Key, Value>(
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun contains(k: Key): Boolean = map.containsKey(k)
 | 
					    override suspend fun contains(k: Key): Boolean = locker.withReadAcquire { map.containsKey(k) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun contains(k: Key, v: Value): Boolean = map[k] ?.contains(v) == true
 | 
					    override suspend fun contains(k: Key, v: Value): Boolean = locker.withReadAcquire { map[k] ?.contains(v) } == true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun count(k: Key): Long = map[k] ?.size ?.toLong() ?: 0L
 | 
					    override suspend fun count(k: Key): Long = locker.withReadAcquire { map[k] ?.size } ?.toLong() ?: 0L
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun count(): Long = map.size.toLong()
 | 
					    override suspend fun count(): Long = locker.withReadAcquire { map.size }.toLong()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MapWriteKeyValuesRepo<Key, Value>(
 | 
					class MapWriteKeyValuesRepo<Key, Value>(
 | 
				
			||||||
    private val map: MutableMap<Key, MutableList<Value>> = mutableMapOf()
 | 
					    private val map: MutableMap<Key, MutableList<Value>> = mutableMapOf(),
 | 
				
			||||||
 | 
					    private val locker: SmartRWLocker = SmartRWLocker()
 | 
				
			||||||
) : WriteKeyValuesRepo<Key, Value> {
 | 
					) : WriteKeyValuesRepo<Key, Value> {
 | 
				
			||||||
    private val _onNewValue: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow()
 | 
					    private val _onNewValue: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow()
 | 
				
			||||||
    override val onNewValue: Flow<Pair<Key, Value>> = _onNewValue.asSharedFlow()
 | 
					    override val onNewValue: Flow<Pair<Key, Value>> = _onNewValue.asSharedFlow()
 | 
				
			||||||
@@ -64,49 +75,59 @@ class MapWriteKeyValuesRepo<Key, Value>(
 | 
				
			|||||||
    override val onDataCleared: Flow<Key> = _onDataCleared.asSharedFlow()
 | 
					    override val onDataCleared: Flow<Key> = _onDataCleared.asSharedFlow()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun add(toAdd: Map<Key, List<Value>>) {
 | 
					    override suspend fun add(toAdd: Map<Key, List<Value>>) {
 | 
				
			||||||
        toAdd.keys.forEach { k ->
 | 
					        locker.withWriteLock {
 | 
				
			||||||
            if (map.getOrPut(k) { mutableListOf() }.addAll(toAdd[k] ?: return@forEach)) {
 | 
					            toAdd.keys.forEach { k ->
 | 
				
			||||||
                toAdd[k] ?.forEach { v ->
 | 
					                if (map.getOrPut(k) { mutableListOf() }.addAll(toAdd[k] ?: return@forEach)) {
 | 
				
			||||||
                    _onNewValue.emit(k to v)
 | 
					                    toAdd[k] ?.forEach { v ->
 | 
				
			||||||
 | 
					                        _onNewValue.emit(k to v)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun remove(toRemove: Map<Key, List<Value>>) {
 | 
					    override suspend fun remove(toRemove: Map<Key, List<Value>>) {
 | 
				
			||||||
        toRemove.keys.forEach { k ->
 | 
					        locker.withWriteLock {
 | 
				
			||||||
            if (map[k] ?.removeAll(toRemove[k] ?: return@forEach) == true) {
 | 
					            toRemove.keys.forEach { k ->
 | 
				
			||||||
                toRemove[k] ?.forEach { v ->
 | 
					                if (map[k]?.removeAll(toRemove[k] ?: return@forEach) == true) {
 | 
				
			||||||
                    _onValueRemoved.emit(k to v)
 | 
					                    toRemove[k]?.forEach { v ->
 | 
				
			||||||
 | 
					                        _onValueRemoved.emit(k to v)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (map[k]?.isEmpty() == true) {
 | 
				
			||||||
 | 
					                    map.remove(k)
 | 
				
			||||||
 | 
					                    _onDataCleared.emit(k)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (map[k] ?.isEmpty() == true) {
 | 
					 | 
				
			||||||
                map.remove(k)
 | 
					 | 
				
			||||||
                _onDataCleared.emit(k)
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun removeWithValue(v: Value) {
 | 
					    override suspend fun removeWithValue(v: Value) {
 | 
				
			||||||
        map.forEach { (k, values) ->
 | 
					        locker.withWriteLock {
 | 
				
			||||||
            if (values.remove(v)) {
 | 
					            map.forEach { (k, values) ->
 | 
				
			||||||
                _onValueRemoved.emit(k to v)
 | 
					                if (values.remove(v)) {
 | 
				
			||||||
 | 
					                    _onValueRemoved.emit(k to v)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun clear(k: Key) {
 | 
					    override suspend fun clear(k: Key) {
 | 
				
			||||||
        map.remove(k) ?.also { _onDataCleared.emit(k) }
 | 
					        locker.withWriteLock {
 | 
				
			||||||
 | 
					            map.remove(k) ?.also { _onDataCleared.emit(k) }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun clearWithValue(v: Value) {
 | 
					    override suspend fun clearWithValue(v: Value) {
 | 
				
			||||||
        map.filter { (_, values) ->
 | 
					        locker.withWriteLock {
 | 
				
			||||||
            values.contains(v)
 | 
					            map.filter { (_, values) ->
 | 
				
			||||||
        }.forEach {
 | 
					                values.contains(v)
 | 
				
			||||||
            map.remove(it.key) ?.onEach { v ->
 | 
					            }.forEach {
 | 
				
			||||||
                _onValueRemoved.emit(it.key to v)
 | 
					                map.remove(it.key)?.onEach { v ->
 | 
				
			||||||
            } ?.also { _ ->
 | 
					                    _onValueRemoved.emit(it.key to v)
 | 
				
			||||||
                _onDataCleared.emit(it.key)
 | 
					                }?.also { _ ->
 | 
				
			||||||
 | 
					                    _onDataCleared.emit(it.key)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -114,11 +135,13 @@ class MapWriteKeyValuesRepo<Key, Value>(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE")
 | 
					@Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE")
 | 
				
			||||||
class MapKeyValuesRepo<Key, Value>(
 | 
					class MapKeyValuesRepo<Key, Value>(
 | 
				
			||||||
    private val map: MutableMap<Key, MutableList<Value>> = mutableMapOf()
 | 
					    private val map: MutableMap<Key, MutableList<Value>> = mutableMapOf(),
 | 
				
			||||||
 | 
					    private val locker: SmartRWLocker = SmartRWLocker()
 | 
				
			||||||
) : KeyValuesRepo<Key, Value>,
 | 
					) : KeyValuesRepo<Key, Value>,
 | 
				
			||||||
    ReadKeyValuesRepo<Key, Value> by MapReadKeyValuesRepo(map),
 | 
					    ReadKeyValuesRepo<Key, Value> by MapReadKeyValuesRepo(map, locker),
 | 
				
			||||||
    WriteKeyValuesRepo<Key, Value> by MapWriteKeyValuesRepo(map)
 | 
					    WriteKeyValuesRepo<Key, Value> by MapWriteKeyValuesRepo(map, locker)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <K, V> MutableMap<K, List<V>>.asKeyValuesRepo(): KeyValuesRepo<K, V> = MapKeyValuesRepo(
 | 
					fun <K, V> MutableMap<K, List<V>>.asKeyValuesRepo(locker: SmartRWLocker = SmartRWLocker()): KeyValuesRepo<K, V> = MapKeyValuesRepo(
 | 
				
			||||||
    map { (k, v) -> k to v.toMutableList() }.toMap().toMutableMap()
 | 
					    map { (k, v) -> k to v.toMutableList() }.toMap().toMutableMap(),
 | 
				
			||||||
 | 
					    locker
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user