package dev.inmo.micro_utils.repos.cache import dev.inmo.micro_utils.repos.* import dev.inmo.micro_utils.repos.cache.cache.KVCache import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.* open class ReadCRUDCacheRepo( protected open val parentRepo: ReadCRUDRepo, protected open val kvCache: KVCache, protected open val idGetter: (ObjectType) -> IdType ) : ReadCRUDRepo by parentRepo { override suspend fun getById(id: IdType): ObjectType? = kvCache.get(id) ?: (parentRepo.getById(id) ?.also { kvCache.set(id, it) }) override suspend fun contains(id: IdType): Boolean = kvCache.contains(id) || parentRepo.contains(id) } fun ReadCRUDRepo.cached( kvCache: KVCache, idGetter: (ObjectType) -> IdType ) = ReadCRUDCacheRepo(this, kvCache, idGetter) open class WriteCRUDCacheRepo( protected open val parentRepo: WriteCRUDRepo, protected open val kvCache: KVCache, protected open val scope: CoroutineScope = CoroutineScope(Dispatchers.Default), protected open val idGetter: (ObjectType) -> IdType ) : WriteCRUDRepo { override val newObjectsFlow: Flow by parentRepo::newObjectsFlow override val updatedObjectsFlow: Flow by parentRepo::updatedObjectsFlow override val deletedObjectsIdsFlow: Flow by parentRepo::deletedObjectsIdsFlow val deletedObjectsFlowJob = parentRepo.deletedObjectsIdsFlow.onEach { kvCache.unset(it) }.launchIn(scope) override suspend fun deleteById(ids: List) = parentRepo.deleteById(ids) override suspend fun update(values: List>): List { val updated = parentRepo.update(values) kvCache.unset(values.map { it.id }) kvCache.set(updated.associateBy { idGetter(it) }) return updated } override suspend fun update(id: IdType, value: InputValueType): ObjectType? { return parentRepo.update(id, value) ?.also { kvCache.unset(id) kvCache.set(idGetter(it), it) } } override suspend fun create(values: List): List { val created = parentRepo.create(values) kvCache.set( created.associateBy { idGetter(it) } ) return created } } fun WriteCRUDRepo.caching( kvCache: KVCache, scope: CoroutineScope, idGetter: (ObjectType) -> IdType ) = WriteCRUDCacheRepo(this, kvCache, scope, idGetter) open class CRUDCacheRepo( override val parentRepo: CRUDRepo, kvCache: KVCache, scope: CoroutineScope = CoroutineScope(Dispatchers.Default), idGetter: (ObjectType) -> IdType ) : ReadCRUDCacheRepo( parentRepo, kvCache, idGetter ), WriteCRUDRepo by WriteCRUDCacheRepo( parentRepo, kvCache, scope, idGetter ), CRUDRepo fun CRUDRepo.cached( kvCache: KVCache, scope: CoroutineScope, idGetter: (ObjectType) -> IdType ) = CRUDCacheRepo(this, kvCache, scope, idGetter)