package dev.inmo.micro_utils.repos import dev.inmo.micro_utils.common.diff import dev.inmo.micro_utils.pagination.* import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging import kotlinx.coroutines.flow.Flow interface ReadKeyValuesRepo : Repo { suspend fun get(k: Key, pagination: Pagination, reversed: Boolean = false): PaginationResult suspend fun keys(pagination: Pagination, reversed: Boolean = false): PaginationResult suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean = false): PaginationResult suspend fun contains(k: Key): Boolean suspend fun contains(k: Key, v: Value): Boolean suspend fun count(k: Key): Long suspend fun count(): Long suspend fun getAll(k: Key, reversed: Boolean = false): List { val results = getAllWithNextPaging { get(k, it) } return if (reversed) { results.reversed() } else { results } } /** * WARNING!!! THIS METHOD PROBABLY IS NOT EFFICIENT, USE WITH CAUTION */ suspend fun getAll(reverseLists: Boolean = false): Map> = mutableMapOf>().also { map -> doWithPagination { keys(it).also { paginationResult -> paginationResult.results.forEach { k -> map[k] = getAll(k, reverseLists) } }.nextPageIfNotEmpty() } } } typealias ReadOneToManyKeyValueRepo = ReadKeyValuesRepo interface WriteKeyValuesRepo : Repo { val onNewValue: Flow> val onValueRemoved: Flow> val onDataCleared: Flow suspend fun add(toAdd: Map>) /** * Removes [Value]s by passed [Key]s without full clear of all data by [Key] */ suspend fun remove(toRemove: Map>) /** * Removes [v] without full clear of all data by [Key]s with [v] */ suspend fun removeWithValue(v: Value) /** * Fully clear all data by [k] */ suspend fun clear(k: Key) /** * Clear [v] **with** full clear of all data by [Key]s with [v] */ suspend fun clearWithValue(v: Value) suspend fun set(toSet: Map>) { toSet.keys.forEach { key -> clear(key) } add(toSet) } } typealias WriteOneToManyKeyValueRepo = WriteKeyValuesRepo suspend inline fun > REPO.add( keysAndValues: List>> ) = add(keysAndValues.toMap()) suspend inline fun > REPO.add( vararg keysAndValues: Pair> ) = add(keysAndValues.toMap()) suspend inline fun WriteKeyValuesRepo.add( k: Key, v: List ) = add(mapOf(k to v)) suspend inline fun WriteKeyValuesRepo.add( k: Key, vararg v: Value ) = add(k, v.toList()) suspend inline fun > REPO.set( keysAndValues: List>> ) = set(keysAndValues.toMap()) suspend inline fun > REPO.set( vararg keysAndValues: Pair> ) = set(keysAndValues.toMap()) suspend inline fun WriteKeyValuesRepo.set( k: Key, v: List ) = set(mapOf(k to v)) suspend inline fun WriteKeyValuesRepo.set( k: Key, vararg v: Value ) = set(k, v.toList()) interface KeyValuesRepo : ReadKeyValuesRepo, WriteKeyValuesRepo { override suspend fun clearWithValue(v: Value) { doWithPagination { val keysResult = keys(v, it) if (keysResult.results.isNotEmpty()) { remove(keysResult.results.map { it to listOf(v) }) } keysResult.currentPageIfNotEmpty() } } suspend override fun removeWithValue(v: Value) { val toRemove = mutableMapOf>() doForAllWithNextPaging { keys(it).also { it.results.forEach { if (contains(it, v)) { toRemove[it] = listOf(v) } } } } remove(toRemove) } override suspend fun set(toSet: Map>) { toSet.forEach { (k, v) -> val diff = getAll(k).diff(v) remove(k, diff.removed.map { it.value }) add(k, diff.added.map { it.value }) } } } typealias OneToManyKeyValueRepo = KeyValuesRepo class DelegateBasedKeyValuesRepo( readDelegate: ReadKeyValuesRepo, writeDelegate: WriteKeyValuesRepo ) : KeyValuesRepo, ReadKeyValuesRepo by readDelegate, WriteKeyValuesRepo by writeDelegate suspend inline fun WriteKeyValuesRepo.remove( keysAndValues: List>> ) = remove(keysAndValues.toMap()) suspend inline fun WriteKeyValuesRepo.remove( vararg keysAndValues: Pair> ) = remove(keysAndValues.toMap()) suspend inline fun WriteKeyValuesRepo.remove( k: Key, v: List ) = remove(mapOf(k to v)) suspend inline fun WriteKeyValuesRepo.remove( k: Key, vararg v: Value ) = remove(k, v.toList())