All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.dev.inmo.micro_utils.repos.cache.KeyValueCacheRepo.kt Maven / Gradle / Ivy

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.repos.*
import dev.inmo.micro_utils.repos.cache.cache.KVCache
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*

open class ReadKeyValueCacheRepo(
    protected open val parentRepo: ReadKeyValueRepo,
    protected open val kvCache: KVCache,
    protected val locker: SmartRWLocker = SmartRWLocker(),
) : ReadKeyValueRepo by parentRepo, CommonCacheRepo {
    override suspend fun get(k: Key): Value? = locker.withReadAcquire {
        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 {
        return locker.withReadAcquire {
            keys(pagination, reversed).let {
                it.changeResultsUnchecked(
                    it.results.mapNotNull {
                        get(it)
                    }
                )
            }
        }
    }

    override suspend fun getAll(): Map = locker.withReadAcquire {
        kvCache.getAll()
    }.takeIf {
        it.size.toLong() == count()
    } ?: parentRepo.getAll().also {
        locker.withWriteLock {
            kvCache.set(it)
        }
    }

    override suspend fun invalidate() = kvCache.actualizeAll(parentRepo, locker = locker)
}

fun  ReadKeyValueRepo.cached(
    kvCache: KVCache,
    locker: SmartRWLocker = SmartRWLocker(),
) = ReadKeyValueCacheRepo(this, kvCache, locker)

open class KeyValueCacheRepo(
    override val parentRepo: KeyValueRepo,
    kvCache: KVCache,
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
    locker: SmartRWLocker = SmartRWLocker(),
) : ReadKeyValueCacheRepo(parentRepo, kvCache, locker), KeyValueRepo, WriteKeyValueRepo by parentRepo, CommonCacheRepo {
    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 clear() {
        parentRepo.clear()
        locker.withWriteLock {
            kvCache.clear()
        }
    }
}

fun  KeyValueRepo.cached(
    kvCache: KVCache,
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
    locker: SmartRWLocker = SmartRWLocker(),
) = KeyValueCacheRepo(this, kvCache, scope, locker)




© 2015 - 2024 Weber Informatics LLC | Privacy Policy