mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2024-12-23 17:17:14 +00:00
commit
fe8f80b9d9
15
CHANGELOG.md
15
CHANGELOG.md
@ -1,5 +1,20 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.18.0
|
||||||
|
|
||||||
|
**ALL PREVIOUSLY DEPRECATED FUNCTIONALITY HAVE BEEN REMOVED**
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Android Fragments`: `1.5.6` -> `1.5.7`
|
||||||
|
* `Ktor`:
|
||||||
|
* `Server`:
|
||||||
|
* Now it is possible to take query parameters as list
|
||||||
|
* `Repos`:
|
||||||
|
* `Common`:
|
||||||
|
* New `WriteKeyValuesRepo.removeWithValue`
|
||||||
|
* `Cache`:
|
||||||
|
* Rename full caching factories functions to `fullyCached`
|
||||||
|
|
||||||
## 0.17.8
|
## 0.17.8
|
||||||
|
|
||||||
* `Versions`:
|
* `Versions`:
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
package dev.inmo.micro_utils.coroutines.compose
|
|
||||||
|
|
||||||
import androidx.compose.runtime.MutableState
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
|
|
||||||
@Deprecated("Duplicated functionality", ReplaceWith("asMutableComposeState(initial, scope)", "dev.inmo.micro_utils.coroutines.compose.asMutableComposeState"))
|
|
||||||
fun <T> Flow<T>.toMutableState(
|
|
||||||
initial: T,
|
|
||||||
scope: CoroutineScope
|
|
||||||
): MutableState<T> = asMutableComposeState(initial, scope)
|
|
||||||
|
|
||||||
@Deprecated("Duplicated functionality", ReplaceWith("asMutableComposeState(scope)", "dev.inmo.micro_utils.coroutines.compose.asMutableComposeState"))
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
|
||||||
inline fun <T> StateFlow<T>.toMutableState(
|
|
||||||
scope: CoroutineScope
|
|
||||||
): MutableState<T> = asMutableComposeState(scope)
|
|
||||||
|
|
@ -14,5 +14,5 @@ crypto_js_version=4.1.1
|
|||||||
# Project data
|
# Project data
|
||||||
|
|
||||||
group=dev.inmo
|
group=dev.inmo
|
||||||
version=0.17.8
|
version=0.18.0
|
||||||
android_code_version=190
|
android_code_version=191
|
||||||
|
@ -30,13 +30,13 @@ dexcount = "4.0.0"
|
|||||||
android-coreKtx = "1.10.0"
|
android-coreKtx = "1.10.0"
|
||||||
android-recyclerView = "1.3.0"
|
android-recyclerView = "1.3.0"
|
||||||
android-appCompat = "1.6.1"
|
android-appCompat = "1.6.1"
|
||||||
android-fragment = "1.5.6"
|
android-fragment = "1.5.7"
|
||||||
android-espresso = "3.5.1"
|
android-espresso = "3.5.1"
|
||||||
android-test = "1.1.5"
|
android-test = "1.1.5"
|
||||||
|
|
||||||
android-props-minSdk = "21"
|
android-props-minSdk = "21"
|
||||||
android-props-compileSdk = "33"
|
android-props-compileSdk = "33"
|
||||||
android-props-buildTools = "33.0.1"
|
android-props-buildTools = "33.0.2"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
|
|
||||||
|
@ -12,10 +12,22 @@ suspend fun ApplicationCall.getParameterOrSendError(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun ApplicationCall.getParametersOrSendError(
|
||||||
|
field: String
|
||||||
|
) = parameters.getAll(field).also {
|
||||||
|
if (it == null) {
|
||||||
|
respond(HttpStatusCode.BadRequest, "Request must contains $field")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun ApplicationCall.getQueryParameter(
|
fun ApplicationCall.getQueryParameter(
|
||||||
field: String
|
field: String
|
||||||
) = request.queryParameters[field]
|
) = request.queryParameters[field]
|
||||||
|
|
||||||
|
fun ApplicationCall.getQueryParameters(
|
||||||
|
field: String
|
||||||
|
) = request.queryParameters.getAll(field)
|
||||||
|
|
||||||
suspend fun ApplicationCall.getQueryParameterOrSendError(
|
suspend fun ApplicationCall.getQueryParameterOrSendError(
|
||||||
field: String
|
field: String
|
||||||
) = getQueryParameter(field).also {
|
) = getQueryParameter(field).also {
|
||||||
@ -23,3 +35,11 @@ suspend fun ApplicationCall.getQueryParameterOrSendError(
|
|||||||
respond(HttpStatusCode.BadRequest, "Request query parameters must contains $field")
|
respond(HttpStatusCode.BadRequest, "Request query parameters must contains $field")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun ApplicationCall.getQueryParametersOrSendError(
|
||||||
|
field: String
|
||||||
|
) = getQueryParameters(field).also {
|
||||||
|
if (it == null) {
|
||||||
|
respond(HttpStatusCode.BadRequest, "Request query parameters must contains $field")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -21,9 +21,9 @@ open class AutoRecacheWriteCRUDRepo<RegisteredObject, Id, InputObject>(
|
|||||||
protected val idGetter: (RegisteredObject) -> Id
|
protected val idGetter: (RegisteredObject) -> Id
|
||||||
) : WriteCRUDRepo<RegisteredObject, Id, InputObject>, FallbackCacheRepo {
|
) : WriteCRUDRepo<RegisteredObject, Id, InputObject>, FallbackCacheRepo {
|
||||||
override val deletedObjectsIdsFlow: Flow<Id>
|
override val deletedObjectsIdsFlow: Flow<Id>
|
||||||
get() = (originalRepo.deletedObjectsIdsFlow + kvCache.onValueRemoved).distinctUntilChanged()
|
get() = (originalRepo.deletedObjectsIdsFlow).distinctUntilChanged()
|
||||||
override val newObjectsFlow: Flow<RegisteredObject>
|
override val newObjectsFlow: Flow<RegisteredObject>
|
||||||
get() = (originalRepo.newObjectsFlow + kvCache.onNewValue.map { it.second }).distinctUntilChanged()
|
get() = (originalRepo.newObjectsFlow).distinctUntilChanged()
|
||||||
override val updatedObjectsFlow: Flow<RegisteredObject>
|
override val updatedObjectsFlow: Flow<RegisteredObject>
|
||||||
get() = originalRepo.updatedObjectsFlow
|
get() = originalRepo.updatedObjectsFlow
|
||||||
|
|
||||||
|
@ -17,10 +17,10 @@ open class AutoRecacheWriteKeyValueRepo<Id, RegisteredObject>(
|
|||||||
protected val kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache()
|
protected val kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache()
|
||||||
) : WriteKeyValueRepo<Id, RegisteredObject>, FallbackCacheRepo {
|
) : WriteKeyValueRepo<Id, RegisteredObject>, FallbackCacheRepo {
|
||||||
override val onValueRemoved: Flow<Id>
|
override val onValueRemoved: Flow<Id>
|
||||||
get() = (originalRepo.onValueRemoved + kvCache.onValueRemoved).distinctUntilChanged()
|
get() = (originalRepo.onValueRemoved).distinctUntilChanged()
|
||||||
|
|
||||||
override val onNewValue: Flow<Pair<Id, RegisteredObject>>
|
override val onNewValue: Flow<Pair<Id, RegisteredObject>>
|
||||||
get() = (originalRepo.onNewValue + kvCache.onNewValue).distinctUntilChanged()
|
get() = (originalRepo.onNewValue).distinctUntilChanged()
|
||||||
|
|
||||||
private val onRemovingUpdatesListeningJob = originalRepo.onValueRemoved.subscribeSafelyWithoutExceptions(scope) {
|
private val onRemovingUpdatesListeningJob = originalRepo.onValueRemoved.subscribeSafelyWithoutExceptions(scope) {
|
||||||
kvCache.unset(it)
|
kvCache.unset(it)
|
||||||
|
@ -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
|
||||||
@ -24,7 +25,7 @@ open class AutoRecacheWriteKeyValuesRepo<Id, RegisteredObject>(
|
|||||||
override val onNewValue: Flow<Pair<Id, RegisteredObject>>
|
override val onNewValue: Flow<Pair<Id, RegisteredObject>>
|
||||||
get() = originalRepo.onNewValue
|
get() = originalRepo.onNewValue
|
||||||
override val onDataCleared: Flow<Id>
|
override val onDataCleared: Flow<Id>
|
||||||
get() = (originalRepo.onDataCleared + kvCache.onValueRemoved).distinctUntilChanged()
|
get() = (originalRepo.onDataCleared).distinctUntilChanged()
|
||||||
|
|
||||||
private val onDataClearedListeningJob = originalRepo.onDataCleared.subscribeSafelyWithoutExceptions(scope) {
|
private val onDataClearedListeningJob = originalRepo.onDataCleared.subscribeSafelyWithoutExceptions(scope) {
|
||||||
kvCache.unset(it)
|
kvCache.unset(it)
|
||||||
@ -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) ->
|
||||||
|
@ -102,8 +102,15 @@ open class FullCRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.fullyCached(
|
||||||
|
kvCache: FullKVCache<IdType, ObjectType> = FullKVCache(),
|
||||||
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||||
|
idGetter: (ObjectType) -> IdType
|
||||||
|
) = FullCRUDCacheRepo(this, kvCache, scope, idGetter)
|
||||||
|
|
||||||
|
@Deprecated("Renamed", ReplaceWith("this.fullyCached(kvCache, scope, idGetter)", "dev.inmo.micro_utils.repos.cache.full.fullyCached"))
|
||||||
fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.cached(
|
fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.cached(
|
||||||
kvCache: FullKVCache<IdType, ObjectType>,
|
kvCache: FullKVCache<IdType, ObjectType>,
|
||||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||||
idGetter: (ObjectType) -> IdType
|
idGetter: (ObjectType) -> IdType
|
||||||
) = FullCRUDCacheRepo(this, kvCache, scope, idGetter)
|
) = fullyCached(kvCache, scope, idGetter)
|
||||||
|
@ -117,7 +117,13 @@ open class FullKeyValueCacheRepo<Key,Value>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <Key, Value> KeyValueRepo<Key, Value>.fullyCached(
|
||||||
|
kvCache: FullKVCache<Key, Value> = FullKVCache(),
|
||||||
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
|
) = FullKeyValueCacheRepo(this, kvCache, scope)
|
||||||
|
|
||||||
|
@Deprecated("Renamed", ReplaceWith("this.fullyCached(kvCache, scope)", "dev.inmo.micro_utils.repos.cache.full.fullyCached"))
|
||||||
fun <Key, Value> KeyValueRepo<Key, Value>.cached(
|
fun <Key, Value> KeyValueRepo<Key, Value>.cached(
|
||||||
kvCache: FullKVCache<Key, Value>,
|
kvCache: FullKVCache<Key, Value>,
|
||||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
) = FullKeyValueCacheRepo(this, kvCache, scope)
|
) = fullyCached(kvCache, scope)
|
||||||
|
@ -157,8 +157,18 @@ 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(
|
||||||
|
kvCache: FullKVCache<Key, List<Value>> = FullKVCache(),
|
||||||
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
|
) = FullKeyValuesCacheRepo(this, kvCache, scope)
|
||||||
|
|
||||||
|
@Deprecated("Renamed", ReplaceWith("this.fullyCached(kvCache, scope)", "dev.inmo.micro_utils.repos.cache.full.fullyCached"))
|
||||||
fun <Key, Value> KeyValuesRepo<Key, Value>.caching(
|
fun <Key, Value> KeyValuesRepo<Key, Value>.caching(
|
||||||
kvCache: FullKVCache<Key, List<Value>>,
|
kvCache: FullKVCache<Key, List<Value>>,
|
||||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
|
@ -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)
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
package dev.inmo.micro_utils.startup.launcher
|
|
||||||
|
|
||||||
import dev.inmo.micro_utils.startup.launcher.StartLauncherPlugin.setupDI
|
|
||||||
import kotlinx.serialization.json.JsonObject
|
|
||||||
import org.koin.core.KoinApplication
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Will create [KoinApplication], init, load modules using [StartLauncherPlugin] and start plugins using the same base
|
|
||||||
* plugin
|
|
||||||
*
|
|
||||||
* @param rawConfig It is expected that this [JsonObject] will contain serialized [Config] ([StartLauncherPlugin] will
|
|
||||||
* deserialize it in its [StartLauncherPlugin.setupDI]
|
|
||||||
*/
|
|
||||||
@Deprecated("Fully replaced with StartLauncherPlugin#start", ReplaceWith("StartLauncherPlugin.start(rawConfig)", "dev.inmo.micro_utils.startup.launcher.StartLauncherPlugin"))
|
|
||||||
suspend fun start(rawConfig: JsonObject) {
|
|
||||||
StartLauncherPlugin.start(rawConfig)
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
package dev.inmo.micro_utils.startup.launcher
|
|
||||||
|
|
||||||
import dev.inmo.kslog.common.KSLog
|
|
||||||
import dev.inmo.kslog.common.i
|
|
||||||
import kotlinx.serialization.json.JsonObject
|
|
||||||
import kotlinx.serialization.json.jsonObject
|
|
||||||
|
|
||||||
@Deprecated("Useless due to including of the same functionality in StrtLauncherPlugin")
|
|
||||||
object PluginsStarter {
|
|
||||||
init {
|
|
||||||
KSLog.default = KSLog("Launcher")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* It is expected that you have registered all the [dev.inmo.micro_utils.startup.plugin.StartPlugin]s of your JS
|
|
||||||
* app inside of [dev.inmo.micro_utils.startup.plugin.StartPluginSerializer] using its
|
|
||||||
* [dev.inmo.micro_utils.startup.plugin.StartPluginSerializer.registerPlugin] method
|
|
||||||
*/
|
|
||||||
suspend fun startPlugins(json: JsonObject) = StartLauncherPlugin.start(json)
|
|
||||||
/**
|
|
||||||
* Will convert [config] to [JsonObject] with auto registration of [dev.inmo.micro_utils.startup.plugin.StartPlugin]s
|
|
||||||
* in [dev.inmo.micro_utils.startup.plugin.StartPluginSerializer]
|
|
||||||
*/
|
|
||||||
suspend fun startPlugins(config: Config) = StartLauncherPlugin.start(config)
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user