2021-03-29 13:39:10 +00:00
|
|
|
package dev.inmo.micro_utils.repos.cache
|
|
|
|
|
2023-08-22 21:26:54 +00:00
|
|
|
import dev.inmo.micro_utils.coroutines.SmartRWLocker
|
|
|
|
import dev.inmo.micro_utils.coroutines.withReadAcquire
|
|
|
|
import dev.inmo.micro_utils.coroutines.withWriteLock
|
2021-03-29 13:39:10 +00:00
|
|
|
import dev.inmo.micro_utils.repos.*
|
2022-06-29 13:31:57 +00:00
|
|
|
import dev.inmo.micro_utils.repos.cache.cache.KVCache
|
2024-02-20 18:05:57 +00:00
|
|
|
import dev.inmo.micro_utils.repos.cache.util.ActualizeAllClearMode
|
2023-03-10 12:37:48 +00:00
|
|
|
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
|
2021-03-29 13:39:10 +00:00
|
|
|
import kotlinx.coroutines.CoroutineScope
|
|
|
|
import kotlinx.coroutines.Dispatchers
|
2022-06-29 17:53:49 +00:00
|
|
|
import kotlinx.coroutines.flow.*
|
2021-03-29 13:39:10 +00:00
|
|
|
|
2021-06-05 14:29:59 +00:00
|
|
|
open class ReadCRUDCacheRepo<ObjectType, IdType>(
|
2022-06-29 17:53:49 +00:00
|
|
|
protected open val parentRepo: ReadCRUDRepo<ObjectType, IdType>,
|
|
|
|
protected open val kvCache: KVCache<IdType, ObjectType>,
|
2023-08-22 21:26:54 +00:00
|
|
|
protected val locker: SmartRWLocker = SmartRWLocker(),
|
2022-06-29 17:53:49 +00:00
|
|
|
protected open val idGetter: (ObjectType) -> IdType
|
2023-01-27 08:45:31 +00:00
|
|
|
) : ReadCRUDRepo<ObjectType, IdType> by parentRepo, CommonCacheRepo {
|
2023-08-22 21:26:54 +00:00
|
|
|
override suspend fun getById(id: IdType): ObjectType? = locker.withReadAcquire {
|
|
|
|
kvCache.get(id)
|
|
|
|
} ?: (parentRepo.getById(id) ?.also {
|
|
|
|
locker.withWriteLock {
|
|
|
|
kvCache.set(id, it)
|
|
|
|
}
|
2021-03-29 13:39:10 +00:00
|
|
|
})
|
|
|
|
|
2023-03-10 12:37:48 +00:00
|
|
|
override suspend fun getAll(): Map<IdType, ObjectType> {
|
2023-08-22 21:26:54 +00:00
|
|
|
return locker.withReadAcquire {
|
|
|
|
kvCache.getAll()
|
|
|
|
}.takeIf { it.size.toLong() == count() } ?: parentRepo.getAll().also {
|
|
|
|
locker.withWriteLock {
|
2024-02-20 18:05:57 +00:00
|
|
|
kvCache.actualizeAll(clearMode = ActualizeAllClearMode.BeforeSet) { it }
|
2023-08-22 21:26:54 +00:00
|
|
|
}
|
2023-03-10 12:37:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-22 21:26:54 +00:00
|
|
|
override suspend fun contains(id: IdType): Boolean = locker.withReadAcquire {
|
|
|
|
kvCache.contains(id)
|
|
|
|
} || parentRepo.contains(id)
|
2023-01-27 08:45:31 +00:00
|
|
|
|
2023-08-22 21:26:54 +00:00
|
|
|
override suspend fun invalidate() = locker.withWriteLock {
|
|
|
|
kvCache.clear()
|
|
|
|
}
|
2021-03-29 13:39:10 +00:00
|
|
|
}
|
2021-06-05 14:29:59 +00:00
|
|
|
|
2022-06-29 20:44:44 +00:00
|
|
|
fun <ObjectType, IdType> ReadCRUDRepo<ObjectType, IdType>.cached(
|
|
|
|
kvCache: KVCache<IdType, ObjectType>,
|
2023-08-22 21:26:54 +00:00
|
|
|
locker: SmartRWLocker = SmartRWLocker(),
|
2022-06-29 20:44:44 +00:00
|
|
|
idGetter: (ObjectType) -> IdType
|
2023-08-22 21:26:54 +00:00
|
|
|
) = ReadCRUDCacheRepo(this, kvCache, locker, idGetter)
|
2022-06-29 20:44:44 +00:00
|
|
|
|
2022-06-29 17:53:49 +00:00
|
|
|
open class WriteCRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
2022-06-29 20:44:44 +00:00
|
|
|
protected open val parentRepo: WriteCRUDRepo<ObjectType, IdType, InputValueType>,
|
2023-08-22 21:26:54 +00:00
|
|
|
protected open val kvCache: KeyValueRepo<IdType, ObjectType>,
|
2022-06-29 17:53:49 +00:00
|
|
|
protected open val scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
2023-08-22 21:26:54 +00:00
|
|
|
protected val locker: SmartRWLocker = SmartRWLocker(),
|
2022-06-29 17:53:49 +00:00
|
|
|
protected open val idGetter: (ObjectType) -> IdType
|
2023-01-27 08:45:31 +00:00
|
|
|
) : WriteCRUDRepo<ObjectType, IdType, InputValueType>, CommonCacheRepo {
|
2022-06-29 17:53:49 +00:00
|
|
|
override val newObjectsFlow: Flow<ObjectType> by parentRepo::newObjectsFlow
|
|
|
|
override val updatedObjectsFlow: Flow<ObjectType> by parentRepo::updatedObjectsFlow
|
|
|
|
override val deletedObjectsIdsFlow: Flow<IdType> by parentRepo::deletedObjectsIdsFlow
|
|
|
|
|
2022-09-05 09:07:33 +00:00
|
|
|
val createdObjectsFlowJob = parentRepo.newObjectsFlow.onEach {
|
2023-08-30 19:37:35 +00:00
|
|
|
locker.withWriteLock {
|
|
|
|
kvCache.set(idGetter(it), it)
|
|
|
|
}
|
2022-09-05 09:07:33 +00:00
|
|
|
}.launchIn(scope)
|
|
|
|
|
|
|
|
val updatedObjectsFlowJob = parentRepo.updatedObjectsFlow.onEach {
|
2023-08-30 19:37:35 +00:00
|
|
|
locker.withWriteLock {
|
|
|
|
kvCache.set(idGetter(it), it)
|
|
|
|
}
|
2022-09-05 09:07:33 +00:00
|
|
|
}.launchIn(scope)
|
|
|
|
|
2022-06-29 17:53:49 +00:00
|
|
|
val deletedObjectsFlowJob = parentRepo.deletedObjectsIdsFlow.onEach {
|
2023-08-30 19:37:35 +00:00
|
|
|
locker.withWriteLock {
|
|
|
|
kvCache.unset(it)
|
|
|
|
}
|
2022-06-29 17:53:49 +00:00
|
|
|
}.launchIn(scope)
|
|
|
|
|
2023-08-30 19:37:35 +00:00
|
|
|
override suspend fun deleteById(ids: List<IdType>) = parentRepo.deleteById(ids).also {
|
|
|
|
locker.withWriteLock {
|
|
|
|
kvCache.unset(ids)
|
|
|
|
}
|
|
|
|
}
|
2022-06-29 17:53:49 +00:00
|
|
|
|
|
|
|
override suspend fun update(values: List<UpdatedValuePair<IdType, InputValueType>>): List<ObjectType> {
|
|
|
|
val updated = parentRepo.update(values)
|
|
|
|
|
2023-08-22 21:26:54 +00:00
|
|
|
locker.withWriteLock {
|
|
|
|
kvCache.unset(values.map { it.id })
|
|
|
|
kvCache.set(updated.associateBy { idGetter(it) })
|
|
|
|
}
|
2022-06-29 17:53:49 +00:00
|
|
|
|
|
|
|
return updated
|
|
|
|
}
|
|
|
|
|
|
|
|
override suspend fun update(id: IdType, value: InputValueType): ObjectType? {
|
|
|
|
return parentRepo.update(id, value) ?.also {
|
2023-08-22 21:26:54 +00:00
|
|
|
locker.withWriteLock {
|
|
|
|
kvCache.unset(id)
|
|
|
|
kvCache.set(idGetter(it), it)
|
|
|
|
}
|
2022-06-29 17:53:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override suspend fun create(values: List<InputValueType>): List<ObjectType> {
|
|
|
|
val created = parentRepo.create(values)
|
|
|
|
|
2023-08-22 21:26:54 +00:00
|
|
|
locker.withWriteLock {
|
|
|
|
kvCache.set(
|
|
|
|
created.associateBy { idGetter(it) }
|
|
|
|
)
|
|
|
|
}
|
2022-06-29 17:53:49 +00:00
|
|
|
|
|
|
|
return created
|
|
|
|
}
|
2023-01-27 08:45:31 +00:00
|
|
|
|
2023-08-22 21:26:54 +00:00
|
|
|
override suspend fun invalidate() = locker.withWriteLock {
|
|
|
|
kvCache.clear()
|
|
|
|
}
|
2022-06-29 17:53:49 +00:00
|
|
|
}
|
|
|
|
|
2022-06-29 20:44:44 +00:00
|
|
|
fun <ObjectType, IdType, InputType> WriteCRUDRepo<ObjectType, IdType, InputType>.caching(
|
|
|
|
kvCache: KVCache<IdType, ObjectType>,
|
|
|
|
scope: CoroutineScope,
|
2023-08-22 21:26:54 +00:00
|
|
|
locker: SmartRWLocker = SmartRWLocker(),
|
2022-06-29 20:44:44 +00:00
|
|
|
idGetter: (ObjectType) -> IdType
|
2023-08-22 21:26:54 +00:00
|
|
|
) = WriteCRUDCacheRepo(this, kvCache, scope, locker, idGetter)
|
2022-06-29 20:44:44 +00:00
|
|
|
|
2022-06-29 17:53:49 +00:00
|
|
|
|
2021-06-05 14:29:59 +00:00
|
|
|
open class CRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
2022-06-29 17:53:49 +00:00
|
|
|
override val parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>,
|
2021-06-05 14:29:59 +00:00
|
|
|
kvCache: KVCache<IdType, ObjectType>,
|
|
|
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
2023-08-22 21:26:54 +00:00
|
|
|
locker: SmartRWLocker = SmartRWLocker(),
|
2021-06-05 14:29:59 +00:00
|
|
|
idGetter: (ObjectType) -> IdType
|
|
|
|
) : ReadCRUDCacheRepo<ObjectType, IdType>(
|
|
|
|
parentRepo,
|
|
|
|
kvCache,
|
2023-08-22 21:26:54 +00:00
|
|
|
locker,
|
2021-06-05 14:29:59 +00:00
|
|
|
idGetter
|
2022-06-29 17:53:49 +00:00
|
|
|
),
|
|
|
|
WriteCRUDRepo<ObjectType, IdType, InputValueType> by WriteCRUDCacheRepo(
|
|
|
|
parentRepo,
|
|
|
|
kvCache,
|
|
|
|
scope,
|
2023-08-22 21:26:54 +00:00
|
|
|
locker,
|
2022-06-29 17:53:49 +00:00
|
|
|
idGetter
|
|
|
|
),
|
2024-02-20 18:05:57 +00:00
|
|
|
CRUDRepo<ObjectType, IdType, InputValueType> {
|
|
|
|
override suspend fun invalidate() = kvCache.actualizeAll(parentRepo, locker = locker)
|
|
|
|
}
|
2022-06-29 20:44:44 +00:00
|
|
|
|
|
|
|
fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.cached(
|
|
|
|
kvCache: KVCache<IdType, ObjectType>,
|
|
|
|
scope: CoroutineScope,
|
2023-08-22 21:26:54 +00:00
|
|
|
locker: SmartRWLocker = SmartRWLocker(),
|
2022-06-29 20:44:44 +00:00
|
|
|
idGetter: (ObjectType) -> IdType
|
2023-08-22 21:26:54 +00:00
|
|
|
) = CRUDCacheRepo(this, kvCache, scope, locker, idGetter)
|