mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-10-27 10:11:22 +00:00 
			
		
		
		
	ReadKeyValuesRepo#removeWithValue
This commit is contained in:
		| @@ -6,6 +6,8 @@ | |||||||
|     * `Server`: |     * `Server`: | ||||||
|         * Now it is possible to take query parameters as list |         * Now it is possible to take query parameters as list | ||||||
| * `Repos`: | * `Repos`: | ||||||
|  |     * `Common`: | ||||||
|  |         * New `WriteKeyValuesRepo.removeWithValue` | ||||||
|     * `Cache`: |     * `Cache`: | ||||||
|         * Rename full caching factories functions to `fullyCached` |         * Rename full caching factories functions to `fullyCached` | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging | |||||||
| import dev.inmo.micro_utils.repos.WriteKeyValuesRepo | import dev.inmo.micro_utils.repos.WriteKeyValuesRepo | ||||||
| import dev.inmo.micro_utils.repos.cache.cache.FullKVCache | import dev.inmo.micro_utils.repos.cache.cache.FullKVCache | ||||||
| import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo | import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo | ||||||
|  | import dev.inmo.micro_utils.repos.pagination.maxPagePagination | ||||||
| import dev.inmo.micro_utils.repos.set | import dev.inmo.micro_utils.repos.set | ||||||
| import dev.inmo.micro_utils.repos.unset | import dev.inmo.micro_utils.repos.unset | ||||||
| import kotlinx.coroutines.CoroutineScope | import kotlinx.coroutines.CoroutineScope | ||||||
| @@ -50,7 +51,7 @@ open class AutoRecacheWriteKeyValuesRepo<Id, RegisteredObject>( | |||||||
|  |  | ||||||
|     override suspend fun clearWithValue(v: RegisteredObject) { |     override suspend fun clearWithValue(v: RegisteredObject) { | ||||||
|         originalRepo.clearWithValue(v) |         originalRepo.clearWithValue(v) | ||||||
|         doForAllWithNextPaging(FirstPagePagination(kvCache.count().takeIf { it < Int.MAX_VALUE } ?.toInt() ?: Int.MAX_VALUE)) { |         doForAllWithNextPaging(kvCache.maxPagePagination()) { | ||||||
|             kvCache.keys(it).also { |             kvCache.keys(it).also { | ||||||
|                 it.results.forEach { id -> |                 it.results.forEach { id -> | ||||||
|                     kvCache.get(id) ?.takeIf { it.contains(v) } ?.let { |                     kvCache.get(id) ?.takeIf { it.contains(v) } ?.let { | ||||||
| @@ -73,6 +74,19 @@ open class AutoRecacheWriteKeyValuesRepo<Id, RegisteredObject>( | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     override suspend fun removeWithValue(v: RegisteredObject) { | ||||||
|  |         originalRepo.removeWithValue(v) | ||||||
|  |         doForAllWithNextPaging(kvCache.maxPagePagination()) { | ||||||
|  |             kvCache.keys(it).also { | ||||||
|  |                 it.results.forEach { id -> | ||||||
|  |                     kvCache.get(id) ?.takeIf { it.contains(v) } ?.let { | ||||||
|  |                         kvCache.set(id, it - v) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     override suspend fun add(toAdd: Map<Id, List<RegisteredObject>>) { |     override suspend fun add(toAdd: Map<Id, List<RegisteredObject>>) { | ||||||
|         originalRepo.add(toAdd) |         originalRepo.add(toAdd) | ||||||
|         toAdd.forEach { (k, v) -> |         toAdd.forEach { (k, v) -> | ||||||
|   | |||||||
| @@ -157,6 +157,10 @@ open class FullKeyValuesCacheRepo<Key,Value>( | |||||||
|     override suspend fun invalidate() { |     override suspend fun invalidate() { | ||||||
|         kvCache.actualizeAll(parentRepo) |         kvCache.actualizeAll(parentRepo) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     override suspend fun removeWithValue(v: Value) { | ||||||
|  |         super<FullWriteKeyValuesCacheRepo>.removeWithValue(v) | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| fun <Key, Value> KeyValuesRepo<Key, Value>.fullyCached( | fun <Key, Value> KeyValuesRepo<Key, Value>.fullyCached( | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package dev.inmo.micro_utils.repos | package dev.inmo.micro_utils.repos | ||||||
|  |  | ||||||
| import dev.inmo.micro_utils.pagination.* | import dev.inmo.micro_utils.pagination.* | ||||||
|  | import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging | ||||||
| import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging | import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging | ||||||
| import kotlinx.coroutines.flow.Flow | import kotlinx.coroutines.flow.Flow | ||||||
|  |  | ||||||
| @@ -44,9 +45,23 @@ interface WriteKeyValuesRepo<Key, Value> : Repo { | |||||||
|  |  | ||||||
|     suspend fun add(toAdd: Map<Key, List<Value>>) |     suspend fun add(toAdd: Map<Key, List<Value>>) | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Removes [Value]s by passed [Key]s without full clear of all data by [Key] | ||||||
|  |      */ | ||||||
|     suspend fun remove(toRemove: Map<Key, List<Value>>) |     suspend fun remove(toRemove: Map<Key, List<Value>>) | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 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) |     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 clearWithValue(v: Value) | ||||||
|  |  | ||||||
|     suspend fun set(toSet: Map<Key, List<Value>>) { |     suspend fun set(toSet: Map<Key, List<Value>>) { | ||||||
| @@ -100,6 +115,21 @@ interface KeyValuesRepo<Key, Value> : ReadKeyValuesRepo<Key, Value>, WriteKeyVal | |||||||
|             keysResult.currentPageIfNotEmpty() |             keysResult.currentPageIfNotEmpty() | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     suspend override fun removeWithValue(v: Value) { | ||||||
|  |         val toRemove = mutableMapOf<Key, List<Value>>() | ||||||
|  |  | ||||||
|  |         doForAllWithNextPaging { | ||||||
|  |             keys(it).also { | ||||||
|  |                 it.results.forEach { | ||||||
|  |                     if (contains(it, v)) { | ||||||
|  |                         toRemove[it] = listOf(v) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         remove(toRemove) | ||||||
|  |     } | ||||||
| } | } | ||||||
| typealias OneToManyKeyValueRepo<Key,Value> = KeyValuesRepo<Key, Value> | typealias OneToManyKeyValueRepo<Key,Value> = KeyValuesRepo<Key, Value> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -97,6 +97,8 @@ open class MapperWriteKeyValuesRepo<FromKey, FromValue, ToKey, ToValue>( | |||||||
|         }.toMap() |         }.toMap() | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|  |     override suspend fun removeWithValue(v: FromValue) = to.removeWithValue(v.toOutValue()) | ||||||
|  |  | ||||||
|     override suspend fun set(toSet: Map<FromKey, List<FromValue>>) { |     override suspend fun set(toSet: Map<FromKey, List<FromValue>>) { | ||||||
|         to.set( |         to.set( | ||||||
|             toSet.map { (k, vs) -> k.toOutKey() to vs.map { v -> v.toOutValue() } }.toMap() |             toSet.map { (k, vs) -> k.toOutKey() to vs.map { v -> v.toOutValue() } }.toMap() | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import dev.inmo.micro_utils.pagination.FirstPagePagination | |||||||
| import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging | import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging | ||||||
| import dev.inmo.micro_utils.repos.KeyValueRepo | import dev.inmo.micro_utils.repos.KeyValueRepo | ||||||
| import dev.inmo.micro_utils.repos.KeyValuesRepo | import dev.inmo.micro_utils.repos.KeyValuesRepo | ||||||
|  | import dev.inmo.micro_utils.repos.set | ||||||
| import dev.inmo.micro_utils.repos.unset | import dev.inmo.micro_utils.repos.unset | ||||||
| import kotlinx.coroutines.flow.Flow | import kotlinx.coroutines.flow.Flow | ||||||
| import kotlinx.coroutines.flow.MutableSharedFlow | import kotlinx.coroutines.flow.MutableSharedFlow | ||||||
| @@ -60,6 +61,24 @@ open class KeyValuesFromKeyValueRepo<Key, Value, ValuesIterable : Iterable<Value | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     override suspend fun removeWithValue(v: Value) { | ||||||
|  |         val toRemove = mutableMapOf<Key, List<Value>>() | ||||||
|  |  | ||||||
|  |         doForAllWithNextPaging { | ||||||
|  |             original.keys(it).also { | ||||||
|  |                 it.results.forEach { | ||||||
|  |                     val data = original.get(it) ?: return@forEach | ||||||
|  |  | ||||||
|  |                     if (v in data) { | ||||||
|  |                         toRemove[it] = listOf(v) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         remove(toRemove) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     override suspend fun add(toAdd: Map<Key, List<Value>>) { |     override suspend fun add(toAdd: Map<Key, List<Value>>) { | ||||||
|         original.set( |         original.set( | ||||||
|             toAdd.mapNotNull { (k, adding) -> |             toAdd.mapNotNull { (k, adding) -> | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ import dev.inmo.micro_utils.common.mapNotNullA | |||||||
| import dev.inmo.micro_utils.pagination.* | import dev.inmo.micro_utils.pagination.* | ||||||
| import dev.inmo.micro_utils.pagination.utils.reverse | import dev.inmo.micro_utils.pagination.utils.reverse | ||||||
| import dev.inmo.micro_utils.repos.* | import dev.inmo.micro_utils.repos.* | ||||||
|  | import dev.inmo.micro_utils.repos.crud.asId | ||||||
| import kotlinx.coroutines.flow.Flow | import kotlinx.coroutines.flow.Flow | ||||||
| import kotlinx.coroutines.flow.MutableSharedFlow | import kotlinx.coroutines.flow.MutableSharedFlow | ||||||
| import kotlinx.coroutines.flow.asSharedFlow | import kotlinx.coroutines.flow.asSharedFlow | ||||||
| @@ -260,6 +261,19 @@ class OneToManyAndroidRepo<Key, Value>( | |||||||
|             _onValueRemoved.emit(k to v) |             _onValueRemoved.emit(k to v) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     override suspend fun removeWithValue(v: Value) { | ||||||
|  |         helper.blockingWritableTransaction { | ||||||
|  |             val keys = select(tableName, idColumnArray, "$valueColumnName=?", arrayOf(v.valueAsString())).map { | ||||||
|  |                 it.asId.keyFromString() | ||||||
|  |             } | ||||||
|  |             keys.filter { | ||||||
|  |                 delete(tableName, "$idColumnName=? AND $valueColumnName=?", arrayOf(it.keyAsString(), v.valueAsString())) > 0 | ||||||
|  |             } | ||||||
|  |         }.forEach { k -> | ||||||
|  |             _onValueRemoved.emit(k to v) | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| fun <Key, Value> OneToManyAndroidRepo( | fun <Key, Value> OneToManyAndroidRepo( | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ import dev.inmo.micro_utils.repos.exposed.ColumnAllocator | |||||||
| import kotlinx.coroutines.flow.* | import kotlinx.coroutines.flow.* | ||||||
| import org.jetbrains.exposed.sql.* | import org.jetbrains.exposed.sql.* | ||||||
| import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq | import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq | ||||||
|  | import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList | ||||||
| import org.jetbrains.exposed.sql.transactions.transaction | import org.jetbrains.exposed.sql.transactions.transaction | ||||||
|  |  | ||||||
| typealias ExposedOneToManyKeyValueRepo1<Key, Value> = ExposedKeyValuesRepo<Key, Value> | typealias ExposedOneToManyKeyValueRepo1<Key, Value> = ExposedKeyValuesRepo<Key, Value> | ||||||
| @@ -66,9 +67,36 @@ open class ExposedKeyValuesRepo<Key, Value>( | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     override suspend fun removeWithValue(v: Value) { | ||||||
|  |         transaction(database) { | ||||||
|  |             val keys = select { selectByValue(v) }.map { it.asKey } | ||||||
|  |             deleteWhere { SqlExpressionBuilder.selectByValue(v) } | ||||||
|  |             keys | ||||||
|  |         }.forEach { | ||||||
|  |             _onValueRemoved.emit(it to v) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     override suspend fun clear(k: Key) { |     override suspend fun clear(k: Key) { | ||||||
|         transaction(database) { |         transaction(database) { | ||||||
|             deleteWhere { keyColumn.eq(k) } |             deleteWhere { keyColumn.eq(k) } | ||||||
|         }.also { _onDataCleared.emit(k) } |         }.also { _onDataCleared.emit(k) } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     override suspend fun clearWithValue(v: Value) { | ||||||
|  |         transaction(database) { | ||||||
|  |             val toClear = select { selectByValue(v) } | ||||||
|  |                 .asSequence() | ||||||
|  |                 .map { it.asKey to it.asObject } | ||||||
|  |                 .groupBy { it.first } | ||||||
|  |                 .mapValues { it.value.map { it.second } } | ||||||
|  |             deleteWhere { keyColumn.inList(toClear.keys) } | ||||||
|  |             toClear | ||||||
|  |         }.forEach { | ||||||
|  |             it.value.forEach { v -> | ||||||
|  |                 _onValueRemoved.emit(it.key to v) | ||||||
|  |             } | ||||||
|  |             _onDataCleared.emit(it.key) | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -87,13 +87,27 @@ class MapWriteKeyValuesRepo<Key, Value>( | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     override suspend fun removeWithValue(v: Value) { | ||||||
|  |         map.forEach { (k, values) -> | ||||||
|  |             if (values.remove(v)) { | ||||||
|  |                 _onValueRemoved.emit(k to v) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     override suspend fun clear(k: Key) { |     override suspend fun clear(k: Key) { | ||||||
|         map.remove(k) ?.also { _onDataCleared.emit(k) } |         map.remove(k) ?.also { _onDataCleared.emit(k) } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override suspend fun clearWithValue(v: Value) { |     override suspend fun clearWithValue(v: Value) { | ||||||
|         map.forEach { (k, values) -> |         map.filter { (_, values) -> | ||||||
|             if (values.remove(v)) _onValueRemoved.emit(k to v) |             values.contains(v) | ||||||
|  |         }.forEach { | ||||||
|  |             map.remove(it.key) ?.onEach { v -> | ||||||
|  |                 _onValueRemoved.emit(it.key to v) | ||||||
|  |             } ?.also { _ -> | ||||||
|  |                 _onDataCleared.emit(it.key) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -47,6 +47,17 @@ class KtorWriteKeyValuesRepoClient<Key : Any, Value : Any>( | |||||||
|         }.throwOnUnsuccess { "Unable to remove $toRemove" } |         }.throwOnUnsuccess { "Unable to remove $toRemove" } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @OptIn(InternalAPI::class) | ||||||
|  |     override suspend fun removeWithValue(v: Value) { | ||||||
|  |         httpClient.post( | ||||||
|  |             buildStandardUrl(baseUrl, removeWithValueRoute) | ||||||
|  |         ) { | ||||||
|  |             body = v | ||||||
|  |             bodyType = valueTypeInfo | ||||||
|  |             contentType(contentType) | ||||||
|  |         }.throwOnUnsuccess { "Unable to remove $v" } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @OptIn(InternalAPI::class) |     @OptIn(InternalAPI::class) | ||||||
|     override suspend fun clear(k: Key) { |     override suspend fun clear(k: Key) { | ||||||
|         httpClient.post( |         httpClient.post( | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ const val onDataClearedRoute = "onDataCleared" | |||||||
|  |  | ||||||
| const val addRoute = "add" | const val addRoute = "add" | ||||||
| const val removeRoute = "remove" | const val removeRoute = "remove" | ||||||
|  | const val removeWithValueRoute = "removeWithValue" | ||||||
| const val clearRoute = "clear" | const val clearRoute = "clear" | ||||||
| const val clearWithValueRoute = "clearWithValue" | const val clearWithValueRoute = "clearWithValue" | ||||||
| const val setRoute = "set" | const val setRoute = "set" | ||||||
|   | |||||||
| @@ -46,6 +46,11 @@ inline fun <reified Key : Any, reified Value : Any> Route.configureWriteKeyValue | |||||||
|         call.respond(HttpStatusCode.OK) |         call.respond(HttpStatusCode.OK) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     post(removeWithValueRoute) { | ||||||
|  |         originalRepo.removeWithValue(call.receive()) | ||||||
|  |         call.respond(HttpStatusCode.OK) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     post(clearRoute) { |     post(clearRoute) { | ||||||
|         originalRepo.clear(call.receive()) |         originalRepo.clear(call.receive()) | ||||||
|         call.respond(HttpStatusCode.OK) |         call.respond(HttpStatusCode.OK) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user