mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-10-27 10:11:22 +00:00 
			
		
		
		
	complete improvements in repos ktor parts
This commit is contained in:
		| @@ -2,6 +2,12 @@ | ||||
|  | ||||
| ## 0.11.0 | ||||
|  | ||||
| * `Ktor` | ||||
|   *  | ||||
| * `Repos` | ||||
|   * `Ktor`: | ||||
|     * Fully rewritten work with all declared repositories | ||||
|  | ||||
| ## 0.10.8 | ||||
|  | ||||
| * `Common` | ||||
|   | ||||
| @@ -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()) | ||||
| } | ||||
| @@ -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 <T : Any> ApplicationCall.respond( | ||||
|     message: T, | ||||
|     typeInfo: TypeInfo | ||||
| ) { | ||||
|     response.responseType = typeInfo | ||||
|     response.pipeline.execute(this, message as Any) | ||||
| } | ||||
| @@ -104,6 +104,13 @@ interface OneToManyKeyValueRepo<Key, Value> : ReadOneToManyKeyValueRepo<Key, Val | ||||
| } | ||||
| typealias KeyValuesRepo<Key,Value> = OneToManyKeyValueRepo<Key, Value> | ||||
|  | ||||
| class DelegateBasedOneToManyKeyValueRepo<Key, Value>( | ||||
|     readDelegate: ReadOneToManyKeyValueRepo<Key, Value>, | ||||
|     writeDelegate: WriteOneToManyKeyValueRepo<Key, Value> | ||||
| ) : OneToManyKeyValueRepo<Key, Value>, | ||||
|     ReadOneToManyKeyValueRepo<Key, Value> by readDelegate, | ||||
|     WriteOneToManyKeyValueRepo<Key, Value> by writeDelegate | ||||
|  | ||||
| suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.remove( | ||||
|     keysAndValues: List<Pair<Key, List<Value>>> | ||||
| ) = remove(keysAndValues.toMap()) | ||||
|   | ||||
| @@ -80,6 +80,10 @@ class MapWriteOneToManyKeyValueRepo<Key, Value>( | ||||
|                     _onValueRemoved.emit(k to v) | ||||
|                 } | ||||
|             } | ||||
|             if (map[k] ?.isEmpty() == true) { | ||||
|                 map.remove(k) | ||||
|                 _onDataCleared.emit(k) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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<ObjectType, IdType, InputValue> ( | ||||
|     private val baseUrl: String, | ||||
| @@ -50,7 +46,7 @@ class KtorWriteStandardCrudRepoClient<ObjectType, IdType, InputValue> ( | ||||
|             buildStandardUrl(baseUrl, deleteByIdRouting) | ||||
|         ) { | ||||
|             deleteByIdSetup(ids) | ||||
|         }.status | ||||
|         }.throwOnUnsuccess { "Unable to delete $ids" } | ||||
|     } | ||||
|  | ||||
|     companion object { | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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<Key, Value>( | ||||
|     override suspend fun count(): Long = httpClient.get( | ||||
|         buildStandardUrl( | ||||
|             baseUrl, | ||||
|             countRouting | ||||
|             dev.inmo.micro_utils.repos.ktor.common.countRoute | ||||
|         ) | ||||
|     ) { | ||||
|         contentType(contentType) | ||||
|   | ||||
| @@ -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<Key, Value>( | ||||
|     private val baseUrl: String, | ||||
| @@ -35,7 +31,7 @@ class KtorWriteStandardKeyValueRepoClient<Key, Value>( | ||||
|             body = toUnset | ||||
|             bodyType = objectsListTypeInfo | ||||
|             contentType(contentType) | ||||
|         }.status | ||||
|         }.throwOnUnsuccess { "Unable to unset data with values $toUnset" } | ||||
|     } | ||||
|  | ||||
|     @OptIn(InternalAPI::class) | ||||
| @@ -46,7 +42,7 @@ class KtorWriteStandardKeyValueRepoClient<Key, Value>( | ||||
|             body = toUnset | ||||
|             bodyType = idsListTypeInfo | ||||
|             contentType(contentType) | ||||
|         }.status | ||||
|         }.throwOnUnsuccess { "Unable to unset $toUnset" } | ||||
|     } | ||||
|  | ||||
|     @OptIn(InternalAPI::class) | ||||
| @@ -57,7 +53,7 @@ class KtorWriteStandardKeyValueRepoClient<Key, Value>( | ||||
|             body = toSet | ||||
|             bodyType = idsToObjectsMapTypeInfo | ||||
|             contentType(contentType) | ||||
|         }.status | ||||
|         }.throwOnUnsuccess { "Unable to set $toSet" } | ||||
|     } | ||||
|  | ||||
|     companion object { | ||||
|   | ||||
| @@ -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<Key, Value>( | ||||
|     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<Key, Value> { | ||||
|     override suspend fun get( | ||||
|         k: Key, | ||||
|         pagination: Pagination, | ||||
|         reversed: Boolean | ||||
|     ): PaginationResult<Value> = 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<Key> = 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<Key> = 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 <reified Key, reified Value> KtorReadStandardKeyValuesRepoClient( | ||||
|     baseUrl: String, | ||||
|     httpClient: HttpClient, | ||||
|     contentType: ContentType, | ||||
|     noinline keySerializer: suspend (Key) -> String, | ||||
|     noinline valueSerializer: suspend (Value) -> String | ||||
| ) = KtorReadStandardKeyValuesRepoClient<Key, Value>( | ||||
|     baseUrl, | ||||
|     httpClient, | ||||
|     contentType, | ||||
|     typeInfo<PaginationResult<Value>>(), | ||||
|     typeInfo<PaginationResult<Key>>(), | ||||
|     keySerializer, | ||||
|     valueSerializer | ||||
| ) | ||||
|  | ||||
| inline fun <reified Key, reified Value> KtorReadStandardKeyValuesRepoClient( | ||||
|     baseUrl: String, | ||||
|     httpClient: HttpClient, | ||||
|     idsSerializer: KSerializer<Key>, | ||||
|     valueSerializer: KSerializer<Value>, | ||||
|     serialFormat: StringFormat, | ||||
|     contentType: ContentType, | ||||
| ) = KtorReadStandardKeyValuesRepoClient<Key, Value>( | ||||
|     baseUrl, | ||||
|     httpClient, | ||||
|     contentType, | ||||
|     { | ||||
|         serialFormat.encodeToString(idsSerializer, it).encodeURLQueryComponent() | ||||
|     } | ||||
| ) { | ||||
|     serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent() | ||||
| } | ||||
|  | ||||
| inline fun <reified Key, reified Value> KtorReadStandardKeyValuesRepoClient( | ||||
|     baseUrl: String, | ||||
|     httpClient: HttpClient, | ||||
|     idsSerializer: KSerializer<Key>, | ||||
|     valuesSerializer: KSerializer<Value>, | ||||
|     serialFormat: BinaryFormat, | ||||
|     contentType: ContentType, | ||||
| ) = KtorReadStandardKeyValuesRepoClient<Key, Value>( | ||||
|     baseUrl, | ||||
|     httpClient, | ||||
|     contentType, | ||||
|     { | ||||
|         serialFormat.encodeHex(idsSerializer, it) | ||||
|     } | ||||
| ) { | ||||
|     serialFormat.encodeHex(valuesSerializer, it) | ||||
| } | ||||
| @@ -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<Key, Value> ( | ||||
|     readDelegate: ReadOneToManyKeyValueRepo<Key, Value>, | ||||
|     writeDelegate: WriteOneToManyKeyValueRepo<Key, Value> | ||||
| ) : OneToManyKeyValueRepo<Key, Value> by DelegateBasedOneToManyKeyValueRepo( | ||||
|     readDelegate, | ||||
|     writeDelegate | ||||
| ) { | ||||
|     companion object { | ||||
|         inline operator fun <reified Key : Any, reified Value : Any> 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 <reified Key : Any, reified Value : Any> 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 <reified Key : Any, reified Value : Any> KtorStandardKeyValuesRepoClient( | ||||
|     baseUrl: String, | ||||
|     httpClient: HttpClient, | ||||
|     contentType: ContentType, | ||||
|     keySerializer: SerializationStrategy<Key>, | ||||
|     valueSerializer: SerializationStrategy<Value>, | ||||
|     serialFormat: StringFormat, | ||||
| ) = KtorStandardKeyValuesRepoClient<Key, Value>( | ||||
|     baseUrl, | ||||
|     httpClient, | ||||
|     contentType, | ||||
|     { | ||||
|         serialFormat.encodeToString(keySerializer, it).encodeURLQueryComponent() | ||||
|     } | ||||
| ) { | ||||
|     serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent() | ||||
| } | ||||
|  | ||||
| inline fun <reified Key : Any, reified Value : Any> KtorStandardKeyValuesRepoClient( | ||||
|     baseUrl: String, | ||||
|     httpClient: HttpClient, | ||||
|     contentType: ContentType, | ||||
|     keySerializer: SerializationStrategy<Key>, | ||||
|     valueSerializer: SerializationStrategy<Value>, | ||||
|     serialFormat: BinaryFormat, | ||||
| ) = KtorStandardKeyValuesRepoClient<Key, Value>( | ||||
|     baseUrl, | ||||
|     httpClient, | ||||
|     contentType, | ||||
|     { | ||||
|         serialFormat.encodeHex(keySerializer, it) | ||||
|     } | ||||
| ) { | ||||
|     serialFormat.encodeHex(valueSerializer, it) | ||||
| } | ||||
| @@ -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<Key : Any, Value : Any>( | ||||
|     private val baseUrl: String, | ||||
|     private val httpClient: HttpClient, | ||||
|     private val contentType: ContentType, | ||||
|     override val onNewValue: Flow<Pair<Key, Value>>, | ||||
|     override val onValueRemoved: Flow<Pair<Key, Value>>, | ||||
|     override val onDataCleared: Flow<Key>, | ||||
|     private val keyTypeInfo: TypeInfo, | ||||
|     private val valueTypeInfo: TypeInfo, | ||||
|     private val keyToValuesMapTypeInfo: TypeInfo | ||||
| ) : WriteOneToManyKeyValueRepo<Key, Value> { | ||||
|  | ||||
|     @OptIn(InternalAPI::class) | ||||
|     override suspend fun add(toAdd: Map<Key, List<Value>>) { | ||||
|         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<Key, List<Value>>) { | ||||
|         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<Key, List<Value>>) { | ||||
|         httpClient.post( | ||||
|             buildStandardUrl(baseUrl, setRoute) | ||||
|         ) { | ||||
|             body = toSet | ||||
|             bodyType = keyToValuesMapTypeInfo | ||||
|             contentType(contentType) | ||||
|         }.throwOnUnsuccess { "Unable to set data $toSet" } | ||||
|     } | ||||
|  | ||||
|     companion object { | ||||
|         inline operator fun <reified Key : Any, reified Value : Any> invoke( | ||||
|             baseUrl: String, | ||||
|             httpClient: HttpClient, | ||||
|             contentType: ContentType | ||||
|         ) = KtorWriteStandardKeyValuesRepoClient<Key, Value>( | ||||
|             baseUrl, | ||||
|             httpClient, | ||||
|             contentType, | ||||
|             httpClient.createStandardWebsocketFlow( | ||||
|                 buildStandardUrl(baseUrl, onNewValueRoute), | ||||
|             ), | ||||
|             httpClient.createStandardWebsocketFlow( | ||||
|                 buildStandardUrl(baseUrl, onValueRemovedRoute), | ||||
|             ), | ||||
|             httpClient.createStandardWebsocketFlow( | ||||
|                 buildStandardUrl(baseUrl, onDataClearedRoute), | ||||
|             ), | ||||
|             typeInfo<Key>(), | ||||
|             typeInfo<Value>(), | ||||
|             typeInfo<Map<Key, List<Value>>>() | ||||
|         ) | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,3 @@ | ||||
| package dev.inmo.micro_utils.repos.ktor.common | ||||
|  | ||||
| const val containsRoute = "contains" | ||||
| @@ -0,0 +1,3 @@ | ||||
| package dev.inmo.micro_utils.repos.ktor.common | ||||
|  | ||||
| const val countRoute = "count" | ||||
| @@ -0,0 +1,3 @@ | ||||
| package dev.inmo.micro_utils.repos.ktor.common | ||||
|  | ||||
| const val countRouting = "count" | ||||
| @@ -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" | ||||
|   | ||||
| @@ -3,8 +3,8 @@ 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" | ||||
|   | ||||
| @@ -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" | ||||
|   | ||||
| @@ -21,7 +21,7 @@ class CRUDTests { | ||||
|     @OptIn(ExperimentalCoroutinesApi::class) | ||||
|     @Test | ||||
|     fun testCRUDFunctions() { | ||||
|         runTest() { | ||||
|         runTest { | ||||
|             val map = mutableMapOf<Int, ComplexData>() | ||||
|             val repo = MapCRUDRepo<ComplexData, Int, SimpleData>( | ||||
|                 map, | ||||
|   | ||||
| @@ -22,8 +22,8 @@ import kotlin.test.* | ||||
| class KVTests { | ||||
|     @OptIn(ExperimentalCoroutinesApi::class) | ||||
|     @Test | ||||
|     fun testCRUDFunctions() { | ||||
|         runTest() { | ||||
|     fun testKVFunctions() { | ||||
|         runTest { | ||||
|             val map = mutableMapOf<Int, ComplexData>() | ||||
|             val repo = MapKeyValueRepo<Int, ComplexData>(map) | ||||
|             val server = io.ktor.server.engine.embeddedServer( | ||||
|   | ||||
							
								
								
									
										141
									
								
								repos/ktor/common/src/jvmTest/kotlin/KVsTests.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								repos/ktor/common/src/jvmTest/kotlin/KVsTests.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -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<Int, MutableList<ComplexData>>() | ||||
|             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() | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 <reified Key, reified Value> Route.configureReadStandardKeyValueRepoRoutes ( | ||||
| @@ -26,6 +25,9 @@ inline fun <reified Key, reified Value> Route.configureReadStandardKeyValueRepoR | ||||
|     noinline idDeserializer: suspend (String) -> Key, | ||||
|     noinline valueDeserializer: suspend (String) -> Value | ||||
| ) { | ||||
|     val paginationWithValuesTypeInfo = typeInfo<PaginationResult<Value>>() | ||||
|     val paginationWithKeysTypeInfo = typeInfo<PaginationResult<Key>>() | ||||
|  | ||||
|     get(getRoute) { | ||||
|         val key = idDeserializer( | ||||
|             call.getQueryParameterOrSendError(idParameterName) ?: return@get | ||||
| @@ -36,13 +38,14 @@ inline fun <reified Key, reified Value> Route.configureReadStandardKeyValueRepoR | ||||
|         } ?: call.respond(HttpStatusCode.NoContent) | ||||
|     } | ||||
|  | ||||
|     val paginationWithValuesTypeInfo = typeInfo<PaginationResult<Value>>() | ||||
|     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 <reified Key, reified Value> 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 <reified Key, reified Value> Route.configureReadStandardKeyValueRepoR | ||||
|             call.getQueryParameterOrSendError(idParameterName) ?: return@get | ||||
|         ) | ||||
|  | ||||
|         call.respond( | ||||
|             originalRepo.contains(key) | ||||
|         ) | ||||
|         call.respond(originalRepo.contains(key)) | ||||
|     } | ||||
|  | ||||
|     get(countRoute) { | ||||
|   | ||||
| @@ -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 <reified Key : Any, reified Value : Any> Route.configureStandardKeyValuesRepoRoutes ( | ||||
|     originalRepo: OneToManyKeyValueRepo<Key, Value>, | ||||
|     noinline idDeserializer: suspend (String) -> Key, | ||||
|     noinline valueDeserializer: suspend (String) -> Value | ||||
| ) { | ||||
|     configureReadStandardKeyValuesRepoRoutes(originalRepo, idDeserializer, valueDeserializer) | ||||
|     configureWriteStandardKeyValuesRepoRoutes(originalRepo) | ||||
| } | ||||
|  | ||||
| inline fun <reified Key : Any, reified Value : Any> Route.configureStandardKeyValuesRepoRoutes( | ||||
|     originalRepo: OneToManyKeyValueRepo<Key, Value>, | ||||
|     idsSerializer: DeserializationStrategy<Key>, | ||||
|     valueSerializer: DeserializationStrategy<Value>, | ||||
|     serialFormat: StringFormat | ||||
| ) = configureStandardKeyValuesRepoRoutes( | ||||
|     originalRepo, | ||||
|     { | ||||
|         serialFormat.decodeFromString(idsSerializer, it.decodeURLQueryComponent()) | ||||
|     }, | ||||
|     { | ||||
|         serialFormat.decodeFromString(valueSerializer, it.decodeURLQueryComponent()) | ||||
|     } | ||||
| ) | ||||
|  | ||||
| inline fun <reified Key : Any, reified Value : Any> Route.configureStandardKeyValuesRepoRoutes( | ||||
|     originalRepo: OneToManyKeyValueRepo<Key, Value>, | ||||
|     idsSerializer: DeserializationStrategy<Key>, | ||||
|     valueSerializer: DeserializationStrategy<Value>, | ||||
|     serialFormat: BinaryFormat | ||||
| ) = configureStandardKeyValuesRepoRoutes( | ||||
|     originalRepo, | ||||
|     { | ||||
|         serialFormat.decodeHex(idsSerializer, it) | ||||
|     }, | ||||
|     { | ||||
|         serialFormat.decodeHex(valueSerializer, it) | ||||
|     } | ||||
| ) | ||||
|  | ||||
| @@ -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 <reified Key, reified Value> Route.configureReadStandardKeyValuesRepoRoutes ( | ||||
|     originalRepo: ReadOneToManyKeyValueRepo<Key, Value>, | ||||
|     noinline idDeserializer: suspend (String) -> Key, | ||||
|     noinline valueDeserializer: suspend (String) -> Value | ||||
| ) { | ||||
|     val paginationWithValuesTypeInfo = typeInfo<PaginationResult<Value>>() | ||||
|     val paginationWithKeysTypeInfo = typeInfo<PaginationResult<Key>>() | ||||
|  | ||||
|     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 <reified Key, reified Value> Route.configureReadStandardKeyValuesRepoRoutes( | ||||
|     originalRepo: ReadOneToManyKeyValueRepo<Key, Value>, | ||||
|     idsSerializer: DeserializationStrategy<Key>, | ||||
|     valueSerializer: DeserializationStrategy<Value>, | ||||
|     serialFormat: StringFormat | ||||
| ) = configureReadStandardKeyValuesRepoRoutes( | ||||
|     originalRepo, | ||||
|     { | ||||
|         serialFormat.decodeFromString(idsSerializer, it.decodeURLQueryComponent()) | ||||
|     }, | ||||
|     { | ||||
|         serialFormat.decodeFromString(valueSerializer, it.decodeURLQueryComponent()) | ||||
|     } | ||||
| ) | ||||
|  | ||||
| inline fun <reified Key, reified Value> Route.configureReadStandardKeyValuesRepoRoutes( | ||||
|     originalRepo: ReadOneToManyKeyValueRepo<Key, Value>, | ||||
|     idsSerializer: DeserializationStrategy<Key>, | ||||
|     valueSerializer: DeserializationStrategy<Value>, | ||||
|     serialFormat: BinaryFormat | ||||
| ) = configureReadStandardKeyValuesRepoRoutes( | ||||
|     originalRepo, | ||||
|     { | ||||
|         serialFormat.decodeHex(idsSerializer, it) | ||||
|     }, | ||||
|     { | ||||
|         serialFormat.decodeHex(valueSerializer, it) | ||||
|     } | ||||
| ) | ||||
|  | ||||
| @@ -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 <reified Key : Any, reified Value : Any> Route.configureWriteStandardKeyValuesRepoRoutes ( | ||||
|     originalRepo: WriteOneToManyKeyValueRepo<Key, Value> | ||||
| ) { | ||||
|     includeWebsocketHandling( | ||||
|         onNewValueRoute, | ||||
|         originalRepo.onNewValue | ||||
|     ) | ||||
|  | ||||
|     includeWebsocketHandling( | ||||
|         onValueRemovedRoute, | ||||
|         originalRepo.onValueRemoved | ||||
|     ) | ||||
|  | ||||
|     includeWebsocketHandling( | ||||
|         onDataClearedRoute, | ||||
|         originalRepo.onDataCleared | ||||
|     ) | ||||
|  | ||||
|     val mapType = typeInfo<Map<Key, List<Value>>>() | ||||
|  | ||||
|     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) | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user