Compare commits

...

31 Commits

Author SHA1 Message Date
90c0817b6d add clamp 2020-12-07 22:39:23 +06:00
527f7bbafe start 0.4.11 2020-12-07 22:36:32 +06:00
765a32729f Update README.md 2020-12-05 19:01:36 +06:00
de783f77a2 Update README.md 2020-12-05 18:59:28 +06:00
de4c8d104c Set theme jekyll-theme-cayman 2020-12-05 18:57:46 +06:00
88c8c28f45 Update README.md 2020-12-05 18:57:12 +06:00
57b36826d1 Merge pull request #29 from InsanusMokrassar/0.4.10
0.4.10
2020-12-05 18:36:24 +06:00
f81a2f309b add new unseWithValues extensions 2020-12-05 18:12:17 +06:00
5fc760f4a5 fix build and add filestandardkeyvaluerepo unsetWithValues realization 2020-12-05 18:00:27 +06:00
091cb38339 WriteStandardKeyValueRepo#unsetWithValues 2020-12-05 17:52:37 +06:00
3ae9b3e576 update klock dependency 2020-12-05 17:29:49 +06:00
b03b4cbeec start 0.4.10 2020-12-05 17:25:43 +06:00
f2c1b3c76a Merge pull request #27 from InsanusMokrassar/0.4.9
add Synchronously
2020-12-02 17:29:27 +06:00
f3bec34882 add Synchronously 2020-12-02 17:28:59 +06:00
d6aa9fe9c2 Merge pull request #26 from InsanusMokrassar/0.4.9
0.4.9
2020-12-02 16:41:50 +06:00
2d5304a770 BroadcastChannel -> MutableSharedFlow in repos 2020-12-02 16:39:04 +06:00
88f2c16c82 crud exposed realization open fun asObject 2020-12-02 16:28:08 +06:00
490c318d1c update ktor 2020-12-02 16:21:31 +06:00
8beaf61a08 start 0.4.9 2020-12-02 16:13:54 +06:00
8b61c984eb Merge pull request #25 from InsanusMokrassar/0.4.8
0.4.8
2020-12-01 15:52:07 +06:00
e38094df58 change order in iterable to skip changing of pagination on no left elements error 2020-12-01 15:48:37 +06:00
c25e3f5867 update versions 2020-12-01 15:38:44 +06:00
f78e81d175 PaginatedIterable 2020-12-01 15:34:12 +06:00
3837ae237d start 0.4.8 2020-12-01 15:11:18 +06:00
2b6ef8b4ff Merge pull request #24 from InsanusMokrassar/0.4.7
0.4.7
2020-11-27 19:30:40 +06:00
6cc0eefb3e upfix of default in includeWebsocketHandling 2020-11-27 17:53:29 +06:00
ab11e28bf7 UnifiedRouter 2020-11-27 14:35:00 +06:00
26d5f5a5f5 UnifiedRequester 2020-11-27 13:30:02 +06:00
74ae91cba6 start 0.4.7 2020-11-27 11:57:40 +06:00
70509c7edd update wrapper 2020-11-26 22:50:44 +06:00
5a69bd6c63 Merge pull request #23 from InsanusMokrassar/0.4.6
0.4.6
2020-11-26 22:50:08 +06:00
42 changed files with 1055 additions and 415 deletions

View File

@@ -1,5 +1,51 @@
# Changelog # 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`:
* `Ktor`: `1.4.2` -> `1.4.3`
* `Coroutines`:
* `launchSynchronously` has been added in JVM
* `Repo`
* `Common`
* In repos different usages of `BroadcastChannel`s has been replaced with `MutableSharedFlow`
* `Exposed`
* `asObject` open fun has been added in CRUD realization
## 0.4.8
* `Versions`:
* `Coroutines`: `1.4.1` -> `1.4.2`
* `UUID`: `0.2.2` -> `0.2.3`
* `Pagination`
* Add `PaginatedIterable` and `PaginatedIterator`
## 0.4.7
* `Ktor`
* `Client`
* New class `UnifiedRequester`
* `Server`
* New class `UnifiedRouter`
* `Repos`
* `Ktor`
* `Client`
* Rewriting of all clients on new `UnifiedRequester`
* `Server`
* Rewriting of all clients on new `UnifiedRouter`
## 0.4.6 ## 0.4.6
* `Common` * `Common`

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

@@ -0,0 +1,28 @@
package dev.inmo.micro_utils.coroutines
import kotlinx.coroutines.*
fun <T> launchSynchronously(scope: CoroutineScope = CoroutineScope(Dispatchers.Default), block: suspend CoroutineScope.() -> T): T {
var throwable: Throwable? = null
var result: T? = null
val objectToSynchronize = java.lang.Object()
val launchCallback = {
scope.launch {
safely(
{
throwable = it
}
) {
result = block()
}
synchronized(objectToSynchronize) {
objectToSynchronize.notifyAll()
}
}
}
synchronized(objectToSynchronize) {
launchCallback()
objectToSynchronize.wait()
}
throw throwable ?: return result!!
}

View File

@@ -0,0 +1,13 @@
package dev.inmo.micro_utils.coroutines
import kotlin.test.Test
import kotlin.test.assertEquals
class LaunchSynchronouslyTest {
@Test
fun testRunInCoroutine() {
(0 .. 10000).forEach {
assertEquals(it, launchSynchronously { it })
}
}
}

View File

@@ -1,3 +1,5 @@
apply plugin: 'com.getkeepsafe.dexcount'
android { android {
compileSdkVersion "$android_compileSdkVersion".toInteger() compileSdkVersion "$android_compileSdkVersion".toInteger()
buildToolsVersion "$android_buildToolsVersion" buildToolsVersion "$android_buildToolsVersion"

View File

@@ -5,20 +5,19 @@ kotlin.incremental=true
kotlin.incremental.js=true kotlin.incremental.js=true
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
org.gradle.jvmargs=-Xmx2048m
kotlin_version=1.4.20 kotlin_version=1.4.20
kotlin_coroutines_version=1.4.1 kotlin_coroutines_version=1.4.2
kotlin_serialisation_core_version=1.0.1 kotlin_serialisation_core_version=1.0.1
kotlin_exposed_version=0.28.1 kotlin_exposed_version=0.28.1
ktor_version=1.4.2 ktor_version=1.4.3
klockVersion=2.0.0 klockVersion=2.0.1
github_release_plugin_version=2.2.12 github_release_plugin_version=2.2.12
uuidVersion=0.2.2 uuidVersion=0.2.3
# ANDROID # ANDROID
@@ -29,17 +28,17 @@ appcompat_version=1.2.0
android_minSdkVersion=19 android_minSdkVersion=19
android_compileSdkVersion=30 android_compileSdkVersion=30
android_buildToolsVersion=30.0.2 android_buildToolsVersion=30.0.2
dexcount_version=2.0.0-RC1 dexcount_version=2.0.0
junit_version=4.12 junit_version=4.12
test_ext_junit_version=1.1.2 test_ext_junit_version=1.1.2
espresso_core=3.3.0 espresso_core=3.3.0
# Dokka # Dokka
dokka_version=1.4.0 dokka_version=1.4.20
# Project data # Project data
group=dev.inmo group=dev.inmo
version=0.4.6 version=0.4.11
android_code_version=10 android_code_version=15

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -64,10 +64,11 @@ inline fun <T> HttpClient.createStandardWebsocketFlow(
inline fun <T> HttpClient.createStandardWebsocketFlow( inline fun <T> HttpClient.createStandardWebsocketFlow(
url: String, url: String,
crossinline checkReconnection: (Throwable?) -> Boolean = { true }, crossinline checkReconnection: (Throwable?) -> Boolean = { true },
deserializer: DeserializationStrategy<T> deserializer: DeserializationStrategy<T>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
) = createStandardWebsocketFlow( ) = createStandardWebsocketFlow(
url, url,
checkReconnection checkReconnection
) { ) {
standardKtorSerialFormat.decodeDefault(deserializer, it) serialFormat.decodeDefault(deserializer, it)
} }

View File

@@ -4,32 +4,61 @@ import dev.inmo.micro_utils.ktor.common.*
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.request.get import io.ktor.client.request.get
import io.ktor.client.request.post import io.ktor.client.request.post
import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.*
import kotlinx.serialization.SerializationStrategy
typealias BodyPair<T> = Pair<SerializationStrategy<T>, T> typealias BodyPair<T> = Pair<SerializationStrategy<T>, T>
class UnifiedRequester(
private val client: HttpClient = HttpClient(),
private val serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
) {
suspend fun <ResultType> uniget(
url: String,
resultDeserializer: DeserializationStrategy<ResultType>
): ResultType = client.get<StandardKtorSerialInputData>(
url
).let {
serialFormat.decodeDefault(resultDeserializer, it)
}
fun <T> encodeUrlQueryValue(
serializationStrategy: SerializationStrategy<T>,
value: T
) = serialFormat.encodeHex(
serializationStrategy,
value
)
suspend fun <BodyType, ResultType> unipost(
url: String,
bodyInfo: BodyPair<BodyType>,
resultDeserializer: DeserializationStrategy<ResultType>
) = client.post<StandardKtorSerialInputData>(url) {
body = serialFormat.encodeDefault(bodyInfo.first, bodyInfo.second)
}.let {
serialFormat.decodeDefault(resultDeserializer, it)
}
fun <T> createStandardWebsocketFlow(
url: String,
checkReconnection: (Throwable?) -> Boolean = { true },
deserializer: DeserializationStrategy<T>
) = client.createStandardWebsocketFlow(url, checkReconnection, deserializer, serialFormat)
}
val defaultRequester = UnifiedRequester()
suspend fun <ResultType> HttpClient.uniget( suspend fun <ResultType> HttpClient.uniget(
url: String, url: String,
resultDeserializer: DeserializationStrategy<ResultType> resultDeserializer: DeserializationStrategy<ResultType>
) = get<StandardKtorSerialInputData>( ) = defaultRequester.uniget(url, resultDeserializer)
url
).let {
standardKtorSerialFormat.decodeDefault(resultDeserializer, it)
}
fun <T> SerializationStrategy<T>.encodeUrlQueryValue(value: T) = standardKtorSerialFormat.encodeHex( fun <T> SerializationStrategy<T>.encodeUrlQueryValue(value: T) = defaultRequester.encodeUrlQueryValue(this, value)
this,
value
)
suspend fun <BodyType, ResultType> HttpClient.unipost( suspend fun <BodyType, ResultType> HttpClient.unipost(
url: String, url: String,
bodyInfo: BodyPair<BodyType>, bodyInfo: BodyPair<BodyType>,
resultDeserializer: DeserializationStrategy<ResultType> resultDeserializer: DeserializationStrategy<ResultType>
) = post<StandardKtorSerialInputData>(url) { ) = defaultRequester.unipost(url, bodyInfo, resultDeserializer)
body = standardKtorSerialFormat.encodeDefault(bodyInfo.first, bodyInfo.second)
}.let {
standardKtorSerialFormat.decodeDefault(resultDeserializer, it)
}

View File

@@ -33,10 +33,11 @@ fun <T> Route.includeWebsocketHandling(
fun <T> Route.includeWebsocketHandling( fun <T> Route.includeWebsocketHandling(
suburl: String, suburl: String,
flow: Flow<T>, flow: Flow<T>,
serializer: SerializationStrategy<T> serializer: SerializationStrategy<T>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
) = includeWebsocketHandling( ) = includeWebsocketHandling(
suburl, suburl,
flow flow
) { ) {
standardKtorSerialFormat.encodeDefault(serializer, it) serialFormat.encodeDefault(serializer, it)
} }

View File

@@ -3,12 +3,87 @@ package dev.inmo.micro_utils.ktor.server
import dev.inmo.micro_utils.coroutines.safely import dev.inmo.micro_utils.coroutines.safely
import dev.inmo.micro_utils.ktor.common.* import dev.inmo.micro_utils.ktor.common.*
import io.ktor.application.ApplicationCall import io.ktor.application.ApplicationCall
import io.ktor.application.call
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.request.receive import io.ktor.request.receive
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.response.respondBytes import io.ktor.response.respondBytes
import kotlinx.serialization.DeserializationStrategy import io.ktor.routing.Route
import kotlinx.serialization.SerializationStrategy import io.ktor.util.pipeline.PipelineContext
import kotlinx.coroutines.flow.Flow
import kotlinx.serialization.*
class UnifiedRouter(
private val serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
private val serialFormatContentType: ContentType = standardKtorSerialFormatContentType
) {
fun <T> Route.includeWebsocketHandling(
suburl: String,
flow: Flow<T>,
serializer: SerializationStrategy<T>
) = includeWebsocketHandling(suburl, flow, serializer, serialFormat)
suspend fun <T> PipelineContext<*, ApplicationCall>.unianswer(
answerSerializer: SerializationStrategy<T>,
answer: T
) {
call.respondBytes (
serialFormat.encodeDefault(answerSerializer, answer),
serialFormatContentType
)
}
suspend fun <T> PipelineContext<*, ApplicationCall>.uniload(
deserializer: DeserializationStrategy<T>
) = safely {
serialFormat.decodeDefault(
deserializer,
call.receive()
)
}
suspend fun PipelineContext<*, ApplicationCall>.getParameterOrSendError(
field: String
) = call.parameters[field].also {
if (it == null) {
call.respond(HttpStatusCode.BadRequest, "Request must contains $field")
}
}
fun PipelineContext<*, ApplicationCall>.getQueryParameter(
field: String
) = call.request.queryParameters[field]
suspend fun PipelineContext<*, ApplicationCall>.getQueryParameterOrSendError(
field: String
) = getQueryParameter(field).also {
if (it == null) {
call.respond(HttpStatusCode.BadRequest, "Request query parameters must contains $field")
}
}
fun <T> PipelineContext<*, ApplicationCall>.decodeUrlQueryValue(
field: String,
deserializer: DeserializationStrategy<T>
) = getQueryParameter(field) ?.let {
serialFormat.decodeHex(
deserializer,
it
)
}
suspend fun <T> PipelineContext<*, ApplicationCall>.decodeUrlQueryValueOrSendError(
field: String,
deserializer: DeserializationStrategy<T>
) = decodeUrlQueryValue(field, deserializer).also {
if (it == null) {
call.respond(HttpStatusCode.BadRequest, "Request query parameters must contains $field")
}
}
}
val defaultUnifiedRouter = UnifiedRouter()
suspend fun <T> ApplicationCall.unianswer( suspend fun <T> ApplicationCall.unianswer(
answerSerializer: SerializationStrategy<T>, answerSerializer: SerializationStrategy<T>,

View File

@@ -0,0 +1,41 @@
package dev.inmo.micro_utils.pagination.utils
import dev.inmo.micro_utils.pagination.*
class PaginatedIterator<T>(
pageSize: Int,
private val countGetter: () -> Long,
private val paginationResultGetter: Pagination.() -> PaginationResult<T>
) : Iterator<T> {
private var pagination = FirstPagePagination(pageSize)
private val currentStack = mutableListOf<T>()
override fun hasNext(): Boolean = currentStack.isNotEmpty() || (countGetter() < pagination.lastIndexExclusive)
override fun next(): T {
if (currentStack.isEmpty()) {
val resultPagination = paginationResultGetter.invoke(pagination)
currentStack.addAll(resultPagination.results)
require(currentStack.isNotEmpty()) { "There is no elements left" }
pagination = resultPagination.nextPage()
}
return currentStack.removeFirst()
}
}
class PaginatedIterable<T>(
private val pageSize: Int,
private val countGetter: () -> Long,
private val paginationResultGetter: Pagination.() -> PaginationResult<T>
) : Iterable<T> {
override fun iterator(): Iterator<T> = PaginatedIterator(pageSize, countGetter, paginationResultGetter)
}
/**
* Will make iterable using incoming [countGetter] and [paginationResultGetter]
*/
@Suppress("NOTHING_TO_INLINE")
inline fun <T> makeIterable(
noinline countGetter: () -> Long,
pageSize: Int = defaultMediumPageSize,
noinline paginationResultGetter: Pagination.() -> PaginationResult<T>
): Iterable<T> = PaginatedIterable(pageSize, countGetter, paginationResultGetter)

View File

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

View File

@@ -105,6 +105,10 @@ open class MapperWriteStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
k.toOutKey() k.toOutKey()
} }
) )
override suspend fun unsetWithValues(toUnset: List<FromValue>) = to.unsetWithValues(
toUnset.map { it.toOutValue() }
)
} }
@Suppress("NOTHING_TO_INLINE") @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") @Warning("Files watching will not correctly works on Android Platform with version of API lower than API 26")

View File

@@ -3,20 +3,18 @@ package dev.inmo.micro_utils.repos.crud
import android.content.ContentValues import android.content.ContentValues
import dev.inmo.micro_utils.common.mapNotNullA import dev.inmo.micro_utils.common.mapNotNullA
import dev.inmo.micro_utils.repos.* import dev.inmo.micro_utils.repos.*
import kotlinx.coroutines.channels.BroadcastChannel import kotlinx.coroutines.flow.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow
abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType>( abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType>(
helper: StandardSQLHelper helper: StandardSQLHelper
) : WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>, ) : WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>,
AbstractAndroidCRUDRepo<ObjectType, IdType>(helper) { AbstractAndroidCRUDRepo<ObjectType, IdType>(helper) {
protected val newObjectsChannel = BroadcastChannel<ObjectType>(64) protected val newObjectsChannel = MutableSharedFlow<ObjectType>(64)
protected val updateObjectsChannel = BroadcastChannel<ObjectType>(64) protected val updateObjectsChannel = MutableSharedFlow<ObjectType>(64)
protected val deleteObjectsIdsChannel = BroadcastChannel<IdType>(64) protected val deleteObjectsIdsChannel = MutableSharedFlow<IdType>(64)
override val newObjectsFlow: Flow<ObjectType> = newObjectsChannel.asFlow() override val newObjectsFlow: Flow<ObjectType> = newObjectsChannel.asSharedFlow()
override val updatedObjectsFlow: Flow<ObjectType> = updateObjectsChannel.asFlow() override val updatedObjectsFlow: Flow<ObjectType> = updateObjectsChannel.asSharedFlow()
override val deletedObjectsIdsFlow: Flow<IdType> = deleteObjectsIdsChannel.asFlow() override val deletedObjectsIdsFlow: Flow<IdType> = deleteObjectsIdsChannel.asSharedFlow()
protected abstract suspend fun InputValueType.asContentValues(id: IdType? = null): ContentValues protected abstract suspend fun InputValueType.asContentValues(id: IdType? = null): ContentValues
@@ -42,7 +40,7 @@ abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType
} }
}.also { }.also {
it.forEach { it.forEach {
newObjectsChannel.send(it) newObjectsChannel.emit(it)
} }
} }
} }
@@ -59,7 +57,7 @@ abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType
} }
} }
deleted.forEach { deleted.forEach {
deleteObjectsIdsChannel.send(it) deleteObjectsIdsChannel.emit(it)
} }
} }
@@ -76,7 +74,7 @@ abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType
} }
} }
return getById(id) ?.also { return getById(id) ?.also {
updateObjectsChannel.send(it) updateObjectsChannel.emit(it)
} }
} }
@@ -95,7 +93,7 @@ abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType
getById(it.first) getById(it.first)
}.also { }.also {
it.forEach { it.forEach {
updateObjectsChannel.send(it) updateObjectsChannel.emit(it)
} }
} }
} }

View File

@@ -8,10 +8,7 @@ import dev.inmo.micro_utils.pagination.PaginationResult
import dev.inmo.micro_utils.pagination.utils.paginate import dev.inmo.micro_utils.pagination.utils.paginate
import dev.inmo.micro_utils.pagination.utils.reverse import dev.inmo.micro_utils.pagination.utils.reverse
import dev.inmo.micro_utils.repos.StandardKeyValueRepo import dev.inmo.micro_utils.repos.StandardKeyValueRepo
import kotlinx.coroutines.channels.BroadcastChannel import kotlinx.coroutines.flow.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow
private val cache = HashMap<String, KeyValueStore<*>>() private val cache = HashMap<String, KeyValueStore<*>>()
@@ -37,11 +34,11 @@ class KeyValueStore<T : Any> internal constructor (
null null
} }
private val onNewValueChannel = BroadcastChannel<Pair<String, T>>(Channel.BUFFERED) private val onNewValueChannel = MutableSharedFlow<Pair<String, T>>()
private val onValueRemovedChannel = BroadcastChannel<String>(Channel.BUFFERED) private val _onValueRemovedFlow = MutableSharedFlow<String>()
override val onNewValue: Flow<Pair<String, T>> = onNewValueChannel.asFlow() override val onNewValue: Flow<Pair<String, T>> = onNewValueChannel.asSharedFlow()
override val onValueRemoved: Flow<String> = onValueRemovedChannel.asFlow() override val onValueRemoved: Flow<String> = _onValueRemovedFlow.asSharedFlow()
init { init {
cachedData ?.let { cachedData ?.let {
@@ -131,7 +128,7 @@ class KeyValueStore<T : Any> internal constructor (
} }
} }
toSet.forEach { (k, v) -> toSet.forEach { (k, v) ->
onNewValueChannel.send(k to v) onNewValueChannel.emit(k to v)
} }
} }
@@ -139,6 +136,18 @@ class KeyValueStore<T : Any> internal constructor (
sharedPreferences.edit { sharedPreferences.edit {
toUnset.forEach { remove(it) } toUnset.forEach { remove(it) }
} }
toUnset.forEach { onValueRemovedChannel.send(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

@@ -32,11 +32,11 @@ class AndroidSQLStandardVersionsRepoProxy(
} }
} }
override suspend fun getTableVersion(table: String): Int? = database.writableTransaction { override suspend fun getTableVersion(tableName: String): Int? = database.writableTransaction {
select( select(
tableName, this@AndroidSQLStandardVersionsRepoProxy.tableName,
selection = "$tableNameColumnName=?", selection = "$tableNameColumnName=?",
selectionArgs = arrayOf(table), selectionArgs = arrayOf(tableName),
limit = limitClause(1) limit = limitClause(1)
).use { ).use {
if (it.moveToFirst()) { if (it.moveToFirst()) {
@@ -47,16 +47,16 @@ class AndroidSQLStandardVersionsRepoProxy(
} }
} }
override suspend fun updateTableVersion(table: String, version: Int) { override suspend fun updateTableVersion(tableName: String, version: Int) {
database.writableTransaction { database.writableTransaction {
val updated = update( val updated = update(
tableName, this@AndroidSQLStandardVersionsRepoProxy.tableName,
contentValuesOf(tableVersionColumnName to version), contentValuesOf(tableVersionColumnName to version),
"$tableNameColumnName=?", "$tableNameColumnName=?",
arrayOf(table) arrayOf(tableName)
) > 0 ) > 0
if (!updated) { if (!updated) {
insert(tableName, null, contentValuesOf(tableNameColumnName to table, tableVersionColumnName to version)) insert(this@AndroidSQLStandardVersionsRepoProxy.tableName, null, contentValuesOf(tableNameColumnName to tableName, tableVersionColumnName to version))
} }
} }
} }

View File

@@ -2,7 +2,6 @@ package dev.inmo.micro_utils.repos.exposed
import dev.inmo.micro_utils.repos.UpdatedValuePair import dev.inmo.micro_utils.repos.UpdatedValuePair
import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo
import kotlinx.coroutines.channels.BroadcastChannel
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.statements.InsertStatement import org.jetbrains.exposed.sql.statements.InsertStatement
@@ -25,8 +24,10 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
override val updatedObjectsFlow: Flow<ObjectType> = updateObjectsChannel.asSharedFlow() override val updatedObjectsFlow: Flow<ObjectType> = updateObjectsChannel.asSharedFlow()
override val deletedObjectsIdsFlow: Flow<IdType> = deleteObjectsIdsChannel.asSharedFlow() override val deletedObjectsIdsFlow: Flow<IdType> = deleteObjectsIdsChannel.asSharedFlow()
@Deprecated("Will be removed in near major update. Override open fun with the same name instead")
abstract val InsertStatement<Number>.asObject: ObjectType abstract val InsertStatement<Number>.asObject: ObjectType
abstract val selectByIds: SqlExpressionBuilder.(List<out IdType>) -> Op<Boolean> protected open fun InsertStatement<Number>.asObject(value: InputValueType): ObjectType = asObject
abstract val selectByIds: SqlExpressionBuilder.(List<IdType>) -> Op<Boolean>
protected abstract fun insert(value: InputValueType, it: InsertStatement<Number>) protected abstract fun insert(value: InputValueType, it: InsertStatement<Number>)
protected abstract fun update(id: IdType, value: InputValueType, it: UpdateStatement) protected abstract fun update(id: IdType, value: InputValueType, it: UpdateStatement)
@@ -34,7 +35,7 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
protected open suspend fun onBeforeCreate(value: List<InputValueType>) {} protected open suspend fun onBeforeCreate(value: List<InputValueType>) {}
private fun createWithoutNotification(value: InputValueType): ObjectType { private fun createWithoutNotification(value: InputValueType): ObjectType {
return transaction(database) { return transaction(database) {
insert { insert(value, it) }.asObject insert { insert(value, it) }.asObject(value)
} }
} }
@@ -42,10 +43,8 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
onBeforeCreate(values) onBeforeCreate(values)
return transaction(db = database) { return transaction(db = database) {
values.map { value -> createWithoutNotification(value) } values.map { value -> createWithoutNotification(value) }
}.also { }.onEach {
it.forEach { newObjectsChannel.emit(it)
newObjectsChannel.emit(it)
}
} }
} }
@@ -83,13 +82,9 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
return ( return (
transaction(db = database) { transaction(db = database) {
values.map { (id, value) -> updateWithoutNotification(id, value) } values.map { (id, value) -> updateWithoutNotification(id, value) }
}.filter { }.filterNotNull()
it != null ).onEach {
} as List<ObjectType> updateObjectsChannel.emit(it)
).also {
it.forEach {
updateObjectsChannel.emit(it)
}
} }
} }
protected open suspend fun onBeforeDelete(ids: List<IdType>) {} protected open suspend fun onBeforeDelete(ids: List<IdType>) {}

View File

@@ -60,4 +60,16 @@ open class ExposedKeyValueRepo<Key, Value>(
_onValueRemoved.emit(it) _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) } 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>( class MapKeyValueRepo<Key, Value>(

View File

@@ -1,8 +1,7 @@
package dev.inmo.micro_utils.repos.ktor.client.crud package dev.inmo.micro_utils.repos.ktor.client.crud
import dev.inmo.micro_utils.ktor.client.encodeUrlQueryValue import dev.inmo.micro_utils.ktor.client.*
import dev.inmo.micro_utils.ktor.client.uniget import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.ktor.common.buildStandardUrl
import dev.inmo.micro_utils.pagination.* import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
import dev.inmo.micro_utils.repos.ktor.common.crud.* import dev.inmo.micro_utils.repos.ktor.common.crud.*
@@ -12,41 +11,52 @@ import kotlinx.serialization.builtins.serializer
class KtorReadStandardCrudRepo<ObjectType, IdType> ( class KtorReadStandardCrudRepo<ObjectType, IdType> (
private val baseUrl: String, private val baseUrl: String,
private val client: HttpClient = HttpClient(), private val unifiedRequester: UnifiedRequester,
private val objectsSerializer: KSerializer<ObjectType>, private val objectsSerializer: KSerializer<ObjectType>,
private val objectsSerializerNullable: KSerializer<ObjectType?>, private val objectsSerializerNullable: KSerializer<ObjectType?>,
private val idsSerializer: KSerializer<IdType> private val idsSerializer: KSerializer<IdType>
) : ReadStandardCRUDRepo<ObjectType, IdType> { ) : ReadStandardCRUDRepo<ObjectType, IdType> {
private val paginationResultSerializer = PaginationResult.serializer(objectsSerializer) private val paginationResultSerializer = PaginationResult.serializer(objectsSerializer)
override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> = client.uniget( constructor(
baseUrl: String,
client: HttpClient,
objectsSerializer: KSerializer<ObjectType>,
objectsSerializerNullable: KSerializer<ObjectType?>,
idsSerializer: KSerializer<IdType>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
) : this (
baseUrl, UnifiedRequester(client, serialFormat), objectsSerializer, objectsSerializerNullable, idsSerializer
)
override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> = unifiedRequester.uniget(
buildStandardUrl(baseUrl, getByPaginationRouting, pagination.asUrlQueryParts), buildStandardUrl(baseUrl, getByPaginationRouting, pagination.asUrlQueryParts),
paginationResultSerializer paginationResultSerializer
) )
override suspend fun getById(id: IdType): ObjectType? = client.uniget( override suspend fun getById(id: IdType): ObjectType? = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
getByIdRouting, getByIdRouting,
mapOf( mapOf(
"id" to idsSerializer.encodeUrlQueryValue(id) "id" to unifiedRequester.encodeUrlQueryValue(idsSerializer, id)
) )
), ),
objectsSerializerNullable objectsSerializerNullable
) )
override suspend fun contains(id: IdType): Boolean = client.uniget( override suspend fun contains(id: IdType): Boolean = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
containsRouting, containsRouting,
mapOf( mapOf(
"id" to idsSerializer.encodeUrlQueryValue(id) "id" to unifiedRequester.encodeUrlQueryValue(idsSerializer, id)
) )
), ),
Boolean.serializer() Boolean.serializer()
) )
override suspend fun count(): Long = client.uniget( override suspend fun count(): Long = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
countRouting countRouting

View File

@@ -1,5 +1,8 @@
package dev.inmo.micro_utils.repos.ktor.client.crud package dev.inmo.micro_utils.repos.ktor.client.crud
import dev.inmo.micro_utils.ktor.client.UnifiedRequester
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.repos.* import dev.inmo.micro_utils.repos.*
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
@@ -7,7 +10,7 @@ import kotlinx.serialization.KSerializer
class KtorStandardCrudRepo<ObjectType, IdType, InputValue> ( class KtorStandardCrudRepo<ObjectType, IdType, InputValue> (
baseUrl: String, baseUrl: String,
baseSubpart: String, baseSubpart: String,
client: HttpClient, unifiedRequester: UnifiedRequester,
objectsSerializer: KSerializer<ObjectType>, objectsSerializer: KSerializer<ObjectType>,
objectsNullableSerializer: KSerializer<ObjectType?>, objectsNullableSerializer: KSerializer<ObjectType?>,
inputsSerializer: KSerializer<InputValue>, inputsSerializer: KSerializer<InputValue>,
@@ -15,16 +18,29 @@ class KtorStandardCrudRepo<ObjectType, IdType, InputValue> (
) : StandardCRUDRepo<ObjectType, IdType, InputValue>, ) : StandardCRUDRepo<ObjectType, IdType, InputValue>,
ReadStandardCRUDRepo<ObjectType, IdType> by KtorReadStandardCrudRepo( ReadStandardCRUDRepo<ObjectType, IdType> by KtorReadStandardCrudRepo(
"$baseUrl/$baseSubpart", "$baseUrl/$baseSubpart",
client, unifiedRequester,
objectsSerializer, objectsSerializer,
objectsNullableSerializer, objectsNullableSerializer,
idsSerializer idsSerializer
), ),
WriteStandardCRUDRepo<ObjectType, IdType, InputValue> by KtorWriteStandardCrudRepo( WriteStandardCRUDRepo<ObjectType, IdType, InputValue> by KtorWriteStandardCrudRepo(
"$baseUrl/$baseSubpart", "$baseUrl/$baseSubpart",
client, unifiedRequester,
objectsSerializer, objectsSerializer,
objectsNullableSerializer, objectsNullableSerializer,
inputsSerializer, inputsSerializer,
idsSerializer idsSerializer
) {
constructor(
baseUrl: String,
baseSubpart: String,
client: HttpClient,
objectsSerializer: KSerializer<ObjectType>,
objectsNullableSerializer: KSerializer<ObjectType?>,
inputsSerializer: KSerializer<InputValue>,
idsSerializer: KSerializer<IdType>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
) : this(
baseUrl, baseSubpart, UnifiedRequester(client, serialFormat), objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer
) )
}

View File

@@ -1,7 +1,7 @@
package dev.inmo.micro_utils.repos.ktor.client.crud package dev.inmo.micro_utils.repos.ktor.client.crud
import dev.inmo.micro_utils.ktor.client.* import dev.inmo.micro_utils.ktor.client.*
import dev.inmo.micro_utils.ktor.common.buildStandardUrl import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.repos.UpdatedValuePair import dev.inmo.micro_utils.repos.UpdatedValuePair
import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo
import dev.inmo.micro_utils.repos.ktor.common.crud.* import dev.inmo.micro_utils.repos.ktor.common.crud.*
@@ -12,7 +12,7 @@ import kotlinx.serialization.builtins.*
class KtorWriteStandardCrudRepo<ObjectType, IdType, InputValue> ( class KtorWriteStandardCrudRepo<ObjectType, IdType, InputValue> (
private val baseUrl: String, private val baseUrl: String,
private val client: HttpClient = HttpClient(), private val unifiedRequester: UnifiedRequester,
private val objectsSerializer: KSerializer<ObjectType>, private val objectsSerializer: KSerializer<ObjectType>,
private val objectsNullableSerializer: KSerializer<ObjectType?>, private val objectsNullableSerializer: KSerializer<ObjectType?>,
private val inputsSerializer: KSerializer<InputValue>, private val inputsSerializer: KSerializer<InputValue>,
@@ -27,39 +27,51 @@ class KtorWriteStandardCrudRepo<ObjectType, IdType, InputValue> (
) )
private val listInputUpdateSerializer = ListSerializer(inputUpdateSerializer) private val listInputUpdateSerializer = ListSerializer(inputUpdateSerializer)
override val newObjectsFlow: Flow<ObjectType> = client.createStandardWebsocketFlow( constructor(
baseUrl: String,
client: HttpClient,
objectsSerializer: KSerializer<ObjectType>,
objectsSerializerNullable: KSerializer<ObjectType?>,
inputsSerializer: KSerializer<InputValue>,
idsSerializer: KSerializer<IdType>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
) : this (
baseUrl, UnifiedRequester(client, serialFormat), objectsSerializer, objectsSerializerNullable, inputsSerializer, idsSerializer
)
override val newObjectsFlow: Flow<ObjectType> = unifiedRequester.createStandardWebsocketFlow(
buildStandardUrl(baseUrl, newObjectsFlowRouting), buildStandardUrl(baseUrl, newObjectsFlowRouting),
deserializer = objectsSerializer deserializer = objectsSerializer
) )
override val updatedObjectsFlow: Flow<ObjectType> = client.createStandardWebsocketFlow( override val updatedObjectsFlow: Flow<ObjectType> = unifiedRequester.createStandardWebsocketFlow(
buildStandardUrl(baseUrl, updatedObjectsFlowRouting), buildStandardUrl(baseUrl, updatedObjectsFlowRouting),
deserializer = objectsSerializer deserializer = objectsSerializer
) )
override val deletedObjectsIdsFlow: Flow<IdType> = client.createStandardWebsocketFlow( override val deletedObjectsIdsFlow: Flow<IdType> = unifiedRequester.createStandardWebsocketFlow(
buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting), buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting),
deserializer = idsSerializer deserializer = idsSerializer
) )
override suspend fun create(values: List<InputValue>): List<ObjectType> = client.unipost( override suspend fun create(values: List<InputValue>): List<ObjectType> = unifiedRequester.unipost(
buildStandardUrl(baseUrl, createRouting), buildStandardUrl(baseUrl, createRouting),
BodyPair(listInputSerializer, values), BodyPair(listInputSerializer, values),
listObjectsSerializer listObjectsSerializer
) )
override suspend fun update(id: IdType, value: InputValue): ObjectType? = client.unipost( override suspend fun update(id: IdType, value: InputValue): ObjectType? = unifiedRequester.unipost(
buildStandardUrl(baseUrl, updateRouting), buildStandardUrl(baseUrl, updateRouting),
BodyPair(inputUpdateSerializer, id to value), BodyPair(inputUpdateSerializer, id to value),
objectsNullableSerializer objectsNullableSerializer
) )
override suspend fun update(values: List<UpdatedValuePair<IdType, InputValue>>): List<ObjectType> = client.unipost( override suspend fun update(values: List<UpdatedValuePair<IdType, InputValue>>): List<ObjectType> = unifiedRequester.unipost(
buildStandardUrl(baseUrl, updateManyRouting), buildStandardUrl(baseUrl, updateManyRouting),
BodyPair(listInputUpdateSerializer, values), BodyPair(listInputUpdateSerializer, values),
listObjectsSerializer listObjectsSerializer
) )
override suspend fun deleteById(ids: List<IdType>) = client.unipost( override suspend fun deleteById(ids: List<IdType>) = unifiedRequester.unipost(
buildStandardUrl(baseUrl, deleteByIdRouting), buildStandardUrl(baseUrl, deleteByIdRouting),
BodyPair(listIdsSerializer, ids), BodyPair(listIdsSerializer, ids),
Unit.serializer() Unit.serializer()

View File

@@ -1,80 +1,90 @@
package dev.inmo.micro_utils.repos.ktor.client.key_value package dev.inmo.micro_utils.repos.ktor.client.key_value
import dev.inmo.micro_utils.ktor.client.encodeUrlQueryValue import dev.inmo.micro_utils.ktor.client.*
import dev.inmo.micro_utils.ktor.client.uniget import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.ktor.common.buildStandardUrl
import dev.inmo.micro_utils.pagination.* import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
import dev.inmo.micro_utils.repos.ktor.common.key_value.* import dev.inmo.micro_utils.repos.ktor.common.key_value.*
import dev.inmo.micro_utils.repos.ktor.common.valueParameterName import dev.inmo.micro_utils.repos.ktor.common.valueParameterName
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import kotlinx.serialization.KSerializer import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer import kotlinx.serialization.builtins.serializer
class KtorReadStandardKeyValueRepo<Key, Value> ( class KtorReadStandardKeyValueRepo<Key, Value> (
private var baseUrl: String, private val baseUrl: String,
private var client: HttpClient = HttpClient(), private val unifiedRequester: UnifiedRequester,
private var keySerializer: KSerializer<Key>, private val keySerializer: KSerializer<Key>,
private var valueSerializer: KSerializer<Value>, private val valueSerializer: KSerializer<Value>,
private var valueNullableSerializer: KSerializer<Value?>, private val valueNullableSerializer: KSerializer<Value?>
) : ReadStandardKeyValueRepo<Key, Value> { ) : ReadStandardKeyValueRepo<Key, Value> {
override suspend fun get(k: Key): Value? = client.uniget( constructor(
baseUrl: String,
client: HttpClient,
keySerializer: KSerializer<Key>,
valueSerializer: KSerializer<Value>,
valueNullableSerializer: KSerializer<Value?>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
) : this (
baseUrl, UnifiedRequester(client, serialFormat), keySerializer, valueSerializer, valueNullableSerializer
)
override suspend fun get(k: Key): Value? = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
getRoute, getRoute,
mapOf( mapOf(
keyParameterName to keySerializer.encodeUrlQueryValue(k) keyParameterName to unifiedRequester.encodeUrlQueryValue(keySerializer, k)
) )
), ),
valueNullableSerializer valueNullableSerializer
) )
override suspend fun values(pagination: Pagination, reversed: Boolean): PaginationResult<Value> = client.uniget( override suspend fun values(pagination: Pagination, reversed: Boolean): PaginationResult<Value> = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
valuesRoute, valuesRoute,
mapOf( mapOf(
reversedParameterName to Boolean.serializer().encodeUrlQueryValue(reversed) reversedParameterName to unifiedRequester.encodeUrlQueryValue(Boolean.serializer(), reversed)
) + pagination.asUrlQueryParts ) + pagination.asUrlQueryParts
), ),
PaginationResult.serializer(valueSerializer) PaginationResult.serializer(valueSerializer)
) )
override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> = client.uniget( override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
keysRoute, keysRoute,
mapOf( mapOf(
reversedParameterName to Boolean.serializer().encodeUrlQueryValue(reversed) reversedParameterName to unifiedRequester.encodeUrlQueryValue(Boolean.serializer(), reversed)
) + pagination.asUrlQueryParts ) + pagination.asUrlQueryParts
), ),
PaginationResult.serializer(keySerializer) PaginationResult.serializer(keySerializer)
) )
override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult<Key> = client.uniget( override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult<Key> = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
keysRoute, keysRoute,
mapOf( mapOf(
valueParameterName to valueSerializer.encodeUrlQueryValue(v), valueParameterName to unifiedRequester.encodeUrlQueryValue(valueSerializer, v),
reversedParameterName to Boolean.serializer().encodeUrlQueryValue(reversed) reversedParameterName to unifiedRequester.encodeUrlQueryValue(Boolean.serializer(), reversed)
) + pagination.asUrlQueryParts ) + pagination.asUrlQueryParts
), ),
PaginationResult.serializer(keySerializer) PaginationResult.serializer(keySerializer)
) )
override suspend fun contains(key: Key): Boolean = client.uniget( override suspend fun contains(key: Key): Boolean = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
containsRoute, containsRoute,
mapOf( mapOf(
keyParameterName to keySerializer.encodeUrlQueryValue(key) keyParameterName to unifiedRequester.encodeUrlQueryValue(keySerializer, key)
), ),
), ),
Boolean.serializer(), Boolean.serializer(),
) )
override suspend fun count(): Long = client.uniget( override suspend fun count(): Long = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
countRoute, countRoute,

View File

@@ -1,27 +1,41 @@
package dev.inmo.micro_utils.repos.ktor.client.key_value package dev.inmo.micro_utils.repos.ktor.client.key_value
import dev.inmo.micro_utils.ktor.client.UnifiedRequester
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.repos.* import dev.inmo.micro_utils.repos.*
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import kotlinx.serialization.KSerializer import kotlinx.serialization.*
@Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE")
class KtorStandartKeyValueRepo<K, V> ( class KtorStandartKeyValueRepo<K, V> (
baseUrl: String, baseUrl: String,
baseSubpart: String, baseSubpart: String,
client: HttpClient = HttpClient(), unifiedRequester: UnifiedRequester,
keySerializer: KSerializer<K>, keySerializer: KSerializer<K>,
valueSerializer: KSerializer<V>, valueSerializer: KSerializer<V>,
valueNullableSerializer: KSerializer<V?> valueNullableSerializer: KSerializer<V?>
) : StandardKeyValueRepo<K, V>, ) : StandardKeyValueRepo<K, V>,
ReadStandardKeyValueRepo<K, V> by KtorReadStandardKeyValueRepo( ReadStandardKeyValueRepo<K, V> by KtorReadStandardKeyValueRepo(
"$baseUrl/$baseSubpart", "$baseUrl/$baseSubpart",
client, unifiedRequester,
keySerializer, keySerializer,
valueSerializer, valueSerializer,
valueNullableSerializer valueNullableSerializer
), ),
WriteStandardKeyValueRepo<K, V> by KtorWriteStandardKeyValueRepo( WriteStandardKeyValueRepo<K, V> by KtorWriteStandardKeyValueRepo(
"$baseUrl/$baseSubpart", "$baseUrl/$baseSubpart",
client, unifiedRequester,
keySerializer, keySerializer,
valueSerializer valueSerializer
) ) {
constructor(
baseUrl: String,
baseSubpart: String,
client: HttpClient = HttpClient(),
keySerializer: KSerializer<K>,
valueSerializer: KSerializer<V>,
valueNullableSerializer: KSerializer<V?>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
) : this(baseUrl, baseSubpart, UnifiedRequester(client, serialFormat), keySerializer, valueSerializer, valueNullableSerializer)
}

View File

@@ -1,7 +1,7 @@
package dev.inmo.micro_utils.repos.ktor.client.key_value package dev.inmo.micro_utils.repos.ktor.client.key_value
import dev.inmo.micro_utils.ktor.client.* import dev.inmo.micro_utils.ktor.client.*
import dev.inmo.micro_utils.ktor.common.buildStandardUrl import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.repos.WriteStandardKeyValueRepo import dev.inmo.micro_utils.repos.WriteStandardKeyValueRepo
import dev.inmo.micro_utils.repos.ktor.common.key_value.* import dev.inmo.micro_utils.repos.ktor.common.key_value.*
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
@@ -11,23 +11,35 @@ import kotlinx.serialization.builtins.*
class KtorWriteStandardKeyValueRepo<K, V> ( class KtorWriteStandardKeyValueRepo<K, V> (
private var baseUrl: String, private var baseUrl: String,
private var client: HttpClient = HttpClient(), private var unifiedRequester: UnifiedRequester,
private var keySerializer: KSerializer<K>, private var keySerializer: KSerializer<K>,
private var valueSerializer: KSerializer<V>, private var valueSerializer: KSerializer<V>,
) : WriteStandardKeyValueRepo<K, V> { ) : WriteStandardKeyValueRepo<K, V> {
private val keyValueMapSerializer = MapSerializer(keySerializer, valueSerializer) private val keyValueMapSerializer = MapSerializer(keySerializer, valueSerializer)
private val keysListSerializer = ListSerializer(keySerializer) private val keysListSerializer = ListSerializer(keySerializer)
override val onNewValue: Flow<Pair<K, V>> = client.createStandardWebsocketFlow( private val valuesListSerializer = ListSerializer(valueSerializer)
constructor(
baseUrl: String,
client: HttpClient,
keySerializer: KSerializer<K>,
valueSerializer: KSerializer<V>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
) : this (
baseUrl, UnifiedRequester(client, serialFormat), keySerializer, valueSerializer
)
override val onNewValue: Flow<Pair<K, V>> = unifiedRequester.createStandardWebsocketFlow(
buildStandardUrl(baseUrl, onNewValueRoute), buildStandardUrl(baseUrl, onNewValueRoute),
deserializer = PairSerializer(keySerializer, valueSerializer) deserializer = PairSerializer(keySerializer, valueSerializer)
) )
override val onValueRemoved: Flow<K> = client.createStandardWebsocketFlow( override val onValueRemoved: Flow<K> = unifiedRequester.createStandardWebsocketFlow(
buildStandardUrl(baseUrl, onValueRemovedRoute), buildStandardUrl(baseUrl, onValueRemovedRoute),
deserializer = keySerializer deserializer = keySerializer
) )
override suspend fun set(toSet: Map<K, V>) = client.unipost( override suspend fun set(toSet: Map<K, V>) = unifiedRequester.unipost(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
setRoute setRoute
@@ -36,7 +48,7 @@ class KtorWriteStandardKeyValueRepo<K, V> (
Unit.serializer() Unit.serializer()
) )
override suspend fun unset(toUnset: List<K>) = client.unipost( override suspend fun unset(toUnset: List<K>) = unifiedRequester.unipost(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
unsetRoute, unsetRoute,
@@ -44,4 +56,13 @@ class KtorWriteStandardKeyValueRepo<K, V> (
BodyPair(keysListSerializer, toUnset), BodyPair(keysListSerializer, toUnset),
Unit.serializer() Unit.serializer()
) )
override suspend fun unsetWithValues(toUnset: List<V>) = unifiedRequester.unipost(
buildStandardUrl(
baseUrl,
unsetWithValuesRoute,
),
BodyPair(valuesListSerializer, toUnset),
Unit.serializer()
)
} }

View File

@@ -1,5 +1,8 @@
package dev.inmo.micro_utils.repos.ktor.client.one_to_many package dev.inmo.micro_utils.repos.ktor.client.one_to_many
import dev.inmo.micro_utils.ktor.client.UnifiedRequester
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.repos.* import dev.inmo.micro_utils.repos.*
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
@@ -7,19 +10,28 @@ import kotlinx.serialization.KSerializer
class KtorOneToManyKeyValueRepo<Key, Value>( class KtorOneToManyKeyValueRepo<Key, Value>(
baseUrl: String, baseUrl: String,
baseSubpart: String, baseSubpart: String,
client: HttpClient, unifiedRequester: UnifiedRequester,
keySerializer: KSerializer<Key>, keySerializer: KSerializer<Key>,
valueSerializer: KSerializer<Value>, valueSerializer: KSerializer<Value>,
) : OneToManyKeyValueRepo<Key, Value>, ) : OneToManyKeyValueRepo<Key, Value>,
ReadOneToManyKeyValueRepo<Key, Value> by KtorReadOneToManyKeyValueRepo<Key, Value> ( ReadOneToManyKeyValueRepo<Key, Value> by KtorReadOneToManyKeyValueRepo<Key, Value> (
"$baseUrl/$baseSubpart", "$baseUrl/$baseSubpart",
client, unifiedRequester,
keySerializer, keySerializer,
valueSerializer, valueSerializer,
), ),
WriteOneToManyKeyValueRepo<Key, Value> by KtorWriteOneToManyKeyValueRepo<Key, Value> ( WriteOneToManyKeyValueRepo<Key, Value> by KtorWriteOneToManyKeyValueRepo<Key, Value> (
"$baseUrl/$baseSubpart", "$baseUrl/$baseSubpart",
client, unifiedRequester,
keySerializer, keySerializer,
valueSerializer, valueSerializer,
) ) {
constructor(
baseUrl: String,
baseSubpart: String,
client: HttpClient,
keySerializer: KSerializer<Key>,
valueSerializer: KSerializer<Value>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
) : this (baseUrl, baseSubpart, UnifiedRequester(client, serialFormat), keySerializer, valueSerializer)
}

View File

@@ -1,8 +1,7 @@
package dev.inmo.micro_utils.repos.ktor.client.one_to_many package dev.inmo.micro_utils.repos.ktor.client.one_to_many
import dev.inmo.micro_utils.ktor.client.encodeUrlQueryValue import dev.inmo.micro_utils.ktor.client.*
import dev.inmo.micro_utils.ktor.client.uniget import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.ktor.common.buildStandardUrl
import dev.inmo.micro_utils.pagination.* import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo
import dev.inmo.micro_utils.repos.ktor.common.keyParameterName import dev.inmo.micro_utils.repos.ktor.common.keyParameterName
@@ -15,81 +14,89 @@ import kotlinx.serialization.builtins.serializer
class KtorReadOneToManyKeyValueRepo<Key, Value> ( class KtorReadOneToManyKeyValueRepo<Key, Value> (
private val baseUrl: String, private val baseUrl: String,
private val client: HttpClient = HttpClient(), private val unifiedRequester: UnifiedRequester,
private val keySerializer: KSerializer<Key>, private val keySerializer: KSerializer<Key>,
private val valueSerializer: KSerializer<Value>, private val valueSerializer: KSerializer<Value>
) : ReadOneToManyKeyValueRepo<Key, Value> { ) : ReadOneToManyKeyValueRepo<Key, Value> {
private val paginationValueResultSerializer = PaginationResult.serializer(valueSerializer) private val paginationValueResultSerializer = PaginationResult.serializer(valueSerializer)
private val paginationKeyResultSerializer = PaginationResult.serializer(keySerializer) private val paginationKeyResultSerializer = PaginationResult.serializer(keySerializer)
override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> = client.uniget( constructor(
baseUrl: String,
client: HttpClient,
keySerializer: KSerializer<Key>,
valueSerializer: KSerializer<Value>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
) : this (baseUrl, UnifiedRequester(client, serialFormat), keySerializer, valueSerializer)
override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
getRoute, getRoute,
mapOf( mapOf(
keyParameterName to keySerializer.encodeUrlQueryValue(k), keyParameterName to unifiedRequester.encodeUrlQueryValue(keySerializer, k),
reversedParameterName to Boolean.serializer().encodeUrlQueryValue(reversed) reversedParameterName to unifiedRequester.encodeUrlQueryValue(Boolean.serializer(), reversed)
) + pagination.asUrlQueryParts ) + pagination.asUrlQueryParts
), ),
paginationValueResultSerializer paginationValueResultSerializer
) )
override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> = client.uniget( override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
keysRoute, keysRoute,
mapOf( mapOf(
reversedParameterName to Boolean.serializer().encodeUrlQueryValue(reversed) reversedParameterName to unifiedRequester.encodeUrlQueryValue(Boolean.serializer(), reversed)
) + pagination.asUrlQueryParts ) + pagination.asUrlQueryParts
), ),
paginationKeyResultSerializer paginationKeyResultSerializer
) )
override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult<Key> = client.uniget( override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult<Key> = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
keysRoute, keysRoute,
mapOf( mapOf(
valueParameterName to valueSerializer.encodeUrlQueryValue(v), valueParameterName to unifiedRequester.encodeUrlQueryValue(valueSerializer, v),
reversedParameterName to Boolean.serializer().encodeUrlQueryValue(reversed) reversedParameterName to unifiedRequester.encodeUrlQueryValue(Boolean.serializer(), reversed)
) + pagination.asUrlQueryParts ) + pagination.asUrlQueryParts
), ),
paginationKeyResultSerializer paginationKeyResultSerializer
) )
override suspend fun contains(k: Key): Boolean = client.uniget( override suspend fun contains(k: Key): Boolean = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
containsByKeyRoute, containsByKeyRoute,
mapOf(keyParameterName to keySerializer.encodeUrlQueryValue(k)) mapOf(keyParameterName to unifiedRequester.encodeUrlQueryValue(keySerializer, k))
), ),
Boolean.serializer() Boolean.serializer()
) )
override suspend fun contains(k: Key, v: Value): Boolean = client.uniget( override suspend fun contains(k: Key, v: Value): Boolean = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
containsByKeyValueRoute, containsByKeyValueRoute,
mapOf( mapOf(
keyParameterName to keySerializer.encodeUrlQueryValue(k), keyParameterName to unifiedRequester.encodeUrlQueryValue(keySerializer, k),
valueParameterName to valueSerializer.encodeUrlQueryValue(v), valueParameterName to unifiedRequester.encodeUrlQueryValue(valueSerializer, v),
) )
), ),
Boolean.serializer() Boolean.serializer()
) )
override suspend fun count(k: Key): Long = client.uniget( override suspend fun count(k: Key): Long = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
countByKeyRoute, countByKeyRoute,
mapOf( mapOf(
keyParameterName to keySerializer.encodeUrlQueryValue(k) keyParameterName to unifiedRequester.encodeUrlQueryValue(keySerializer, k)
) )
), ),
Long.serializer() Long.serializer()
) )
override suspend fun count(): Long = client.uniget( override suspend fun count(): Long = unifiedRequester.uniget(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
countRoute, countRoute,

View File

@@ -1,7 +1,7 @@
package dev.inmo.micro_utils.repos.ktor.client.one_to_many package dev.inmo.micro_utils.repos.ktor.client.one_to_many
import dev.inmo.micro_utils.ktor.client.* import dev.inmo.micro_utils.ktor.client.*
import dev.inmo.micro_utils.ktor.common.buildStandardUrl import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.repos.WriteOneToManyKeyValueRepo import dev.inmo.micro_utils.repos.WriteOneToManyKeyValueRepo
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
@@ -11,26 +11,37 @@ import kotlinx.serialization.builtins.*
class KtorWriteOneToManyKeyValueRepo<Key, Value> ( class KtorWriteOneToManyKeyValueRepo<Key, Value> (
private val baseUrl: String, private val baseUrl: String,
private val client: HttpClient = HttpClient(), private val unifiedRequester: UnifiedRequester,
private val keySerializer: KSerializer<Key>, private val keySerializer: KSerializer<Key>,
private val valueSerializer: KSerializer<Value> private val valueSerializer: KSerializer<Value>
) : WriteOneToManyKeyValueRepo<Key, Value> { ) : WriteOneToManyKeyValueRepo<Key, Value> {
private val keyValueSerializer = PairSerializer(keySerializer, valueSerializer) private val keyValueSerializer = PairSerializer(keySerializer, valueSerializer)
private val keyValueMapSerializer = MapSerializer(keySerializer, ListSerializer(valueSerializer)) private val keyValueMapSerializer = MapSerializer(keySerializer, ListSerializer(valueSerializer))
override val onNewValue: Flow<Pair<Key, Value>> = client.createStandardWebsocketFlow(
constructor(
baseUrl: String,
client: HttpClient,
keySerializer: KSerializer<Key>,
valueSerializer: KSerializer<Value>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
) : this (
baseUrl, UnifiedRequester(client, serialFormat), keySerializer, valueSerializer
)
override val onNewValue: Flow<Pair<Key, Value>> = unifiedRequester.createStandardWebsocketFlow(
buildStandardUrl(baseUrl, onNewValueRoute), buildStandardUrl(baseUrl, onNewValueRoute),
deserializer = keyValueSerializer deserializer = keyValueSerializer
) )
override val onValueRemoved: Flow<Pair<Key, Value>> = client.createStandardWebsocketFlow( override val onValueRemoved: Flow<Pair<Key, Value>> = unifiedRequester.createStandardWebsocketFlow(
buildStandardUrl(baseUrl, onValueRemovedRoute), buildStandardUrl(baseUrl, onValueRemovedRoute),
deserializer = keyValueSerializer deserializer = keyValueSerializer
) )
override val onDataCleared: Flow<Key> = client.createStandardWebsocketFlow( override val onDataCleared: Flow<Key> = unifiedRequester.createStandardWebsocketFlow(
buildStandardUrl(baseUrl, onDataClearedRoute), buildStandardUrl(baseUrl, onDataClearedRoute),
deserializer = keySerializer deserializer = keySerializer
) )
override suspend fun remove(toRemove: Map<Key, List<Value>>) = client.unipost( override suspend fun remove(toRemove: Map<Key, List<Value>>) = unifiedRequester.unipost(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
removeRoute, removeRoute,
@@ -39,7 +50,7 @@ class KtorWriteOneToManyKeyValueRepo<Key, Value> (
Unit.serializer(), Unit.serializer(),
) )
override suspend fun add(toAdd: Map<Key, List<Value>>) = client.unipost( override suspend fun add(toAdd: Map<Key, List<Value>>) = unifiedRequester.unipost(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
addRoute, addRoute,
@@ -47,7 +58,7 @@ class KtorWriteOneToManyKeyValueRepo<Key, Value> (
BodyPair(keyValueMapSerializer, toAdd), BodyPair(keyValueMapSerializer, toAdd),
Unit.serializer(), Unit.serializer(),
) )
override suspend fun clear(k: Key) = client.unipost( override suspend fun clear(k: Key) = unifiedRequester.unipost(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
clearRoute, clearRoute,
@@ -56,7 +67,7 @@ class KtorWriteOneToManyKeyValueRepo<Key, Value> (
Unit.serializer(), Unit.serializer(),
) )
override suspend fun set(toSet: Map<Key, List<Value>>) = client.unipost( override suspend fun set(toSet: Map<Key, List<Value>>) = unifiedRequester.unipost(
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
setRoute, setRoute,

View File

@@ -10,3 +10,4 @@ const val onNewValueRoute = "onNewValue"
const val onValueRemovedRoute = "onValueRemoved" const val onValueRemovedRoute = "onValueRemoved"
const val setRoute = "set" const val setRoute = "set"
const val unsetRoute = "unset" const val unsetRoute = "unset"
const val unsetWithValuesRoute = "unsetWithValues"

View File

@@ -1,12 +1,14 @@
package dev.inmo.micro_utils.repos.ktor.server.crud package dev.inmo.micro_utils.repos.ktor.server.crud
import dev.inmo.micro_utils.ktor.server.decodeUrlQueryValueOrSendError import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.unianswer import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.pagination.PaginationResult import dev.inmo.micro_utils.pagination.PaginationResult
import dev.inmo.micro_utils.pagination.extractPagination import dev.inmo.micro_utils.pagination.extractPagination
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
import dev.inmo.micro_utils.repos.ktor.common.crud.* import dev.inmo.micro_utils.repos.ktor.common.crud.*
import io.ktor.application.call import io.ktor.application.call
import io.ktor.http.ContentType
import io.ktor.routing.Route import io.ktor.routing.Route
import io.ktor.routing.get import io.ktor.routing.get
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
@@ -16,47 +18,65 @@ fun <ObjectType, IdType> Route.configureReadStandardCrudRepoRoutes(
originalRepo: ReadStandardCRUDRepo<ObjectType, IdType>, originalRepo: ReadStandardCRUDRepo<ObjectType, IdType>,
objectsSerializer: KSerializer<ObjectType>, objectsSerializer: KSerializer<ObjectType>,
objectsNullableSerializer: KSerializer<ObjectType?>, objectsNullableSerializer: KSerializer<ObjectType?>,
idsSerializer: KSerializer<IdType> idsSerializer: KSerializer<IdType>,
unifiedRouter: UnifiedRouter
) { ) {
val paginationResultSerializer = PaginationResult.serializer(objectsSerializer) val paginationResultSerializer = PaginationResult.serializer(objectsSerializer)
get(getByPaginationRouting) { get(getByPaginationRouting) {
val pagination = call.request.queryParameters.extractPagination unifiedRouter.apply {
val pagination = call.request.queryParameters.extractPagination
call.unianswer( unianswer(
paginationResultSerializer, paginationResultSerializer,
originalRepo.getByPagination(pagination) originalRepo.getByPagination(pagination)
) )
}
} }
get(getByIdRouting) { get(getByIdRouting) {
val id = call.decodeUrlQueryValueOrSendError( unifiedRouter.apply {
"id", val id = decodeUrlQueryValueOrSendError(
idsSerializer "id",
) ?: return@get idsSerializer
) ?: return@get
call.unianswer( unianswer(
objectsNullableSerializer, objectsNullableSerializer,
originalRepo.getById(id) originalRepo.getById(id)
) )
}
} }
get(containsRouting) { get(containsRouting) {
val id = call.decodeUrlQueryValueOrSendError( unifiedRouter.apply {
"id", val id = decodeUrlQueryValueOrSendError(
idsSerializer "id",
) ?: return@get idsSerializer
) ?: return@get
call.unianswer( unianswer(
Boolean.serializer(), Boolean.serializer(),
originalRepo.contains(id) originalRepo.contains(id)
) )
}
} }
get(countRouting) { get(countRouting) {
call.unianswer( unifiedRouter.apply {
Long.serializer(), unianswer(
originalRepo.count() Long.serializer(),
) originalRepo.count()
)
}
} }
} }
inline fun <ObjectType, IdType> Route.configureReadStandardCrudRepoRoutes(
originalRepo: ReadStandardCRUDRepo<ObjectType, IdType>,
objectsSerializer: KSerializer<ObjectType>,
objectsNullableSerializer: KSerializer<ObjectType?>,
idsSerializer: KSerializer<IdType>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
) = configureReadStandardCrudRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, idsSerializer, UnifiedRouter(serialFormat, serialFormatContentType))

View File

@@ -1,6 +1,11 @@
package dev.inmo.micro_utils.repos.ktor.server.crud package dev.inmo.micro_utils.repos.ktor.server.crud
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.UnifiedRouter
import dev.inmo.micro_utils.ktor.server.standardKtorSerialFormatContentType
import dev.inmo.micro_utils.repos.StandardCRUDRepo import dev.inmo.micro_utils.repos.StandardCRUDRepo
import io.ktor.http.ContentType
import io.ktor.routing.Route import io.ktor.routing.Route
import io.ktor.routing.route import io.ktor.routing.route
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
@@ -11,10 +16,24 @@ fun <ObjectType, IdType, InputValue> Route.configureStandardCrudRepoRoutes(
objectsSerializer: KSerializer<ObjectType>, objectsSerializer: KSerializer<ObjectType>,
objectsNullableSerializer: KSerializer<ObjectType?>, objectsNullableSerializer: KSerializer<ObjectType?>,
inputsSerializer: KSerializer<InputValue>, inputsSerializer: KSerializer<InputValue>,
idsSerializer: KSerializer<IdType> idsSerializer: KSerializer<IdType>,
unifiedRouter: UnifiedRouter
) { ) {
route(baseSubpart) { route(baseSubpart) {
configureReadStandardCrudRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, idsSerializer) configureReadStandardCrudRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, idsSerializer, unifiedRouter)
configureWriteStandardCrudRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer) configureWriteStandardCrudRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer, unifiedRouter)
} }
} }
fun <ObjectType, IdType, InputValue> Route.configureStandardCrudRepoRoutes(
baseSubpart: String,
originalRepo: StandardCRUDRepo<ObjectType, IdType, InputValue>,
objectsSerializer: KSerializer<ObjectType>,
objectsNullableSerializer: KSerializer<ObjectType?>,
inputsSerializer: KSerializer<InputValue>,
idsSerializer: KSerializer<IdType>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
) = configureStandardCrudRepoRoutes(
baseSubpart, originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer, UnifiedRouter(serialFormat, serialFormatContentType)
)

View File

@@ -1,9 +1,12 @@
package dev.inmo.micro_utils.repos.ktor.server.crud package dev.inmo.micro_utils.repos.ktor.server.crud
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.* import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo
import dev.inmo.micro_utils.repos.ktor.common.crud.* import dev.inmo.micro_utils.repos.ktor.common.crud.*
import io.ktor.application.call import io.ktor.application.call
import io.ktor.http.ContentType
import io.ktor.routing.Route import io.ktor.routing.Route
import io.ktor.routing.post import io.ktor.routing.post
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
@@ -14,7 +17,8 @@ fun <ObjectType, IdType, InputValue> Route.configureWriteStandardCrudRepoRoutes(
objectsSerializer: KSerializer<ObjectType>, objectsSerializer: KSerializer<ObjectType>,
objectsNullableSerializer: KSerializer<ObjectType?>, objectsNullableSerializer: KSerializer<ObjectType?>,
inputsSerializer: KSerializer<InputValue>, inputsSerializer: KSerializer<InputValue>,
idsSerializer: KSerializer<IdType> idsSerializer: KSerializer<IdType>,
unifiedRouter: UnifiedRouter
) { ) {
val listObjectsSerializer = ListSerializer(objectsSerializer) val listObjectsSerializer = ListSerializer(objectsSerializer)
val listInputSerializer = ListSerializer(inputsSerializer) val listInputSerializer = ListSerializer(inputsSerializer)
@@ -25,58 +29,80 @@ fun <ObjectType, IdType, InputValue> Route.configureWriteStandardCrudRepoRoutes(
) )
val listInputUpdateSerializer = ListSerializer(inputUpdateSerializer) val listInputUpdateSerializer = ListSerializer(inputUpdateSerializer)
includeWebsocketHandling( unifiedRouter.apply {
newObjectsFlowRouting, includeWebsocketHandling(
originalRepo.newObjectsFlow, newObjectsFlowRouting,
objectsSerializer originalRepo.newObjectsFlow,
) objectsSerializer
includeWebsocketHandling( )
updatedObjectsFlowRouting, includeWebsocketHandling(
originalRepo.updatedObjectsFlow, updatedObjectsFlowRouting,
objectsSerializer originalRepo.updatedObjectsFlow,
) objectsSerializer
includeWebsocketHandling( )
deletedObjectsIdsFlowRouting, includeWebsocketHandling(
originalRepo.deletedObjectsIdsFlow, deletedObjectsIdsFlowRouting,
idsSerializer originalRepo.deletedObjectsIdsFlow,
) idsSerializer
)
}
post(createRouting) { post(createRouting) {
call.unianswer( unifiedRouter.apply {
listObjectsSerializer, unianswer(
originalRepo.create( listObjectsSerializer,
call.uniload(listInputSerializer) originalRepo.create(
uniload(listInputSerializer)
)
) )
) }
} }
post(updateRouting) { post(updateRouting) {
val (id, input) = call.uniload(inputUpdateSerializer) unifiedRouter.apply {
call.unianswer( val (id, input) = uniload(inputUpdateSerializer)
objectsNullableSerializer, unianswer(
originalRepo.update( objectsNullableSerializer,
id, input originalRepo.update(
id, input
)
) )
) }
} }
post(updateManyRouting) { post(updateManyRouting) {
val updates = call.uniload(listInputUpdateSerializer) unifiedRouter.apply {
call.unianswer( val updates = uniload(listInputUpdateSerializer)
listObjectsSerializer, unianswer(
originalRepo.update( listObjectsSerializer,
updates originalRepo.update(
updates
)
) )
) }
} }
post(deleteByIdRouting) { post(deleteByIdRouting) {
val ids = call.uniload(listIdsSerializer) unifiedRouter.apply {
call.unianswer( val ids = uniload(listIdsSerializer)
Unit.serializer(), unianswer(
originalRepo.deleteById( Unit.serializer(),
ids originalRepo.deleteById(
ids
)
) )
) }
} }
} }
fun <ObjectType, IdType, InputValue> Route.configureWriteStandardCrudRepoRoutes(
originalRepo: WriteStandardCRUDRepo<ObjectType, IdType, InputValue>,
objectsSerializer: KSerializer<ObjectType>,
objectsNullableSerializer: KSerializer<ObjectType?>,
inputsSerializer: KSerializer<InputValue>,
idsSerializer: KSerializer<IdType>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
) = configureWriteStandardCrudRepoRoutes(
originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer, UnifiedRouter(serialFormat, serialFormatContentType)
)

View File

@@ -1,16 +1,22 @@
package dev.inmo.micro_utils.repos.ktor.server.key_value package dev.inmo.micro_utils.repos.ktor.server.key_value
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.UnifiedRouter
import dev.inmo.micro_utils.ktor.server.standardKtorSerialFormatContentType
import dev.inmo.micro_utils.repos.StandardKeyValueRepo import dev.inmo.micro_utils.repos.StandardKeyValueRepo
import io.ktor.http.ContentType
import io.ktor.routing.Route import io.ktor.routing.Route
import io.ktor.routing.route import io.ktor.routing.route
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
fun <K, V> Route.configureStandartKeyValueRepoRoutes( fun <K, V> Route.configureStandardKeyValueRepoRoutes(
baseSubpart: String, baseSubpart: String,
originalRepo: StandardKeyValueRepo<K, V>, originalRepo: StandardKeyValueRepo<K, V>,
keySerializer: KSerializer<K>, keySerializer: KSerializer<K>,
valueSerializer: KSerializer<V>, valueSerializer: KSerializer<V>,
valueNullableSerializer: KSerializer<V?>, valueNullableSerializer: KSerializer<V?>,
unifiedRouter: UnifiedRouter
) { ) {
route(baseSubpart) { route(baseSubpart) {
configureReadStandartKeyValueRepoRoutes( configureReadStandartKeyValueRepoRoutes(
@@ -18,11 +24,23 @@ fun <K, V> Route.configureStandartKeyValueRepoRoutes(
keySerializer, keySerializer,
valueSerializer, valueSerializer,
valueNullableSerializer, valueNullableSerializer,
unifiedRouter
) )
configureWriteStandartKeyValueRepoRoutes( configureWriteStandardKeyValueRepoRoutes(
originalRepo, originalRepo,
keySerializer, keySerializer,
valueSerializer, valueSerializer,
unifiedRouter
) )
} }
} }
fun <K, V> Route.configureStandartKeyValueRepoRoutes(
baseSubpart: String,
originalRepo: StandardKeyValueRepo<K, V>,
keySerializer: KSerializer<K>,
valueSerializer: KSerializer<V>,
valueNullableSerializer: KSerializer<V?>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
) = configureStandardKeyValueRepoRoutes(baseSubpart, originalRepo, keySerializer, valueSerializer, valueNullableSerializer, UnifiedRouter(serialFormat, serialFormatContentType))

View File

@@ -1,5 +1,7 @@
package dev.inmo.micro_utils.repos.ktor.server.key_value package dev.inmo.micro_utils.repos.ktor.server.key_value
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.* import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.pagination.PaginationResult import dev.inmo.micro_utils.pagination.PaginationResult
import dev.inmo.micro_utils.pagination.extractPagination import dev.inmo.micro_utils.pagination.extractPagination
@@ -7,6 +9,7 @@ import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
import dev.inmo.micro_utils.repos.ktor.common.key_value.* import dev.inmo.micro_utils.repos.ktor.common.key_value.*
import dev.inmo.micro_utils.repos.ktor.common.valueParameterName import dev.inmo.micro_utils.repos.ktor.common.valueParameterName
import io.ktor.application.call import io.ktor.application.call
import io.ktor.http.ContentType
import io.ktor.routing.Route import io.ktor.routing.Route
import io.ktor.routing.get import io.ktor.routing.get
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
@@ -17,62 +20,84 @@ fun <K, V> Route.configureReadStandartKeyValueRepoRoutes (
keySerializer: KSerializer<K>, keySerializer: KSerializer<K>,
valueSerializer: KSerializer<V>, valueSerializer: KSerializer<V>,
valueNullableSerializer: KSerializer<V?>, valueNullableSerializer: KSerializer<V?>,
unifiedRouter: UnifiedRouter
) { ) {
get(getRoute) { get(getRoute) {
val key = call.decodeUrlQueryValueOrSendError( unifiedRouter.apply {
keyParameterName, val key = decodeUrlQueryValueOrSendError(
keySerializer keyParameterName,
) ?: return@get keySerializer
) ?: return@get
call.unianswer( unianswer(
valueNullableSerializer, valueNullableSerializer,
originalRepo.get(key) originalRepo.get(key)
) )
}
} }
get(valuesRoute) { get(valuesRoute) {
val parination = call.request.queryParameters.extractPagination; unifiedRouter.apply {
val reversed = call.decodeUrlQueryValueOrSendError( val parination = call.request.queryParameters.extractPagination;
reversedParameterName, val reversed = decodeUrlQueryValueOrSendError(
Boolean.serializer() reversedParameterName,
) ?: return@get Boolean.serializer()
) ?: return@get
call.unianswer( unianswer(
PaginationResult.serializer(valueSerializer), PaginationResult.serializer(valueSerializer),
originalRepo.values(parination, reversed) originalRepo.values(parination, reversed)
) )
}
} }
get(keysRoute) { get(keysRoute) {
val parination = call.request.queryParameters.extractPagination; unifiedRouter.apply {
val reversed = call.decodeUrlQueryValueOrSendError( val parination = call.request.queryParameters.extractPagination;
reversedParameterName, val reversed = decodeUrlQueryValueOrSendError(
Boolean.serializer() reversedParameterName,
) ?: return@get Boolean.serializer()
val value = call.decodeUrlQueryValue(valueParameterName, valueSerializer) ) ?: return@get
val value = decodeUrlQueryValue(valueParameterName, valueSerializer)
call.unianswer( unianswer(
PaginationResult.serializer(keySerializer), PaginationResult.serializer(keySerializer),
value ?.let { originalRepo.keys(value, parination, reversed) } ?: originalRepo.keys(parination, reversed) value?.let { originalRepo.keys(value, parination, reversed) } ?: originalRepo.keys(parination, reversed)
) )
}
} }
get(containsRoute) { get(containsRoute) {
val key = call.decodeUrlQueryValueOrSendError( unifiedRouter.apply {
keyParameterName, val key = decodeUrlQueryValueOrSendError(
keySerializer keyParameterName,
) ?: return@get keySerializer
) ?: return@get
call.unianswer( unianswer(
Boolean.serializer(), Boolean.serializer(),
originalRepo.contains(key) originalRepo.contains(key)
) )
}
} }
get(countRoute) { get(countRoute) {
call.unianswer( unifiedRouter.apply {
Long.serializer(), unianswer(
originalRepo.count() Long.serializer(),
) originalRepo.count()
)
}
} }
} }
inline fun <K, V> Route.configureReadStandartKeyValueRepoRoutes (
originalRepo: ReadStandardKeyValueRepo<K, V>,
keySerializer: KSerializer<K>,
valueSerializer: KSerializer<V>,
valueNullableSerializer: KSerializer<V?>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
) = configureReadStandartKeyValueRepoRoutes(
originalRepo, keySerializer, valueSerializer, valueNullableSerializer, UnifiedRouter(serialFormat, serialFormatContentType)
)

View File

@@ -1,44 +1,70 @@
package dev.inmo.micro_utils.repos.ktor.server.key_value package dev.inmo.micro_utils.repos.ktor.server.key_value
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.* import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.repos.WriteStandardKeyValueRepo import dev.inmo.micro_utils.repos.WriteStandardKeyValueRepo
import dev.inmo.micro_utils.repos.ktor.common.key_value.* import dev.inmo.micro_utils.repos.ktor.common.key_value.*
import io.ktor.application.call import io.ktor.http.ContentType
import io.ktor.routing.Route import io.ktor.routing.Route
import io.ktor.routing.post import io.ktor.routing.post
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.* import kotlinx.serialization.builtins.*
fun <K, V> Route.configureWriteStandardKeyValueRepoRoutes (
originalRepo: WriteStandardKeyValueRepo<K, V>,
keySerializer: KSerializer<K>,
valueSerializer: KSerializer<V>,
unifiedRouter: UnifiedRouter
) {
val keyValueMapSerializer = MapSerializer(keySerializer, valueSerializer)
val keysListSerializer = ListSerializer(keySerializer)
val valuesListSerializer = ListSerializer(valueSerializer)
unifiedRouter.apply {
includeWebsocketHandling(
onNewValueRoute,
originalRepo.onNewValue,
PairSerializer(keySerializer, valueSerializer)
)
includeWebsocketHandling(
onValueRemovedRoute,
originalRepo.onValueRemoved,
keySerializer
)
}
post(setRoute) {
unifiedRouter.apply {
val toSet = uniload(
keyValueMapSerializer
)
unianswer(Unit.serializer(), originalRepo.set(toSet))
}
}
post(unsetRoute) {
unifiedRouter.apply {
val toUnset = uniload(keysListSerializer)
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 ( fun <K, V> Route.configureWriteStandartKeyValueRepoRoutes (
originalRepo: WriteStandardKeyValueRepo<K, V>, originalRepo: WriteStandardKeyValueRepo<K, V>,
keySerializer: KSerializer<K>, keySerializer: KSerializer<K>,
valueSerializer: KSerializer<V>, valueSerializer: KSerializer<V>,
) { serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
val keyValueMapSerializer = MapSerializer(keySerializer, valueSerializer) serialFormatContentType: ContentType = standardKtorSerialFormatContentType
val keysListSerializer = ListSerializer(keySerializer) ) = configureWriteStandardKeyValueRepoRoutes(originalRepo, keySerializer, valueSerializer, UnifiedRouter(serialFormat, serialFormatContentType))
includeWebsocketHandling(
onNewValueRoute,
originalRepo.onNewValue,
PairSerializer(keySerializer, valueSerializer)
)
includeWebsocketHandling(
onValueRemovedRoute,
originalRepo.onValueRemoved,
keySerializer
)
post(setRoute) {
val toSet = call.uniload(
keyValueMapSerializer
)
call.unianswer(Unit.serializer(), originalRepo.set(toSet))
}
post(unsetRoute) {
val toUnset = call.uniload(keysListSerializer)
call.unianswer(Unit.serializer(), originalRepo.unset(toUnset))
}
}

View File

@@ -1,6 +1,11 @@
package dev.inmo.micro_utils.repos.ktor.server.one_to_many package dev.inmo.micro_utils.repos.ktor.server.one_to_many
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.UnifiedRouter
import dev.inmo.micro_utils.ktor.server.standardKtorSerialFormatContentType
import dev.inmo.micro_utils.repos.OneToManyKeyValueRepo import dev.inmo.micro_utils.repos.OneToManyKeyValueRepo
import io.ktor.http.ContentType
import io.ktor.routing.Route import io.ktor.routing.Route
import io.ktor.routing.route import io.ktor.routing.route
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
@@ -9,10 +14,22 @@ fun <Key, Value> Route.configureOneToManyKeyValueRepoRoutes(
baseSubpart: String, baseSubpart: String,
originalRepo: OneToManyKeyValueRepo<Key, Value>, originalRepo: OneToManyKeyValueRepo<Key, Value>,
keySerializer: KSerializer<Key>, keySerializer: KSerializer<Key>,
valueSealizer: KSerializer<Value>, valueSerializer: KSerializer<Value>,
unifiedRouter: UnifiedRouter
) { ) {
route(baseSubpart) { route(baseSubpart) {
configureOneToManyReadKeyValueRepoRoutes(originalRepo, keySerializer, valueSealizer) configureOneToManyReadKeyValueRepoRoutes(originalRepo, keySerializer, valueSerializer, unifiedRouter)
configureOneToManyWriteKeyValueRepoRoutes(originalRepo, keySerializer, valueSealizer) configureOneToManyWriteKeyValueRepoRoutes(originalRepo, keySerializer, valueSerializer, unifiedRouter)
} }
} }
fun <Key, Value> Route.configureOneToManyKeyValueRepoRoutes(
baseSubpart: String,
originalRepo: OneToManyKeyValueRepo<Key, Value>,
keySerializer: KSerializer<Key>,
valueSerializer: KSerializer<Value>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
) = configureOneToManyKeyValueRepoRoutes(
baseSubpart, originalRepo, keySerializer, valueSerializer, UnifiedRouter(serialFormat, serialFormatContentType)
)

View File

@@ -1,5 +1,7 @@
package dev.inmo.micro_utils.repos.ktor.server.one_to_many package dev.inmo.micro_utils.repos.ktor.server.one_to_many
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.* import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.pagination.PaginationResult import dev.inmo.micro_utils.pagination.PaginationResult
import dev.inmo.micro_utils.pagination.extractPagination import dev.inmo.micro_utils.pagination.extractPagination
@@ -10,6 +12,7 @@ import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
import dev.inmo.micro_utils.repos.ktor.common.valueParameterName import dev.inmo.micro_utils.repos.ktor.common.valueParameterName
import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName
import io.ktor.application.call import io.ktor.application.call
import io.ktor.http.ContentType
import io.ktor.routing.Route import io.ktor.routing.Route
import io.ktor.routing.get import io.ktor.routing.get
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
@@ -18,89 +21,110 @@ import kotlinx.serialization.builtins.serializer
fun <Key, Value> Route.configureOneToManyReadKeyValueRepoRoutes( fun <Key, Value> Route.configureOneToManyReadKeyValueRepoRoutes(
originalRepo: ReadOneToManyKeyValueRepo<Key, Value>, originalRepo: ReadOneToManyKeyValueRepo<Key, Value>,
keySerializer: KSerializer<Key>, keySerializer: KSerializer<Key>,
valueSealizer: KSerializer<Value>, valueSerializer: KSerializer<Value>,
unifiedRouter: UnifiedRouter
) { ) {
val paginationKeyResult = PaginationResult.serializer(keySerializer) val paginationKeyResult = PaginationResult.serializer(keySerializer)
val paginationValueResult = PaginationResult.serializer(valueSealizer) val paginationValueResult = PaginationResult.serializer(valueSerializer)
get(getRoute) { get(getRoute) {
val pagination = call.request.queryParameters.extractPagination unifiedRouter.apply {
val key = call.decodeUrlQueryValueOrSendError( val pagination = call.request.queryParameters.extractPagination
keyParameterName, val key = decodeUrlQueryValueOrSendError(
keySerializer keyParameterName,
) ?: return@get keySerializer
val reversed = call.decodeUrlQueryValue( ) ?: return@get
reversedParameterName, val reversed = decodeUrlQueryValue(
Boolean.serializer() reversedParameterName,
) ?: false Boolean.serializer()
) ?: false
call.unianswer( unianswer(
paginationValueResult, paginationValueResult,
originalRepo.get(key, pagination, reversed) originalRepo.get(key, pagination, reversed)
) )
}
} }
get(keysRoute) { get(keysRoute) {
val pagination = call.request.queryParameters.extractPagination unifiedRouter.apply {
val reversed = call.decodeUrlQueryValue( val pagination = call.request.queryParameters.extractPagination
reversedParameterName, val reversed = decodeUrlQueryValue(
Boolean.serializer() reversedParameterName,
) ?: false Boolean.serializer()
val value: Value? = call.decodeUrlQueryValue( ) ?: false
valueParameterName, val value: Value? = decodeUrlQueryValue(
valueSealizer valueParameterName,
) valueSerializer
)
call.unianswer( unianswer(
paginationKeyResult, paginationKeyResult,
value ?.let { originalRepo.keys(value, pagination, reversed) } ?: originalRepo.keys(pagination, reversed) value?.let { originalRepo.keys(value, pagination, reversed) } ?: originalRepo.keys(pagination, reversed)
) )
}
} }
get(containsByKeyRoute) { get(containsByKeyRoute) {
val key = call.decodeUrlQueryValueOrSendError( unifiedRouter.apply {
keyParameterName, val key = decodeUrlQueryValueOrSendError(
keySerializer keyParameterName,
) ?: return@get keySerializer
) ?: return@get
call.unianswer( unianswer(
Boolean.serializer(), Boolean.serializer(),
originalRepo.contains(key) originalRepo.contains(key)
) )
}
} }
get(containsByKeyValueRoute) { get(containsByKeyValueRoute) {
val key = call.decodeUrlQueryValueOrSendError( unifiedRouter.apply {
keyParameterName, val key = decodeUrlQueryValueOrSendError(
keySerializer keyParameterName,
) ?: return@get keySerializer
val value = call.decodeUrlQueryValueOrSendError( ) ?: return@get
valueParameterName, val value = decodeUrlQueryValueOrSendError(
valueSealizer valueParameterName,
) ?: return@get valueSerializer
) ?: return@get
call.unianswer( unianswer(
Boolean.serializer(), Boolean.serializer(),
originalRepo.contains(key, value) originalRepo.contains(key, value)
) )
}
} }
get(countByKeyRoute) { get(countByKeyRoute) {
val key = call.decodeUrlQueryValueOrSendError( unifiedRouter.apply {
keyParameterName, val key = decodeUrlQueryValueOrSendError(
keySerializer keyParameterName,
) ?: return@get keySerializer
) ?: return@get
call.unianswer( unianswer(
Long.serializer(), Long.serializer(),
originalRepo.count(key) originalRepo.count(key)
) )
}
} }
get(countRoute) { get(countRoute) {
call.unianswer( unifiedRouter.apply {
Long.serializer(), unianswer(
originalRepo.count() Long.serializer(),
) originalRepo.count()
)
}
} }
} }
inline fun <Key, Value> Route.configureOneToManyReadKeyValueRepoRoutes(
originalRepo: ReadOneToManyKeyValueRepo<Key, Value>,
keySerializer: KSerializer<Key>,
valueSerializer: KSerializer<Value>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
) = configureOneToManyReadKeyValueRepoRoutes(originalRepo, keySerializer, valueSerializer, UnifiedRouter(serialFormat, serialFormatContentType))

View File

@@ -1,9 +1,12 @@
package dev.inmo.micro_utils.repos.ktor.server.one_to_many package dev.inmo.micro_utils.repos.ktor.server.one_to_many
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.* import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.repos.WriteOneToManyKeyValueRepo import dev.inmo.micro_utils.repos.WriteOneToManyKeyValueRepo
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
import io.ktor.application.call import io.ktor.application.call
import io.ktor.http.ContentType
import io.ktor.routing.Route import io.ktor.routing.Route
import io.ktor.routing.post import io.ktor.routing.post
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
@@ -13,61 +16,78 @@ fun <Key, Value> Route.configureOneToManyWriteKeyValueRepoRoutes(
originalRepo: WriteOneToManyKeyValueRepo<Key, Value>, originalRepo: WriteOneToManyKeyValueRepo<Key, Value>,
keySerializer: KSerializer<Key>, keySerializer: KSerializer<Key>,
valueSerializer: KSerializer<Value>, valueSerializer: KSerializer<Value>,
unifiedRouter: UnifiedRouter
) { ) {
val keyValueSerializer = PairSerializer(keySerializer, valueSerializer) val keyValueSerializer = PairSerializer(keySerializer, valueSerializer)
val keyValueMapSerializer = MapSerializer(keySerializer, ListSerializer(valueSerializer)) val keyValueMapSerializer = MapSerializer(keySerializer, ListSerializer(valueSerializer))
includeWebsocketHandling( unifiedRouter.apply {
onNewValueRoute, includeWebsocketHandling(
originalRepo.onNewValue, onNewValueRoute,
keyValueSerializer originalRepo.onNewValue,
) keyValueSerializer
includeWebsocketHandling( )
onValueRemovedRoute, includeWebsocketHandling(
originalRepo.onValueRemoved, onValueRemovedRoute,
keyValueSerializer originalRepo.onValueRemoved,
) keyValueSerializer
includeWebsocketHandling( )
onDataClearedRoute, includeWebsocketHandling(
originalRepo.onDataCleared, onDataClearedRoute,
keySerializer originalRepo.onDataCleared,
) keySerializer
)
}
post(addRoute) { post(addRoute) {
val obj = call.uniload(keyValueMapSerializer) unifiedRouter.apply {
val obj = uniload(keyValueMapSerializer)
call.unianswer( unianswer(
Unit.serializer(), Unit.serializer(),
originalRepo.add(obj) originalRepo.add(obj)
) )
}
} }
post(removeRoute) { post(removeRoute) {
val obj = call.uniload( unifiedRouter.apply {
keyValueMapSerializer val obj = uniload(keyValueMapSerializer)
)
call.unianswer( unianswer(
Unit.serializer(), Unit.serializer(),
originalRepo.remove(obj), originalRepo.remove(obj),
) )
}
} }
post(clearRoute) { post(clearRoute) {
val key = call.uniload(keySerializer) unifiedRouter.apply {
val key = uniload(keySerializer)
call.unianswer( unianswer(
Unit.serializer(), Unit.serializer(),
originalRepo.clear(key), originalRepo.clear(key),
) )
}
} }
post(setRoute) { post(setRoute) {
val obj = call.uniload(keyValueMapSerializer) unifiedRouter.apply {
val obj = uniload(keyValueMapSerializer)
call.unianswer( unianswer(
Unit.serializer(), Unit.serializer(),
originalRepo.set(obj) originalRepo.set(obj)
) )
}
} }
} }
fun <Key, Value> Route.configureOneToManyWriteKeyValueRepoRoutes(
originalRepo: WriteOneToManyKeyValueRepo<Key, Value>,
keySerializer: KSerializer<Key>,
valueSerializer: KSerializer<Value>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
) = configureOneToManyWriteKeyValueRepoRoutes(originalRepo, keySerializer, valueSerializer, UnifiedRouter(serialFormat, serialFormatContentType))