mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-11-04 06:00: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