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

commonMain.dev.inmo.micro_utils.repos.cache.KeyValuesCacheRepo.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.pagination.utils.*
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 ReadKeyValuesCacheRepo(
    protected open val parentRepo: ReadKeyValuesRepo,
    protected open val kvCache: KVCache>,
    protected val locker: SmartRWLocker = SmartRWLocker(),
) : ReadKeyValuesRepo by parentRepo, CommonCacheRepo {
    override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult {
        return locker.withReadAcquire {
            getAll(k, reversed)
        }.paginate(
            pagination
        )
    }
    override suspend fun getAll(k: Key, reversed: Boolean): List {
        return locker.withReadAcquire {
            kvCache.get(k)
        } ?.let {
            if (reversed) it.reversed() else it
        } ?: parentRepo.getAll(k, reversed).also {
            locker.withWriteLock {
                kvCache.set(k, it)
            }
        }
    }
    override suspend fun contains(k: Key, v: Value): Boolean = locker.withReadAcquire {
        kvCache.get(k)
    } ?.contains(v) ?: (parentRepo.contains(k, v).also {
        if (it) {
            locker.withWriteLock {
                kvCache.unset(k) // clear as invalid
            }
        }
    })
    override suspend fun contains(k: Key): Boolean = locker.withReadAcquire {
        kvCache.contains(k)
    } || parentRepo.contains(k)

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

fun  ReadKeyValuesRepo.cached(
    kvCache: KVCache>,
    locker: SmartRWLocker = SmartRWLocker(),
) = ReadKeyValuesCacheRepo(this, kvCache, locker)

open class KeyValuesCacheRepo(
    parentRepo: KeyValuesRepo,
    kvCache: KVCache>,
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
    locker: SmartRWLocker = SmartRWLocker(),
) : ReadKeyValuesCacheRepo(parentRepo, kvCache, locker), KeyValuesRepo, WriteKeyValuesRepo by parentRepo, CommonCacheRepo {
    protected val onNewJob = parentRepo.onNewValue.onEach { (k, v) ->
        locker.withWriteLock {
            kvCache.set(
                k,
                kvCache.get(k) ?.plus(v) ?: return@onEach
            )
        }
    }.launchIn(scope)
    protected val onRemoveJob = parentRepo.onValueRemoved.onEach { (k, v) ->
        locker.withWriteLock {
            kvCache.set(
                k,
                kvCache.get(k)?.minus(v) ?: return@onEach
            )
        }
    }.launchIn(scope)
    protected val onDataClearedJob = parentRepo.onDataCleared.onEach {
        locker.withWriteLock {
            kvCache.unset(it)
        }
    }.launchIn(scope)
}

fun  KeyValuesRepo.cached(
    kvCache: KVCache>,
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
    locker: SmartRWLocker = SmartRWLocker(),
) = KeyValuesCacheRepo(this, kvCache, scope, locker)




© 2015 - 2024 Weber Informatics LLC | Privacy Policy