Merge branch 'master' into key_value_impl

This commit is contained in:
InsanusMokrassar 2020-09-01 20:57:42 +06:00
commit 33bdd83e97
10 changed files with 78 additions and 44 deletions

View File

@ -4,8 +4,7 @@ import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.request.get import io.ktor.client.request.get
import io.ktor.client.request.post import io.ktor.client.request.post
import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.*
import kotlinx.serialization.SerializationStrategy
typealias BodyPair<T> = Pair<SerializationStrategy<T>, T> typealias BodyPair<T> = Pair<SerializationStrategy<T>, T>
@ -18,6 +17,11 @@ suspend fun <ResultType> HttpClient.uniget(
standardKtorSerialFormat.decodeFromByteArray(resultDeserializer, it) standardKtorSerialFormat.decodeFromByteArray(resultDeserializer, it)
} }
fun <T> SerializationStrategy<T>.encodeUrlQueryValue(value: T) = standardKtorSerialFormat.encodeToHexString(
this,
value
)
suspend fun <BodyType, ResultType> HttpClient.unipost( suspend fun <BodyType, ResultType> HttpClient.unipost(
url: String, url: String,
bodyInfo: BodyPair<BodyType>, bodyInfo: BodyPair<BodyType>,

View File

@ -7,3 +7,17 @@ fun buildStandardUrl(
) = "$basePart/$subpart".includeQueryParams( ) = "$basePart/$subpart".includeQueryParams(
parameters parameters
) )
fun buildStandardUrl(
basePart: String,
subpart: String,
parameters: List<QueryParam>
) = "$basePart/$subpart".includeQueryParams(
parameters
)
fun buildStandardUrl(
basePart: String,
subpart: String,
vararg parameters: QueryParam
) = buildStandardUrl(basePart, subpart, parameters.toList())

View File

@ -1,6 +0,0 @@
package com.insanusmokrassar.postssystem.ktor
import kotlinx.serialization.*
fun <T> T.toHex(with: SerializationStrategy<T>) = standardKtorSerialFormat.encodeToHexString(with, this)
fun <T> String.fromHex(with: DeserializationStrategy<T>): T = standardKtorSerialFormat.decodeFromHexString(with, this)

View File

@ -12,6 +12,12 @@ val Pagination.asUrlQueryParts
"size" to size.toString() "size" to size.toString()
) )
val Pagination.asUrlQueryArrayParts
get() = arrayOf(
"page" to page.toString(),
"size" to size.toString()
)
val Map<String, String?>.extractPagination: Pagination val Map<String, String?>.extractPagination: Pagination
get() = SimplePagination( get() = SimplePagination(
get("page") ?.toIntOrNull() ?: 0, get("page") ?.toIntOrNull() ?: 0,

View File

@ -1,13 +1,22 @@
package com.insanusmokrassar.postssystem.ktor package com.insanusmokrassar.postssystem.ktor
typealias QueryParam = Pair<String, String?>
typealias QueryParams = Map<String, String?> typealias QueryParams = Map<String, String?>
val QueryParams.asUrlQuery: String val QueryParams.asUrlQuery: String
get() = keys.joinToString("&") { "${it}${get(it) ?.let { value -> "=$value" }}" } get() = keys.joinToString("&") { "${it}${get(it) ?.let { value -> "=$value" }}" }
val List<QueryParam>.asUrlQuery: String
get() = joinToString("&") { (key, value) -> "${key}${value ?.let { _ -> "=$value" }}" }
fun String.includeQueryParams( fun String.includeQueryParams(
queryParams: QueryParams queryParams: QueryParams
): String = "$this${if (contains("?")) "&" else "?"}${queryParams.asUrlQuery}" ): String = "$this${if (contains("?")) "&" else "?"}${queryParams.asUrlQuery}"
fun String.includeQueryParams(
queryParams: List<QueryParam>
): String = "$this${if (contains("?")) "&" else "?"}${queryParams.asUrlQuery}"
val String.parseUrlQuery: QueryParams val String.parseUrlQuery: QueryParams
get() = split("&").map { get() = split("&").map {
it.split("=").let { pair -> it.split("=").let { pair ->

View File

@ -1,14 +1,12 @@
package com.insanusmokrassar.postssystem.ktor.server package com.insanusmokrassar.postssystem.ktor.server
import com.insanusmokrassar.postssystem.ktor.fromHex
import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat
import io.ktor.application.ApplicationCall import io.ktor.application.ApplicationCall
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.response.respondBytes import io.ktor.response.respondBytes
import io.ktor.util.toByteArray import io.ktor.util.toByteArray
import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.*
import kotlinx.serialization.SerializationStrategy
suspend fun <T> ApplicationCall.unianswer( suspend fun <T> ApplicationCall.unianswer(
answerSerializer: SerializationStrategy<T>, answerSerializer: SerializationStrategy<T>,
@ -27,18 +25,6 @@ suspend fun <T> ApplicationCall.uniload(
request.receiveChannel().toByteArray() request.receiveChannel().toByteArray()
) )
fun <T> ApplicationCall.uniloadFromQuery(
parameterName: String,
deserializer: DeserializationStrategy<T>
): T? = getQueryParameter(parameterName) ?.fromHex(deserializer)
suspend fun <T> ApplicationCall.uniloadFromQueryOrSendError(
parameterName: String,
deserializer: DeserializationStrategy<T>
): T? = uniloadFromQuery(parameterName, deserializer) ?: null.also {
respond(HttpStatusCode.BadRequest, "Request query parameters must contains $parameterName")
}
suspend fun ApplicationCall.getParameterOrSendError( suspend fun ApplicationCall.getParameterOrSendError(
field: String field: String
) = parameters[field].also { ) = parameters[field].also {
@ -58,3 +44,22 @@ suspend fun ApplicationCall.getQueryParameterOrSendError(
respond(HttpStatusCode.BadRequest, "Request query parameters must contains $field") respond(HttpStatusCode.BadRequest, "Request query parameters must contains $field")
} }
} }
fun <T> ApplicationCall.decodeUrlQueryValue(
field: String,
deserializer: DeserializationStrategy<T>
) = getQueryParameter(field) ?.let {
standardKtorSerialFormat.decodeFromHexString(
deserializer,
it
)
}
suspend fun <T> ApplicationCall.decodeUrlQueryValueOrSendError(
field: String,
deserializer: DeserializationStrategy<T>
) = decodeUrlQueryValue(field, deserializer).also {
if (it == null) {
respond(HttpStatusCode.BadRequest, "Request query parameters must contains $field")
}
}

View File

@ -1,6 +1,7 @@
package com.insanusmokrassar.postssystem.utils.repos.ktor.client.crud package com.insanusmokrassar.postssystem.utils.repos.ktor.client.crud
import com.insanusmokrassar.postssystem.ktor.* import com.insanusmokrassar.postssystem.ktor.*
import com.insanusmokrassar.postssystem.ktor.client.encodeUrlQueryValue
import com.insanusmokrassar.postssystem.ktor.client.uniget import com.insanusmokrassar.postssystem.ktor.client.uniget
import com.insanusmokrassar.postssystem.utils.common.pagination.Pagination import com.insanusmokrassar.postssystem.utils.common.pagination.Pagination
import com.insanusmokrassar.postssystem.utils.common.pagination.PaginationResult import com.insanusmokrassar.postssystem.utils.common.pagination.PaginationResult
@ -29,7 +30,7 @@ class KtorReadStandardCrudRepo<ObjectType, IdType> (
baseUrl, baseUrl,
getByIdRouting, getByIdRouting,
mapOf( mapOf(
"id" to id.toHex(idsSerializer) "id" to idsSerializer.encodeUrlQueryValue(id)
) )
), ),
objectsSerializerNullable objectsSerializerNullable
@ -40,7 +41,7 @@ class KtorReadStandardCrudRepo<ObjectType, IdType> (
baseUrl, baseUrl,
containsRouting, containsRouting,
mapOf( mapOf(
"id" to id.toHex(idsSerializer) "id" to idsSerializer.encodeUrlQueryValue(id)
) )
), ),
Boolean.serializer() Boolean.serializer()

View File

@ -1,6 +1,7 @@
package com.insanusmokrassar.postssystem.utils.repos.ktor.client.one_to_many package com.insanusmokrassar.postssystem.utils.repos.ktor.client.one_to_many
import com.insanusmokrassar.postssystem.ktor.* import com.insanusmokrassar.postssystem.ktor.*
import com.insanusmokrassar.postssystem.ktor.client.encodeUrlQueryValue
import com.insanusmokrassar.postssystem.ktor.client.uniget import com.insanusmokrassar.postssystem.ktor.client.uniget
import com.insanusmokrassar.postssystem.utils.common.pagination.Pagination import com.insanusmokrassar.postssystem.utils.common.pagination.Pagination
import com.insanusmokrassar.postssystem.utils.common.pagination.PaginationResult import com.insanusmokrassar.postssystem.utils.common.pagination.PaginationResult
@ -24,8 +25,8 @@ class KtorOneToManyReadKeyValueRepo<Key, Value> (
baseUrl, baseUrl,
getRoute, getRoute,
mapOf( mapOf(
keyParameterName to k.toHex(keySerializer), keyParameterName to keySerializer.encodeUrlQueryValue(k),
reversedParameterName to reversed.toHex(Boolean.serializer()) reversedParameterName to Boolean.serializer().encodeUrlQueryValue(reversed)
) + pagination.asUrlQueryParts ) + pagination.asUrlQueryParts
), ),
paginationValueResultSerializer paginationValueResultSerializer
@ -36,7 +37,7 @@ class KtorOneToManyReadKeyValueRepo<Key, Value> (
baseUrl, baseUrl,
keysRoute, keysRoute,
mapOf( mapOf(
reversedParameterName to reversed.toHex(Boolean.serializer()) reversedParameterName to Boolean.serializer().encodeUrlQueryValue(reversed)
) + pagination.asUrlQueryParts ) + pagination.asUrlQueryParts
), ),
paginationKeyResultSerializer paginationKeyResultSerializer
@ -46,7 +47,7 @@ class KtorOneToManyReadKeyValueRepo<Key, Value> (
buildStandardUrl( buildStandardUrl(
baseUrl, baseUrl,
containsByKeyRoute, containsByKeyRoute,
mapOf(keyParameterName to k.toHex(keySerializer)) mapOf(keyParameterName to keySerializer.encodeUrlQueryValue(k))
), ),
Boolean.serializer() Boolean.serializer()
) )
@ -56,8 +57,8 @@ class KtorOneToManyReadKeyValueRepo<Key, Value> (
baseUrl, baseUrl,
containsByKeyValueRoute, containsByKeyValueRoute,
mapOf( mapOf(
keyParameterName to k.toHex(keySerializer), keyParameterName to keySerializer.encodeUrlQueryValue(k),
valueParameterName to v.toHex(valueSerializer), valueParameterName to valueSerializer.encodeUrlQueryValue(v),
) )
), ),
Boolean.serializer() Boolean.serializer()
@ -68,7 +69,7 @@ class KtorOneToManyReadKeyValueRepo<Key, Value> (
baseUrl, baseUrl,
countByKeyRoute, countByKeyRoute,
mapOf( mapOf(
keyParameterName to k.toHex(keySerializer) keyParameterName to keySerializer.encodeUrlQueryValue(k)
) )
), ),
Long.serializer() Long.serializer()

View File

@ -28,7 +28,7 @@ fun <ObjectType, IdType> Route.configureReadStandardCrudRepoRoutes(
} }
get(getByIdRouting) { get(getByIdRouting) {
val id = call.uniloadFromQueryOrSendError( val id = call.decodeUrlQueryValueOrSendError(
"id", "id",
idsSerializer idsSerializer
) ?: return@get ) ?: return@get
@ -40,7 +40,7 @@ fun <ObjectType, IdType> Route.configureReadStandardCrudRepoRoutes(
} }
get(containsRouting) { get(containsRouting) {
val id = call.uniloadFromQueryOrSendError( val id = call.decodeUrlQueryValueOrSendError(
"id", "id",
idsSerializer idsSerializer
) ?: return@get ) ?: return@get

View File

@ -22,11 +22,11 @@ fun <Key, Value> Route.configureOneToManyReadKeyValueRepoRoutes(
get(getRoute) { get(getRoute) {
val pagination = call.request.queryParameters.extractPagination val pagination = call.request.queryParameters.extractPagination
val key = call.uniloadFromQueryOrSendError( val key = call.decodeUrlQueryValueOrSendError(
keyParameterName, keyParameterName,
keySerializer keySerializer
) ?: return@get ) ?: return@get
val reversed = call.uniloadFromQuery( val reversed = call.decodeUrlQueryValue(
reversedParameterName, reversedParameterName,
Boolean.serializer() Boolean.serializer()
) ?: false ) ?: false
@ -39,7 +39,7 @@ fun <Key, Value> Route.configureOneToManyReadKeyValueRepoRoutes(
get(keysRoute) { get(keysRoute) {
val pagination = call.request.queryParameters.extractPagination val pagination = call.request.queryParameters.extractPagination
val reversed = call.uniloadFromQuery( val reversed = call.decodeUrlQueryValue(
reversedParameterName, reversedParameterName,
Boolean.serializer() Boolean.serializer()
) ?: false ) ?: false
@ -51,10 +51,10 @@ fun <Key, Value> Route.configureOneToManyReadKeyValueRepoRoutes(
} }
get(containsByKeyRoute) { get(containsByKeyRoute) {
val key = standardKtorSerialFormat.decodeFromHexString( val key = call.decodeUrlQueryValueOrSendError(
keySerializer, keyParameterName,
call.getQueryParameterOrSendError(keyParameterName) ?: return@get keySerializer
) ) ?: return@get
call.unianswer( call.unianswer(
Boolean.serializer(), Boolean.serializer(),
@ -63,11 +63,11 @@ fun <Key, Value> Route.configureOneToManyReadKeyValueRepoRoutes(
} }
get(containsByKeyValueRoute) { get(containsByKeyValueRoute) {
val key = call.uniloadFromQueryOrSendError( val key = call.decodeUrlQueryValueOrSendError(
keyParameterName, keyParameterName,
keySerializer keySerializer
) ?: return@get ) ?: return@get
val value = call.uniloadFromQueryOrSendError( val value = call.decodeUrlQueryValueOrSendError(
valueParameterName, valueParameterName,
valueSealizer valueSealizer
) ?: return@get ) ?: return@get
@ -79,7 +79,7 @@ fun <Key, Value> Route.configureOneToManyReadKeyValueRepoRoutes(
} }
get(countByKeyRoute) { get(countByKeyRoute) {
val key = call.uniloadFromQueryOrSendError( val key = call.decodeUrlQueryValueOrSendError(
keyParameterName, keyParameterName,
keySerializer keySerializer
) ?: return@get ) ?: return@get