From 78903cd4eb691cf47cf44bc3401458bfda7603c5 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sat, 4 Jun 2022 00:22:36 +0600 Subject: [PATCH] complete improvements in repos ktor parts --- CHANGELOG.md | 6 + .../ktor/client/HttpStatusCodeAsThrowable.kt | 15 ++ .../ApplicationCallRespondWithTypeInfo.kt | 15 ++ .../repos/OneToManyKeyValueRepo.kt | 7 + .../repos/MapOneToManyKeyValueRepo.kt | 4 + .../client/crud/KtorReadStandardCrudRepo.kt | 1 + .../crud/KtorReadStandardCrudRepoClient.kt | 1 + .../crud/KtorWriteStandardCrudRepoClient.kt | 6 +- .../key_value/KtorReadStandardKeyValueRepo.kt | 6 +- .../KtorReadStandardKeyValueRepoClient.kt | 5 +- .../KtorWriteStandardKeyValueRepoClient.kt | 12 +- .../KtorReadStandardKeyValuesRepoClient.kt | 159 ++++++++++++++++++ .../KtorStandardKeyValuesRepoClient.kt | 89 ++++++++++ .../KtorWriteStandardKeyValuesRepoClient.kt | 106 ++++++++++++ .../repos/ktor/common/ContainsRoute.kt | 3 + .../repos/ktor/common/CountRoute.kt | 3 + .../repos/ktor/common/CountRouting.kt | 3 + .../repos/ktor/common/crud/CrudReadRoutes.kt | 1 - .../ktor/common/key_value/KeyValueRoutes.kt | 6 +- .../common/one_to_many/OneToManyRoutes.kt | 2 +- .../common/src/jvmTest/kotlin/CRUDTests.kt | 2 +- .../ktor/common/src/jvmTest/kotlin/KVTests.kt | 4 +- .../common/src/jvmTest/kotlin/KVsTests.kt | 141 ++++++++++++++++ .../server/crud/KtorReadStandardCrudRepo.kt | 1 + .../crud/NewKtorReadStandardCrudRepo.kt | 1 + .../key_value/KtorStandartReadKeyValueRepo.kt | 6 +- .../NewKtorStandartReadKeyValueRepo.kt | 26 +-- .../NewKtorStandartKeyValuesRepo.kt | 47 ++++++ .../NewKtorStandartReadKeyValuesRepo.kt | 107 ++++++++++++ .../NewKtorStandartWriteKeyValuesRepo.kt | 58 +++++++ 30 files changed, 805 insertions(+), 38 deletions(-) create mode 100644 ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/HttpStatusCodeAsThrowable.kt create mode 100644 ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/ApplicationCallRespondWithTypeInfo.kt create mode 100644 repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorReadStandardKeyValuesRepoClient.kt create mode 100644 repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorStandardKeyValuesRepoClient.kt create mode 100644 repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorWriteStandardKeyValuesRepoClient.kt create mode 100644 repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/ContainsRoute.kt create mode 100644 repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/CountRoute.kt create mode 100644 repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/CountRouting.kt create mode 100644 repos/ktor/common/src/jvmTest/kotlin/KVsTests.kt create mode 100644 repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/NewKtorStandartKeyValuesRepo.kt create mode 100644 repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/NewKtorStandartReadKeyValuesRepo.kt create mode 100644 repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/NewKtorStandartWriteKeyValuesRepo.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index c9a0763bafc..33eb21d63d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## 0.11.0 +* `Ktor` + * +* `Repos` + * `Ktor`: + * Fully rewritten work with all declared repositories + ## 0.10.8 * `Common` diff --git a/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/HttpStatusCodeAsThrowable.kt b/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/HttpStatusCodeAsThrowable.kt new file mode 100644 index 00000000000..8f4205c0caf --- /dev/null +++ b/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/HttpStatusCodeAsThrowable.kt @@ -0,0 +1,15 @@ +package dev.inmo.micro_utils.ktor.client + +import io.ktor.client.plugins.ClientRequestException +import io.ktor.client.statement.HttpResponse +import io.ktor.http.isSuccess + +inline fun HttpResponse.throwOnUnsuccess( + unsuccessMessage: () -> String +) { + if (status.isSuccess()) { + return + } + + throw ClientRequestException(this, unsuccessMessage()) +} diff --git a/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/ApplicationCallRespondWithTypeInfo.kt b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/ApplicationCallRespondWithTypeInfo.kt new file mode 100644 index 00000000000..207dde73a63 --- /dev/null +++ b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/ApplicationCallRespondWithTypeInfo.kt @@ -0,0 +1,15 @@ +package dev.inmo.micro_utils.ktor.server + +import io.ktor.server.application.ApplicationCall +import io.ktor.server.response.responseType +import io.ktor.util.InternalAPI +import io.ktor.util.reflect.TypeInfo + +@InternalAPI +suspend fun ApplicationCall.respond( + message: T, + typeInfo: TypeInfo +) { + response.responseType = typeInfo + response.pipeline.execute(this, message as Any) +} diff --git a/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/OneToManyKeyValueRepo.kt b/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/OneToManyKeyValueRepo.kt index df5bafa86d5..ce9836c59cd 100644 --- a/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/OneToManyKeyValueRepo.kt +++ b/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/OneToManyKeyValueRepo.kt @@ -104,6 +104,13 @@ interface OneToManyKeyValueRepo : ReadOneToManyKeyValueRepo = OneToManyKeyValueRepo +class DelegateBasedOneToManyKeyValueRepo( + readDelegate: ReadOneToManyKeyValueRepo, + writeDelegate: WriteOneToManyKeyValueRepo +) : OneToManyKeyValueRepo, + ReadOneToManyKeyValueRepo by readDelegate, + WriteOneToManyKeyValueRepo by writeDelegate + suspend inline fun WriteOneToManyKeyValueRepo.remove( keysAndValues: List>> ) = remove(keysAndValues.toMap()) diff --git a/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapOneToManyKeyValueRepo.kt b/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapOneToManyKeyValueRepo.kt index 08ebbb45f90..be4dbfd7ab0 100644 --- a/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapOneToManyKeyValueRepo.kt +++ b/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapOneToManyKeyValueRepo.kt @@ -80,6 +80,10 @@ class MapWriteOneToManyKeyValueRepo( _onValueRemoved.emit(k to v) } } + if (map[k] ?.isEmpty() == true) { + map.remove(k) + _onDataCleared.emit(k) + } } } diff --git a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepo.kt b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepo.kt index 80955437308..dfb7ff57df9 100644 --- a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepo.kt +++ b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepo.kt @@ -4,6 +4,7 @@ import dev.inmo.micro_utils.ktor.client.* import dev.inmo.micro_utils.ktor.common.* import dev.inmo.micro_utils.pagination.* import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo +import dev.inmo.micro_utils.repos.ktor.common.countRouting import dev.inmo.micro_utils.repos.ktor.common.crud.* import dev.inmo.micro_utils.repos.ktor.common.idParameterName import io.ktor.client.HttpClient diff --git a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepoClient.kt b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepoClient.kt index 82de6de4b5c..088cea5e31c 100644 --- a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepoClient.kt +++ b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepoClient.kt @@ -3,6 +3,7 @@ package dev.inmo.micro_utils.repos.ktor.client.crud import dev.inmo.micro_utils.ktor.common.* import dev.inmo.micro_utils.pagination.* import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo +import dev.inmo.micro_utils.repos.ktor.common.countRouting import dev.inmo.micro_utils.repos.ktor.common.crud.* import dev.inmo.micro_utils.repos.ktor.common.idParameterName import io.ktor.client.HttpClient diff --git a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorWriteStandardCrudRepoClient.kt b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorWriteStandardCrudRepoClient.kt index 0c5e6673b12..6caf6969b83 100644 --- a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorWriteStandardCrudRepoClient.kt +++ b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorWriteStandardCrudRepoClient.kt @@ -11,11 +11,7 @@ import io.ktor.client.request.* import io.ktor.client.statement.HttpResponse import io.ktor.http.ContentType import io.ktor.http.contentType -import io.ktor.util.reflect.TypeInfo -import io.ktor.util.reflect.typeInfo import kotlinx.coroutines.flow.Flow -import kotlinx.serialization.KSerializer -import kotlinx.serialization.builtins.* class KtorWriteStandardCrudRepoClient ( private val baseUrl: String, @@ -50,7 +46,7 @@ class KtorWriteStandardCrudRepoClient ( buildStandardUrl(baseUrl, deleteByIdRouting) ) { deleteByIdSetup(ids) - }.status + }.throwOnUnsuccess { "Unable to delete $ids" } } companion object { diff --git a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorReadStandardKeyValueRepo.kt b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorReadStandardKeyValueRepo.kt index 55bdf8f0ad8..2359c8d2c24 100644 --- a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorReadStandardKeyValueRepo.kt +++ b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorReadStandardKeyValueRepo.kt @@ -4,8 +4,12 @@ import dev.inmo.micro_utils.ktor.client.* import dev.inmo.micro_utils.ktor.common.* import dev.inmo.micro_utils.pagination.* import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo +import dev.inmo.micro_utils.repos.ktor.common.* +import dev.inmo.micro_utils.repos.ktor.common.containsRoute +import dev.inmo.micro_utils.repos.ktor.common.countRoute 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.key_value.keyParameterName +import dev.inmo.micro_utils.repos.ktor.common.key_value.reversedParameterName import io.ktor.client.HttpClient import kotlinx.serialization.* import kotlinx.serialization.builtins.serializer diff --git a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorReadStandardKeyValueRepoClient.kt b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorReadStandardKeyValueRepoClient.kt index e22a426dca2..792d6b0d0d9 100644 --- a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorReadStandardKeyValueRepoClient.kt +++ b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorReadStandardKeyValueRepoClient.kt @@ -4,9 +4,8 @@ import dev.inmo.micro_utils.ktor.common.* import dev.inmo.micro_utils.pagination.* import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo import dev.inmo.micro_utils.repos.ktor.common.* -import dev.inmo.micro_utils.repos.ktor.common.crud.* +import dev.inmo.micro_utils.repos.ktor.common.containsRoute import dev.inmo.micro_utils.repos.ktor.common.key_value.* -import dev.inmo.micro_utils.repos.ktor.common.one_to_many.containsByKeyRoute import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName import io.ktor.client.HttpClient import io.ktor.client.call.body @@ -83,7 +82,7 @@ class KtorReadStandardKeyValueRepoClient( override suspend fun count(): Long = httpClient.get( buildStandardUrl( baseUrl, - countRouting + dev.inmo.micro_utils.repos.ktor.common.countRoute ) ) { contentType(contentType) diff --git a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorWriteStandardKeyValueRepoClient.kt b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorWriteStandardKeyValueRepoClient.kt index 65cceca45e9..d9abaf672ce 100644 --- a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorWriteStandardKeyValueRepoClient.kt +++ b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorWriteStandardKeyValueRepoClient.kt @@ -1,21 +1,17 @@ package dev.inmo.micro_utils.repos.ktor.client.key_value import dev.inmo.micro_utils.ktor.client.createStandardWebsocketFlow +import dev.inmo.micro_utils.ktor.client.throwOnUnsuccess import dev.inmo.micro_utils.ktor.common.* -import dev.inmo.micro_utils.pagination.* import dev.inmo.micro_utils.repos.WriteStandardKeyValueRepo -import dev.inmo.micro_utils.repos.ktor.common.* -import dev.inmo.micro_utils.repos.ktor.common.crud.* import dev.inmo.micro_utils.repos.ktor.common.key_value.* import io.ktor.client.HttpClient -import io.ktor.client.request.get import io.ktor.client.request.post import io.ktor.http.* import io.ktor.util.InternalAPI import io.ktor.util.reflect.TypeInfo import io.ktor.util.reflect.typeInfo import kotlinx.coroutines.flow.Flow -import kotlinx.serialization.* class KtorWriteStandardKeyValueRepoClient( private val baseUrl: String, @@ -35,7 +31,7 @@ class KtorWriteStandardKeyValueRepoClient( body = toUnset bodyType = objectsListTypeInfo contentType(contentType) - }.status + }.throwOnUnsuccess { "Unable to unset data with values $toUnset" } } @OptIn(InternalAPI::class) @@ -46,7 +42,7 @@ class KtorWriteStandardKeyValueRepoClient( body = toUnset bodyType = idsListTypeInfo contentType(contentType) - }.status + }.throwOnUnsuccess { "Unable to unset $toUnset" } } @OptIn(InternalAPI::class) @@ -57,7 +53,7 @@ class KtorWriteStandardKeyValueRepoClient( body = toSet bodyType = idsToObjectsMapTypeInfo contentType(contentType) - }.status + }.throwOnUnsuccess { "Unable to set $toSet" } } companion object { diff --git a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorReadStandardKeyValuesRepoClient.kt b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorReadStandardKeyValuesRepoClient.kt new file mode 100644 index 00000000000..f05478c1ea7 --- /dev/null +++ b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorReadStandardKeyValuesRepoClient.kt @@ -0,0 +1,159 @@ +package dev.inmo.micro_utils.repos.ktor.client.one_to_many + +import dev.inmo.micro_utils.ktor.common.* +import dev.inmo.micro_utils.pagination.* +import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo +import dev.inmo.micro_utils.repos.ktor.common.* +import dev.inmo.micro_utils.repos.ktor.common.crud.* +import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* +import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName +import io.ktor.client.HttpClient +import io.ktor.client.call.body +import io.ktor.client.request.get +import io.ktor.http.* +import io.ktor.util.reflect.TypeInfo +import io.ktor.util.reflect.typeInfo +import kotlinx.serialization.* + +class KtorReadStandardKeyValuesRepoClient( + private val baseUrl: String, + private val httpClient: HttpClient, + private val contentType: ContentType, + private val paginationResultValuesTypeInfo: TypeInfo, + private val paginationResultKeysTypeInfo: TypeInfo, + private val keySerializer: suspend (Key) -> String, + private val valueSerializer: suspend (Value) -> String +) : ReadOneToManyKeyValueRepo { + override suspend fun get( + k: Key, + pagination: Pagination, + reversed: Boolean + ): PaginationResult = httpClient.get( + buildStandardUrl( + baseUrl, + getRoute, + pagination.asUrlQueryParts + (reversedParameterName to reversed.toString()) + (keyParameterName to keySerializer(k)) + ) + ) { + contentType(contentType) + }.body(paginationResultValuesTypeInfo) + + override suspend fun keys( + pagination: Pagination, + reversed: Boolean + ): PaginationResult = httpClient.get( + buildStandardUrl( + baseUrl, + keysRoute, + pagination.asUrlQueryParts + (reversedParameterName to reversed.toString()) + ) + ) { + contentType(contentType) + }.body(paginationResultKeysTypeInfo) + + override suspend fun keys( + v: Value, + pagination: Pagination, + reversed: Boolean + ): PaginationResult = httpClient.get( + buildStandardUrl( + baseUrl, + keysRoute, + pagination.asUrlQueryParts + (reversedParameterName to reversed.toString()) + (valueParameterName to valueSerializer(v)) + ) + ) { + contentType(contentType) + }.body(paginationResultKeysTypeInfo) + + override suspend fun contains(k: Key): Boolean = httpClient.get( + buildStandardUrl( + baseUrl, + containsRoute, + keyParameterName to keySerializer(k) + ) + ) { + contentType(contentType) + }.body() + + override suspend fun contains(k: Key, v: Value): Boolean = httpClient.get( + buildStandardUrl( + baseUrl, + containsRoute, + keyParameterName to keySerializer(k), + valueParameterName to valueSerializer(v) + ) + ) { + contentType(contentType) + }.body() + + override suspend fun count(): Long = httpClient.get( + buildStandardUrl( + baseUrl, + countRouting + ) + ) { + contentType(contentType) + }.body() + + override suspend fun count(k: Key): Long = httpClient.get( + buildStandardUrl( + baseUrl, + countRouting, + keyParameterName to keySerializer(k), + ) + ) { + contentType(contentType) + }.body() +} + +inline fun KtorReadStandardKeyValuesRepoClient( + baseUrl: String, + httpClient: HttpClient, + contentType: ContentType, + noinline keySerializer: suspend (Key) -> String, + noinline valueSerializer: suspend (Value) -> String +) = KtorReadStandardKeyValuesRepoClient( + baseUrl, + httpClient, + contentType, + typeInfo>(), + typeInfo>(), + keySerializer, + valueSerializer +) + +inline fun KtorReadStandardKeyValuesRepoClient( + baseUrl: String, + httpClient: HttpClient, + idsSerializer: KSerializer, + valueSerializer: KSerializer, + serialFormat: StringFormat, + contentType: ContentType, +) = KtorReadStandardKeyValuesRepoClient( + baseUrl, + httpClient, + contentType, + { + serialFormat.encodeToString(idsSerializer, it).encodeURLQueryComponent() + } +) { + serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent() +} + +inline fun KtorReadStandardKeyValuesRepoClient( + baseUrl: String, + httpClient: HttpClient, + idsSerializer: KSerializer, + valuesSerializer: KSerializer, + serialFormat: BinaryFormat, + contentType: ContentType, +) = KtorReadStandardKeyValuesRepoClient( + baseUrl, + httpClient, + contentType, + { + serialFormat.encodeHex(idsSerializer, it) + } +) { + serialFormat.encodeHex(valuesSerializer, it) +} diff --git a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorStandardKeyValuesRepoClient.kt b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorStandardKeyValuesRepoClient.kt new file mode 100644 index 00000000000..6f1e2f43087 --- /dev/null +++ b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorStandardKeyValuesRepoClient.kt @@ -0,0 +1,89 @@ +package dev.inmo.micro_utils.repos.ktor.client.one_to_many + +import dev.inmo.micro_utils.ktor.common.* +import dev.inmo.micro_utils.repos.* +import io.ktor.client.HttpClient +import io.ktor.http.ContentType +import io.ktor.http.encodeURLQueryComponent +import kotlinx.serialization.* + +class KtorStandardKeyValuesRepoClient ( + readDelegate: ReadOneToManyKeyValueRepo, + writeDelegate: WriteOneToManyKeyValueRepo +) : OneToManyKeyValueRepo by DelegateBasedOneToManyKeyValueRepo( + readDelegate, + writeDelegate +) { + companion object { + inline operator fun invoke( + baseUrl: String, + httpClient: HttpClient, + contentType: ContentType, + noinline keySerializer: suspend (Key) -> String, + noinline valueSerializer: suspend (Value) -> String + ) = KtorStandardKeyValuesRepoClient( + KtorReadStandardKeyValuesRepoClient( + baseUrl, + httpClient, + contentType, + keySerializer, + valueSerializer + ), + KtorWriteStandardKeyValuesRepoClient( + baseUrl, + httpClient, + contentType + ) + ) + inline operator fun invoke( + baseUrl: String, + subpart: String, + httpClient: HttpClient, + contentType: ContentType, + noinline keySerializer: suspend (Key) -> String, + noinline valueSerializer: suspend (Value) -> String + ) = KtorStandardKeyValuesRepoClient( + buildStandardUrl(baseUrl, subpart), + httpClient, + contentType, + keySerializer, + valueSerializer + ) + } +} + +inline fun KtorStandardKeyValuesRepoClient( + baseUrl: String, + httpClient: HttpClient, + contentType: ContentType, + keySerializer: SerializationStrategy, + valueSerializer: SerializationStrategy, + serialFormat: StringFormat, +) = KtorStandardKeyValuesRepoClient( + baseUrl, + httpClient, + contentType, + { + serialFormat.encodeToString(keySerializer, it).encodeURLQueryComponent() + } +) { + serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent() +} + +inline fun KtorStandardKeyValuesRepoClient( + baseUrl: String, + httpClient: HttpClient, + contentType: ContentType, + keySerializer: SerializationStrategy, + valueSerializer: SerializationStrategy, + serialFormat: BinaryFormat, +) = KtorStandardKeyValuesRepoClient( + baseUrl, + httpClient, + contentType, + { + serialFormat.encodeHex(keySerializer, it) + } +) { + serialFormat.encodeHex(valueSerializer, it) +} diff --git a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorWriteStandardKeyValuesRepoClient.kt b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorWriteStandardKeyValuesRepoClient.kt new file mode 100644 index 00000000000..1f77a79f57f --- /dev/null +++ b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorWriteStandardKeyValuesRepoClient.kt @@ -0,0 +1,106 @@ +package dev.inmo.micro_utils.repos.ktor.client.one_to_many + +import dev.inmo.micro_utils.ktor.client.createStandardWebsocketFlow +import dev.inmo.micro_utils.ktor.client.throwOnUnsuccess +import dev.inmo.micro_utils.ktor.common.* +import dev.inmo.micro_utils.repos.WriteOneToManyKeyValueRepo +import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* +import io.ktor.client.HttpClient +import io.ktor.client.request.post +import io.ktor.http.* +import io.ktor.util.InternalAPI +import io.ktor.util.reflect.TypeInfo +import io.ktor.util.reflect.typeInfo +import kotlinx.coroutines.flow.Flow + +class KtorWriteStandardKeyValuesRepoClient( + private val baseUrl: String, + private val httpClient: HttpClient, + private val contentType: ContentType, + override val onNewValue: Flow>, + override val onValueRemoved: Flow>, + override val onDataCleared: Flow, + private val keyTypeInfo: TypeInfo, + private val valueTypeInfo: TypeInfo, + private val keyToValuesMapTypeInfo: TypeInfo +) : WriteOneToManyKeyValueRepo { + + @OptIn(InternalAPI::class) + override suspend fun add(toAdd: Map>) { + httpClient.post( + buildStandardUrl(baseUrl, addRoute) + ) { + body = toAdd + bodyType = keyToValuesMapTypeInfo + contentType(contentType) + }.throwOnUnsuccess { "Unable to add $toAdd" } + } + + @OptIn(InternalAPI::class) + override suspend fun remove(toRemove: Map>) { + httpClient.post( + buildStandardUrl(baseUrl, removeRoute) + ) { + body = toRemove + bodyType = keyToValuesMapTypeInfo + contentType(contentType) + }.throwOnUnsuccess { "Unable to remove $toRemove" } + } + + @OptIn(InternalAPI::class) + override suspend fun clear(k: Key) { + httpClient.post( + buildStandardUrl(baseUrl, clearRoute) + ) { + body = k + bodyType = keyTypeInfo + contentType(contentType) + }.throwOnUnsuccess { "Unable to clear data with key $k" } + } + + @OptIn(InternalAPI::class) + override suspend fun clearWithValue(v: Value) { + httpClient.post( + buildStandardUrl(baseUrl, clearWithValueRoute) + ) { + body = v + bodyType = valueTypeInfo + contentType(contentType) + }.throwOnUnsuccess { "Unable to clear data with value $v" } + } + + @OptIn(InternalAPI::class) + override suspend fun set(toSet: Map>) { + httpClient.post( + buildStandardUrl(baseUrl, setRoute) + ) { + body = toSet + bodyType = keyToValuesMapTypeInfo + contentType(contentType) + }.throwOnUnsuccess { "Unable to set data $toSet" } + } + + companion object { + inline operator fun invoke( + baseUrl: String, + httpClient: HttpClient, + contentType: ContentType + ) = KtorWriteStandardKeyValuesRepoClient( + baseUrl, + httpClient, + contentType, + httpClient.createStandardWebsocketFlow( + buildStandardUrl(baseUrl, onNewValueRoute), + ), + httpClient.createStandardWebsocketFlow( + buildStandardUrl(baseUrl, onValueRemovedRoute), + ), + httpClient.createStandardWebsocketFlow( + buildStandardUrl(baseUrl, onDataClearedRoute), + ), + typeInfo(), + typeInfo(), + typeInfo>>() + ) + } +} diff --git a/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/ContainsRoute.kt b/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/ContainsRoute.kt new file mode 100644 index 00000000000..988d02c30ee --- /dev/null +++ b/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/ContainsRoute.kt @@ -0,0 +1,3 @@ +package dev.inmo.micro_utils.repos.ktor.common + +const val containsRoute = "contains" diff --git a/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/CountRoute.kt b/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/CountRoute.kt new file mode 100644 index 00000000000..c1811cba14e --- /dev/null +++ b/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/CountRoute.kt @@ -0,0 +1,3 @@ +package dev.inmo.micro_utils.repos.ktor.common + +const val countRoute = "count" diff --git a/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/CountRouting.kt b/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/CountRouting.kt new file mode 100644 index 00000000000..5803193e10f --- /dev/null +++ b/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/CountRouting.kt @@ -0,0 +1,3 @@ +package dev.inmo.micro_utils.repos.ktor.common + +const val countRouting = "count" diff --git a/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/crud/CrudReadRoutes.kt b/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/crud/CrudReadRoutes.kt index 00348cc409d..dc44163c26e 100644 --- a/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/crud/CrudReadRoutes.kt +++ b/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/crud/CrudReadRoutes.kt @@ -3,4 +3,3 @@ package dev.inmo.micro_utils.repos.ktor.common.crud const val getByPaginationRouting = "getByPagination" const val getByIdRouting = "getById" const val containsRouting = "contains" -const val countRouting = "count" diff --git a/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/key_value/KeyValueRoutes.kt b/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/key_value/KeyValueRoutes.kt index 860429cf28c..61f14d6c4bf 100644 --- a/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/key_value/KeyValueRoutes.kt +++ b/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/key_value/KeyValueRoutes.kt @@ -3,11 +3,11 @@ package dev.inmo.micro_utils.repos.ktor.common.key_value const val getRoute = "get" const val valuesRoute = "values" const val keysRoute = "keys" -const val containsRoute = "contains" -const val countRoute = "count" +const val containsRoute = dev.inmo.micro_utils.repos.ktor.common.containsRoute +const val countRoute = dev.inmo.micro_utils.repos.ktor.common.countRoute const val onNewValueRoute = "onNewValue" const val onValueRemovedRoute = "onValueRemoved" const val setRoute = "set" const val unsetRoute = "unset" -const val unsetWithValuesRoute = "unsetWithValues" \ No newline at end of file +const val unsetWithValuesRoute = "unsetWithValues" diff --git a/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/one_to_many/OneToManyRoutes.kt b/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/one_to_many/OneToManyRoutes.kt index b10a45476ff..3bd568bb3a4 100644 --- a/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/one_to_many/OneToManyRoutes.kt +++ b/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/one_to_many/OneToManyRoutes.kt @@ -5,7 +5,7 @@ const val keysRoute = "keys" const val containsByKeyRoute = "containsByKey" const val containsByKeyValueRoute = "containsByKeyValue" const val countByKeyRoute = "countByKey" -const val countRoute = "count" +const val countRoute = dev.inmo.micro_utils.repos.ktor.common.countRoute const val onNewValueRoute = "onNewValue" const val onValueRemovedRoute = "onValueRemoved" diff --git a/repos/ktor/common/src/jvmTest/kotlin/CRUDTests.kt b/repos/ktor/common/src/jvmTest/kotlin/CRUDTests.kt index 9c17c341e0f..4ac4993dffc 100644 --- a/repos/ktor/common/src/jvmTest/kotlin/CRUDTests.kt +++ b/repos/ktor/common/src/jvmTest/kotlin/CRUDTests.kt @@ -21,7 +21,7 @@ class CRUDTests { @OptIn(ExperimentalCoroutinesApi::class) @Test fun testCRUDFunctions() { - runTest() { + runTest { val map = mutableMapOf() val repo = MapCRUDRepo( map, diff --git a/repos/ktor/common/src/jvmTest/kotlin/KVTests.kt b/repos/ktor/common/src/jvmTest/kotlin/KVTests.kt index e9071246e86..c3ddf467325 100644 --- a/repos/ktor/common/src/jvmTest/kotlin/KVTests.kt +++ b/repos/ktor/common/src/jvmTest/kotlin/KVTests.kt @@ -22,8 +22,8 @@ import kotlin.test.* class KVTests { @OptIn(ExperimentalCoroutinesApi::class) @Test - fun testCRUDFunctions() { - runTest() { + fun testKVFunctions() { + runTest { val map = mutableMapOf() val repo = MapKeyValueRepo(map) val server = io.ktor.server.engine.embeddedServer( diff --git a/repos/ktor/common/src/jvmTest/kotlin/KVsTests.kt b/repos/ktor/common/src/jvmTest/kotlin/KVsTests.kt new file mode 100644 index 00000000000..36363da5c60 --- /dev/null +++ b/repos/ktor/common/src/jvmTest/kotlin/KVsTests.kt @@ -0,0 +1,141 @@ +import dev.inmo.micro_utils.pagination.firstPageWithOneElementPagination +import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging +import dev.inmo.micro_utils.repos.* +import dev.inmo.micro_utils.repos.ktor.client.key_value.KtorStandardKeyValueRepoClient +import dev.inmo.micro_utils.repos.ktor.client.one_to_many.KtorStandardKeyValuesRepoClient +import dev.inmo.micro_utils.repos.ktor.server.one_to_many.configureStandardKeyValuesRepoRoutes +import io.ktor.client.HttpClient +import io.ktor.client.plugins.logging.Logging +import io.ktor.http.ContentType +import io.ktor.serialization.kotlinx.KotlinxWebsocketSerializationConverter +import io.ktor.serialization.kotlinx.json.json +import io.ktor.server.application.install +import io.ktor.server.cio.CIO +import io.ktor.server.plugins.contentnegotiation.ContentNegotiation +import io.ktor.server.routing.routing +import io.ktor.server.websocket.WebSockets +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.json.Json +import kotlin.test.* + +class KVsTests { + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun testKVsFunctions() { + runTest { + val map = mutableMapOf>() + val repo = MapOneToManyKeyValueRepo(map) + val server = io.ktor.server.engine.embeddedServer( + CIO, + 23456, + "127.0.0.1" + ) { + install(ContentNegotiation) { + json() + } + install(WebSockets) { + contentConverter = KotlinxWebsocketSerializationConverter(Json) + } + routing { + configureStandardKeyValuesRepoRoutes( + repo, + Int.serializer(), + ComplexData.serializer(), + Json {} + ) + } + }.start(false) + val client = HttpClient { + install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) { + json() + } + install(Logging) + install(io.ktor.client.plugins.websocket.WebSockets) { + contentConverter = KotlinxWebsocketSerializationConverter(Json) + } + } + val crudClient = KtorStandardKeyValuesRepoClient( + "http://127.0.0.1:23456", + client, + ContentType.Application.Json, + Int.serializer(), + ComplexData.serializer(), + Json + ) + + val dataInOneKey = ComplexData(1, title = "Example1") + val dataInMultipleKeys = ComplexData(2, title = "Example2") + val repeatCount = 3 + + val dataList = listOf( + 1 to listOf(dataInOneKey) + ) + (0 until repeatCount).map { + (it + 2) to listOf(dataInMultipleKeys) + } + + dataList.forEachIndexed { i, (id, data) -> + crudClient.set(id, data) + assertEquals(i + 1, map.size) + assertEquals(map.size.toLong(), crudClient.count()) + assertEquals(i + 1L, crudClient.count()) + dataList.take(i + 1).forEach { (id, data) -> + assertContentEquals(data, map[id]) + assertContentEquals(data, crudClient.getAll(id)) + assertContentEquals(map[id], crudClient.getAll(id)) + } + } + + dataList.forEach { (key, data) -> + assertTrue(crudClient.contains(key)) + assertContentEquals(data, crudClient.getAll(key)) + } + + assertEquals( + dataList.mapNotNull { if (it.second.contains(dataInMultipleKeys)) it.first else null }, + getAllWithNextPaging(firstPageWithOneElementPagination) { + crudClient.keys(dataInMultipleKeys, it) + } + ) + + assertEquals( + dataList.mapNotNull { if (it.second.contains(dataInOneKey)) it.first else null }, + getAllWithNextPaging(firstPageWithOneElementPagination) { + crudClient.keys(dataInOneKey, it) + } + ) + + assertEquals( + dataList.map { it.first }, + getAllWithNextPaging(firstPageWithOneElementPagination) { + crudClient.keys(it) + } + ) + + assertEquals( + dataList.map { it.first }, + getAllWithNextPaging(firstPageWithOneElementPagination) { + crudClient.keys(it) + } + ) + + assertEquals(dataList.size.toLong(), crudClient.count()) + + crudClient.remove(dataList.filter { it.second.contains(dataInMultipleKeys) }) + println(map) + assertEquals( + dataList.filter { it.second.contains(dataInOneKey) }.size.toLong(), + crudClient.count() + ) + + crudClient.remove(dataList.filter { it.second.contains(dataInOneKey) }) + assertEquals( + 0, + crudClient.count() + ) + + server.stop() + } + } +} diff --git a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/KtorReadStandardCrudRepo.kt b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/KtorReadStandardCrudRepo.kt index 75053535d03..e5bdbaa5b84 100644 --- a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/KtorReadStandardCrudRepo.kt +++ b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/KtorReadStandardCrudRepo.kt @@ -6,6 +6,7 @@ import dev.inmo.micro_utils.ktor.server.* import dev.inmo.micro_utils.pagination.PaginationResult import dev.inmo.micro_utils.pagination.extractPagination import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo +import dev.inmo.micro_utils.repos.ktor.common.countRouting import dev.inmo.micro_utils.repos.ktor.common.crud.* import io.ktor.http.ContentType import io.ktor.server.application.call diff --git a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/NewKtorReadStandardCrudRepo.kt b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/NewKtorReadStandardCrudRepo.kt index e8ee34dd409..53354208e16 100644 --- a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/NewKtorReadStandardCrudRepo.kt +++ b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/NewKtorReadStandardCrudRepo.kt @@ -4,6 +4,7 @@ import dev.inmo.micro_utils.ktor.common.decodeHex import dev.inmo.micro_utils.ktor.server.* import dev.inmo.micro_utils.pagination.extractPagination import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo +import dev.inmo.micro_utils.repos.ktor.common.countRouting import dev.inmo.micro_utils.repos.ktor.common.crud.* import dev.inmo.micro_utils.repos.ktor.common.idParameterName import io.ktor.http.ContentType diff --git a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key_value/KtorStandartReadKeyValueRepo.kt b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key_value/KtorStandartReadKeyValueRepo.kt index 843b935fe18..a24b402cb3a 100644 --- a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key_value/KtorStandartReadKeyValueRepo.kt +++ b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key_value/KtorStandartReadKeyValueRepo.kt @@ -6,8 +6,12 @@ import dev.inmo.micro_utils.ktor.server.* import dev.inmo.micro_utils.pagination.PaginationResult import dev.inmo.micro_utils.pagination.extractPagination import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo +import dev.inmo.micro_utils.repos.ktor.common.* +import dev.inmo.micro_utils.repos.ktor.common.containsRoute +import dev.inmo.micro_utils.repos.ktor.common.countRoute 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.key_value.keyParameterName +import dev.inmo.micro_utils.repos.ktor.common.key_value.reversedParameterName import io.ktor.http.ContentType import io.ktor.server.application.call import io.ktor.server.routing.Route diff --git a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key_value/NewKtorStandartReadKeyValueRepo.kt b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key_value/NewKtorStandartReadKeyValueRepo.kt index 8ade9432458..a0f55ecc488 100644 --- a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key_value/NewKtorStandartReadKeyValueRepo.kt +++ b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key_value/NewKtorStandartReadKeyValueRepo.kt @@ -4,21 +4,20 @@ import dev.inmo.micro_utils.ktor.common.* import dev.inmo.micro_utils.ktor.server.* import dev.inmo.micro_utils.pagination.PaginationResult import dev.inmo.micro_utils.pagination.extractPagination -import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo -import dev.inmo.micro_utils.repos.ktor.common.idParameterName +import dev.inmo.micro_utils.repos.ktor.common.* +import dev.inmo.micro_utils.repos.ktor.common.containsRoute +import dev.inmo.micro_utils.repos.ktor.common.countRoute 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.reversedParameterName import io.ktor.http.* import io.ktor.server.application.call import io.ktor.server.response.respond -import io.ktor.server.response.responseType import io.ktor.server.routing.Route import io.ktor.server.routing.get import io.ktor.util.InternalAPI import io.ktor.util.reflect.typeInfo import kotlinx.serialization.* -import kotlinx.serialization.builtins.serializer @OptIn(InternalAPI::class) inline fun Route.configureReadStandardKeyValueRepoRoutes ( @@ -26,6 +25,9 @@ inline fun Route.configureReadStandardKeyValueRepoR noinline idDeserializer: suspend (String) -> Key, noinline valueDeserializer: suspend (String) -> Value ) { + val paginationWithValuesTypeInfo = typeInfo>() + val paginationWithKeysTypeInfo = typeInfo>() + get(getRoute) { val key = idDeserializer( call.getQueryParameterOrSendError(idParameterName) ?: return@get @@ -36,13 +38,14 @@ inline fun Route.configureReadStandardKeyValueRepoR } ?: call.respond(HttpStatusCode.NoContent) } - val paginationWithValuesTypeInfo = typeInfo>() get(valuesRoute) { val pagination = call.request.queryParameters.extractPagination val reversed = call.getQueryParameter(reversedParameterName) ?.toBoolean() ?: false - call.response.responseType = paginationWithValuesTypeInfo - call.response.pipeline.execute(call, originalRepo.values(pagination, reversed) as Any) + call.respond( + originalRepo.values(pagination, reversed), + paginationWithValuesTypeInfo + ) } get(keysRoute) { @@ -53,7 +56,8 @@ inline fun Route.configureReadStandardKeyValueRepoR } call.respond( - value ?.let { originalRepo.keys(value, pagination, reversed) } ?: originalRepo.keys(pagination, reversed) + value ?.let { originalRepo.keys(value, pagination, reversed) } ?: originalRepo.keys(pagination, reversed), + paginationWithKeysTypeInfo ) } @@ -62,9 +66,7 @@ inline fun Route.configureReadStandardKeyValueRepoR call.getQueryParameterOrSendError(idParameterName) ?: return@get ) - call.respond( - originalRepo.contains(key) - ) + call.respond(originalRepo.contains(key)) } get(countRoute) { diff --git a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/NewKtorStandartKeyValuesRepo.kt b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/NewKtorStandartKeyValuesRepo.kt new file mode 100644 index 00000000000..625ddc25529 --- /dev/null +++ b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/NewKtorStandartKeyValuesRepo.kt @@ -0,0 +1,47 @@ +package dev.inmo.micro_utils.repos.ktor.server.one_to_many + +import dev.inmo.micro_utils.ktor.common.* +import dev.inmo.micro_utils.repos.* +import io.ktor.http.* +import io.ktor.server.routing.Route +import kotlinx.serialization.* + +inline fun Route.configureStandardKeyValuesRepoRoutes ( + originalRepo: OneToManyKeyValueRepo, + noinline idDeserializer: suspend (String) -> Key, + noinline valueDeserializer: suspend (String) -> Value +) { + configureReadStandardKeyValuesRepoRoutes(originalRepo, idDeserializer, valueDeserializer) + configureWriteStandardKeyValuesRepoRoutes(originalRepo) +} + +inline fun Route.configureStandardKeyValuesRepoRoutes( + originalRepo: OneToManyKeyValueRepo, + idsSerializer: DeserializationStrategy, + valueSerializer: DeserializationStrategy, + serialFormat: StringFormat +) = configureStandardKeyValuesRepoRoutes( + originalRepo, + { + serialFormat.decodeFromString(idsSerializer, it.decodeURLQueryComponent()) + }, + { + serialFormat.decodeFromString(valueSerializer, it.decodeURLQueryComponent()) + } +) + +inline fun Route.configureStandardKeyValuesRepoRoutes( + originalRepo: OneToManyKeyValueRepo, + idsSerializer: DeserializationStrategy, + valueSerializer: DeserializationStrategy, + serialFormat: BinaryFormat +) = configureStandardKeyValuesRepoRoutes( + originalRepo, + { + serialFormat.decodeHex(idsSerializer, it) + }, + { + serialFormat.decodeHex(valueSerializer, it) + } +) + diff --git a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/NewKtorStandartReadKeyValuesRepo.kt b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/NewKtorStandartReadKeyValuesRepo.kt new file mode 100644 index 00000000000..c8f5c0b7b7c --- /dev/null +++ b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/NewKtorStandartReadKeyValuesRepo.kt @@ -0,0 +1,107 @@ +package dev.inmo.micro_utils.repos.ktor.server.one_to_many + +import dev.inmo.micro_utils.ktor.common.* +import dev.inmo.micro_utils.ktor.server.* +import dev.inmo.micro_utils.pagination.PaginationResult +import dev.inmo.micro_utils.pagination.extractPagination +import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo +import dev.inmo.micro_utils.repos.ktor.common.* +import dev.inmo.micro_utils.repos.ktor.common.containsRoute +import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* +import io.ktor.http.* +import io.ktor.server.application.call +import io.ktor.server.response.respond +import io.ktor.server.routing.Route +import io.ktor.server.routing.get +import io.ktor.util.InternalAPI +import io.ktor.util.reflect.typeInfo +import kotlinx.serialization.* + +@OptIn(InternalAPI::class) +inline fun Route.configureReadStandardKeyValuesRepoRoutes ( + originalRepo: ReadOneToManyKeyValueRepo, + noinline idDeserializer: suspend (String) -> Key, + noinline valueDeserializer: suspend (String) -> Value +) { + val paginationWithValuesTypeInfo = typeInfo>() + val paginationWithKeysTypeInfo = typeInfo>() + + get(getRoute) { + val key = idDeserializer( + call.getQueryParameterOrSendError(keyParameterName) ?: return@get + ) + val pagination = call.request.queryParameters.extractPagination + val reversed = call.getQueryParameter(reversedParameterName) ?.toBoolean() ?: false + + call.respond( + originalRepo.get(key, pagination, reversed), + paginationWithValuesTypeInfo + ) + } + + get(keysRoute) { + val pagination = call.request.queryParameters.extractPagination + val reversed = call.getQueryParameterOrSendError(reversedParameterName) ?.toBoolean() ?: false + val value = call.getQueryParameter(valueParameterName) ?.let { + valueDeserializer(it) + } + + call.respond( + value ?.let { originalRepo.keys(value, pagination, reversed) } ?: originalRepo.keys(pagination, reversed), + paginationWithKeysTypeInfo + ) + } + + get(containsRoute) { + val key = idDeserializer( + call.getQueryParameterOrSendError(keyParameterName) ?: return@get + ) + val value = call.getQueryParameter(valueParameterName) ?.let { + valueDeserializer(it) + } + + call.respond( + value ?.let { originalRepo.contains(key, value) } ?: originalRepo.contains(key) + ) + } + + get(dev.inmo.micro_utils.repos.ktor.common.countRoute) { + val id = call.getQueryParameter(keyParameterName) ?.let { + idDeserializer(it) + } + call.respond( + id ?.let { originalRepo.count(it) } ?: originalRepo.count() + ) + } +} + +inline fun Route.configureReadStandardKeyValuesRepoRoutes( + originalRepo: ReadOneToManyKeyValueRepo, + idsSerializer: DeserializationStrategy, + valueSerializer: DeserializationStrategy, + serialFormat: StringFormat +) = configureReadStandardKeyValuesRepoRoutes( + originalRepo, + { + serialFormat.decodeFromString(idsSerializer, it.decodeURLQueryComponent()) + }, + { + serialFormat.decodeFromString(valueSerializer, it.decodeURLQueryComponent()) + } +) + +inline fun Route.configureReadStandardKeyValuesRepoRoutes( + originalRepo: ReadOneToManyKeyValueRepo, + idsSerializer: DeserializationStrategy, + valueSerializer: DeserializationStrategy, + serialFormat: BinaryFormat +) = configureReadStandardKeyValuesRepoRoutes( + originalRepo, + { + serialFormat.decodeHex(idsSerializer, it) + }, + { + serialFormat.decodeHex(valueSerializer, it) + } +) + diff --git a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/NewKtorStandartWriteKeyValuesRepo.kt b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/NewKtorStandartWriteKeyValuesRepo.kt new file mode 100644 index 00000000000..a33e9062a72 --- /dev/null +++ b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/NewKtorStandartWriteKeyValuesRepo.kt @@ -0,0 +1,58 @@ +package dev.inmo.micro_utils.repos.ktor.server.one_to_many + +import dev.inmo.micro_utils.ktor.server.* +import dev.inmo.micro_utils.repos.WriteOneToManyKeyValueRepo +import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* +import io.ktor.http.HttpStatusCode +import io.ktor.server.application.call +import io.ktor.server.request.receive +import io.ktor.server.response.respond +import io.ktor.server.routing.Route +import io.ktor.server.routing.post +import io.ktor.util.reflect.typeInfo + +inline fun Route.configureWriteStandardKeyValuesRepoRoutes ( + originalRepo: WriteOneToManyKeyValueRepo +) { + includeWebsocketHandling( + onNewValueRoute, + originalRepo.onNewValue + ) + + includeWebsocketHandling( + onValueRemovedRoute, + originalRepo.onValueRemoved + ) + + includeWebsocketHandling( + onDataClearedRoute, + originalRepo.onDataCleared + ) + + val mapType = typeInfo>>() + + post(addRoute) { + originalRepo.add(call.receive(mapType)) + call.respond(HttpStatusCode.OK) + } + + post(setRoute) { + originalRepo.set(call.receive(mapType)) + call.respond(HttpStatusCode.OK) + } + + post(removeRoute) { + originalRepo.remove(call.receive(mapType)) + call.respond(HttpStatusCode.OK) + } + + post(clearRoute) { + originalRepo.clear(call.receive()) + call.respond(HttpStatusCode.OK) + } + + post(clearWithValueRoute) { + originalRepo.clearWithValue(call.receive()) + call.respond(HttpStatusCode.OK) + } +}