Compare commits

...

14 Commits

15 changed files with 151 additions and 12 deletions

View File

@@ -1,5 +1,17 @@
# Changelog
## 0.4.11
* `Common`
* Add `clamp` function
## 0.4.10
* `Versions`:
* `Klock`: `2.0.0` -> `2.0.1`
* `Repo`
* Repo `WriteStandardKeyValueRepo` got new method `unsetWithValues`
## 0.4.9
* `Versions`:

View File

@@ -1 +1,35 @@
# MicroUtils
# MicroUtils
This is a library with collection of tools for working in Kotlin environment. First of all, this library collection is oriented to use next technologies:
* [`Kotlin Coroutines`](https://github.com/Kotlin/kotlinx.coroutines)
* [`Kotlin Serialization`](https://github.com/Kotlin/kotlinx.serialization)
* [`Kotlin Exposed`](https://github.com/JetBrains/Exposed)
* [`Ktor`](https://ktor.io)
<details>
<summary> <b>Android environment</b> </summary>
You always can look at the <a href="https://github.com/InsanusMokrassar/MicroUtils/blob/master/gradle.properties#L24-L34">properties file</a> to get information about current project dependencies, compile and build tools for `Android` target.
</details>
## Projects
* `common` contains common tools for platform which usually are absent out-of-the-box when you starting project
* `coroutines` is a module for `Kotlin Coroutines` with different things like subscribing on flows (`onEach` + `launchIn` shortcut :) )
* `ktor` is a set of modules for `client`s and `server`s
* `mime_types` is NOT lightweight set of `MimeType`s with a lot of different objected and serializable (with `Kotlin Serialization`) mime types
* `pagination` is a complex of modules (explanation in [Complex modules structure](#complex-modules-structure) section) for lightweight pagination
* `repos` is a complex of modules (explanation in [Complex modules structure](#complex-modules-structure) section) for `KeyValue`/`OneToMany`/`CRUD` repos created to be able to exclude some heavy dependencies when you need some simple and lightweight typical repositories
## Complex modules structure
Most of complex modules are built with next hierarchy:
* `common` submodule for `API` things which are common for all platforms
* `exposed` submodule contains realizations for exposed tables
* `ktor` submodule is usually unavailable directly, because it contains its own submodules for clients and servers
* `common` part contains routes which are common for clients and servers
* `client` submodule contains clients which are usually using `UnifiedRequester` to make requests using routes from `ktor/common` module and some internal logic of requests
* `server` submodule (in most cases `JVM`-only) contains some extensions for `Route` instances which usually will give opportunity to proxy internet requests from `ktor/client` realization to some proxy object

1
_config.yml Normal file
View File

@@ -0,0 +1 @@
theme: jekyll-theme-cayman

View File

@@ -0,0 +1,10 @@
package dev.inmo.micro_utils.common
@Suppress("NOTHING_TO_INLINE")
inline fun <T : Comparable<T>> T.clamp(min: T, max: T): T {
return when {
this < min -> min
this > max -> max
else -> this
}
}

View File

@@ -13,7 +13,7 @@ kotlin_exposed_version=0.28.1
ktor_version=1.4.3
klockVersion=2.0.0
klockVersion=2.0.1
github_release_plugin_version=2.2.12
@@ -35,10 +35,10 @@ espresso_core=3.3.0
# Dokka
dokka_version=1.4.10.2
dokka_version=1.4.20
# Project data
group=dev.inmo
version=0.4.9
android_code_version=13
version=0.4.11
android_code_version=15

View File

@@ -1,7 +1,6 @@
package dev.inmo.micro_utils.repos
import dev.inmo.micro_utils.pagination.Pagination
import dev.inmo.micro_utils.pagination.PaginationResult
import dev.inmo.micro_utils.pagination.*
import kotlinx.coroutines.flow.Flow
interface ReadStandardKeyValueRepo<Key, Value> : Repo {
@@ -20,6 +19,7 @@ interface WriteStandardKeyValueRepo<Key, Value> : Repo {
suspend fun set(toSet: Map<Key, Value>)
suspend fun unset(toUnset: List<Key>)
suspend fun unsetWithValues(toUnset: List<Value>)
}
typealias WriteKeyValueRepo<Key,Value> = WriteStandardKeyValueRepo<Key, Value>
@@ -35,5 +35,17 @@ suspend inline fun <Key, Value> WriteStandardKeyValueRepo<Key, Value>.unset(
vararg k: Key
) = unset(k.toList())
interface StandardKeyValueRepo<Key, Value> : ReadStandardKeyValueRepo<Key, Value>, WriteStandardKeyValueRepo<Key, Value>
suspend inline fun <Key, Value> WriteStandardKeyValueRepo<Key, Value>.unsetWithValues(
vararg v: Value
) = unsetWithValues(v.toList())
interface StandardKeyValueRepo<Key, Value> : ReadStandardKeyValueRepo<Key, Value>, WriteStandardKeyValueRepo<Key, Value> {
override suspend fun unsetWithValues(toUnset: List<Value>) = toUnset.forEach { v ->
doWithPagination {
keys(v, it).also {
unset(it.results)
}
}
}
}
typealias KeyValueRepo<Key,Value> = StandardKeyValueRepo<Key, Value>

View File

@@ -105,6 +105,10 @@ open class MapperWriteStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
k.toOutKey()
}
)
override suspend fun unsetWithValues(toUnset: List<FromValue>) = to.unsetWithValues(
toUnset.map { it.toOutValue() }
)
}
@Suppress("NOTHING_TO_INLINE")

View File

@@ -160,6 +160,18 @@ class FileWriteStandardKeyValueRepo(
}
}
}
override suspend fun unsetWithValues(toUnset: List<File>) {
val keys = toUnset.mapNotNull { v ->
val key = v.absolutePath.removePrefix(folder.absolutePath)
if (key != v.absolutePath) {
key
} else {
null
}
}
unset(keys)
}
}
@Warning("Files watching will not correctly works on Android Platform with version of API lower than API 26")

View File

@@ -35,10 +35,10 @@ class KeyValueStore<T : Any> internal constructor (
}
private val onNewValueChannel = MutableSharedFlow<Pair<String, T>>()
private val onValueRemovedChannel = MutableSharedFlow<String>()
private val _onValueRemovedFlow = MutableSharedFlow<String>()
override val onNewValue: Flow<Pair<String, T>> = onNewValueChannel.asSharedFlow()
override val onValueRemoved: Flow<String> = onValueRemovedChannel.asSharedFlow()
override val onValueRemoved: Flow<String> = _onValueRemovedFlow.asSharedFlow()
init {
cachedData ?.let {
@@ -136,6 +136,18 @@ class KeyValueStore<T : Any> internal constructor (
sharedPreferences.edit {
toUnset.forEach { remove(it) }
}
toUnset.forEach { onValueRemovedChannel.emit(it) }
toUnset.forEach { _onValueRemovedFlow.emit(it) }
}
override suspend fun unsetWithValues(toUnset: List<T>) {
val keysToRemove = sharedPreferences.all.mapNotNull { if (it.value in toUnset) it.key else null }
sharedPreferences.edit {
keysToRemove.map {
remove(it)
}
}
keysToRemove.forEach {
_onValueRemovedFlow.emit(it)
}
}
}

View File

@@ -60,4 +60,16 @@ open class ExposedKeyValueRepo<Key, Value>(
_onValueRemoved.emit(it)
}
}
override suspend fun unsetWithValues(toUnset: List<Value>) {
transaction(database) {
toUnset.flatMap {
val keys = select { valueColumn.eq(it) }.mapNotNull { it[keyColumn] }
deleteWhere { keyColumn.inList(keys) }
keys
}
}.distinct().forEach {
_onValueRemoved.emit(it)
}
}
}

View File

@@ -76,6 +76,15 @@ class WriteMapKeyValueRepo<Key, Value>(
map.remove(k) ?.also { _ -> _onValueRemoved.emit(k) }
}
}
override suspend fun unsetWithValues(toUnset: List<Value>) {
map.forEach {
if (it.value in toUnset) {
map.remove(it.key)
_onValueRemoved.emit(it.key)
}
}
}
}
class MapKeyValueRepo<Key, Value>(

View File

@@ -7,6 +7,7 @@ import dev.inmo.micro_utils.repos.*
import io.ktor.client.HttpClient
import kotlinx.serialization.*
@Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE")
class KtorStandartKeyValueRepo<K, V> (
baseUrl: String,
baseSubpart: String,

View File

@@ -17,6 +17,7 @@ class KtorWriteStandardKeyValueRepo<K, V> (
) : WriteStandardKeyValueRepo<K, V> {
private val keyValueMapSerializer = MapSerializer(keySerializer, valueSerializer)
private val keysListSerializer = ListSerializer(keySerializer)
private val valuesListSerializer = ListSerializer(valueSerializer)
constructor(
baseUrl: String,
@@ -55,4 +56,13 @@ class KtorWriteStandardKeyValueRepo<K, V> (
BodyPair(keysListSerializer, toUnset),
Unit.serializer()
)
override suspend fun unsetWithValues(toUnset: List<V>) = unifiedRequester.unipost(
buildStandardUrl(
baseUrl,
unsetWithValuesRoute,
),
BodyPair(valuesListSerializer, toUnset),
Unit.serializer()
)
}

View File

@@ -9,4 +9,5 @@ const val countRoute = "count"
const val onNewValueRoute = "onNewValue"
const val onValueRemovedRoute = "onValueRemoved"
const val setRoute = "set"
const val unsetRoute = "unset"
const val unsetRoute = "unset"
const val unsetWithValuesRoute = "unsetWithValues"

View File

@@ -19,6 +19,7 @@ fun <K, V> Route.configureWriteStandardKeyValueRepoRoutes (
) {
val keyValueMapSerializer = MapSerializer(keySerializer, valueSerializer)
val keysListSerializer = ListSerializer(keySerializer)
val valuesListSerializer = ListSerializer(valueSerializer)
unifiedRouter.apply {
includeWebsocketHandling(
onNewValueRoute,
@@ -50,6 +51,14 @@ fun <K, V> Route.configureWriteStandardKeyValueRepoRoutes (
unianswer(Unit.serializer(), originalRepo.unset(toUnset))
}
}
post(unsetWithValuesRoute) {
unifiedRouter.apply {
val toUnset = uniload(valuesListSerializer)
unianswer(Unit.serializer(), originalRepo.unsetWithValues(toUnset))
}
}
}
fun <K, V> Route.configureWriteStandartKeyValueRepoRoutes (