mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2024-12-02 15:00:08 +00:00
Compare commits
2 Commits
8eed435302
...
eaa143f7d7
Author | SHA1 | Date | |
---|---|---|---|
eaa143f7d7 | |||
bcb0e42fa2 |
@ -37,17 +37,24 @@ kt-serialization-cbor = { module = "org.jetbrains.kotlinx:kotlinx-serialization-
|
|||||||
|
|
||||||
kt-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kt-coroutines" }
|
kt-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kt-coroutines" }
|
||||||
kt-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kt-coroutines" }
|
kt-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kt-coroutines" }
|
||||||
|
kt-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kt-coroutines" }
|
||||||
|
|
||||||
|
|
||||||
ktor-io = { module = "io.ktor:ktor-io", version.ref = "ktor" }
|
ktor-io = { module = "io.ktor:ktor-io", version.ref = "ktor" }
|
||||||
|
ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
|
||||||
ktor-client = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
|
ktor-client = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
|
||||||
|
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
|
||||||
ktor-client-java = { module = "io.ktor:ktor-client-java", version.ref = "ktor" }
|
ktor-client-java = { module = "io.ktor:ktor-client-java", version.ref = "ktor" }
|
||||||
|
ktor-client-websockets = { module = "io.ktor:ktor-client-websockets", version.ref = "ktor" }
|
||||||
|
ktor-client-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" }
|
||||||
|
ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
|
||||||
ktor-server = { module = "io.ktor:ktor-server", version.ref = "ktor" }
|
ktor-server = { module = "io.ktor:ktor-server", version.ref = "ktor" }
|
||||||
ktor-server-cio = { module = "io.ktor:ktor-server-cio", version.ref = "ktor" }
|
ktor-server-cio = { module = "io.ktor:ktor-server-cio", version.ref = "ktor" }
|
||||||
ktor-server-host-common = { module = "io.ktor:ktor-server-host-common", version.ref = "ktor" }
|
ktor-server-host-common = { module = "io.ktor:ktor-server-host-common", version.ref = "ktor" }
|
||||||
ktor-websockets = { module = "io.ktor:ktor-websockets", version.ref = "ktor" }
|
ktor-websockets = { module = "io.ktor:ktor-websockets", version.ref = "ktor" }
|
||||||
ktor-server-websockets = { module = "io.ktor:ktor-server-websockets", version.ref = "ktor" }
|
ktor-server-websockets = { module = "io.ktor:ktor-server-websockets", version.ref = "ktor" }
|
||||||
ktor-server-statusPages = { module = "io.ktor:ktor-server-status-pages", version.ref = "ktor" }
|
ktor-server-statusPages = { module = "io.ktor:ktor-server-status-pages", version.ref = "ktor" }
|
||||||
|
ktor-server-content-negotiation = { module = "io.ktor:ktor-server-content-negotiation", version.ref = "ktor" }
|
||||||
|
|
||||||
|
|
||||||
klock = { module = "com.soywiz.korlibs.klock:klock", version.ref = "klock" }
|
klock = { module = "com.soywiz.korlibs.klock:klock", version.ref = "klock" }
|
||||||
|
@ -9,6 +9,7 @@ import io.ktor.client.plugins.websocket.*
|
|||||||
import io.ktor.client.request.HttpRequestBuilder
|
import io.ktor.client.request.HttpRequestBuilder
|
||||||
import io.ktor.websocket.Frame
|
import io.ktor.websocket.Frame
|
||||||
import io.ktor.websocket.readBytes
|
import io.ktor.websocket.readBytes
|
||||||
|
import io.ktor.websocket.serialization.sendSerializedBase
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.channelFlow
|
import kotlinx.coroutines.flow.channelFlow
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
@ -18,9 +19,9 @@ import kotlinx.serialization.DeserializationStrategy
|
|||||||
* @param checkReconnection This lambda will be called when it is required to reconnect to websocket to establish
|
* @param checkReconnection This lambda will be called when it is required to reconnect to websocket to establish
|
||||||
* connection. Must return true in case if must be reconnected. By default always reconnecting
|
* connection. Must return true in case if must be reconnected. By default always reconnecting
|
||||||
*/
|
*/
|
||||||
inline fun <T> HttpClient.createStandardWebsocketFlow(
|
inline fun <reified T> HttpClient.createStandardWebsocketFlow(
|
||||||
url: String,
|
url: String,
|
||||||
crossinline checkReconnection: suspend (Throwable?) -> Boolean = { true },
|
noinline checkReconnection: suspend (Throwable?) -> Boolean = { true },
|
||||||
noinline requestBuilder: HttpRequestBuilder.() -> Unit = {}
|
noinline requestBuilder: HttpRequestBuilder.() -> Unit = {}
|
||||||
): Flow<T> {
|
): Flow<T> {
|
||||||
pluginOrNull(WebSockets) ?: error("Plugin $WebSockets must be installed for using createStandardWebsocketFlow")
|
pluginOrNull(WebSockets) ?: error("Plugin $WebSockets must be installed for using createStandardWebsocketFlow")
|
||||||
|
@ -43,3 +43,10 @@ suspend fun <ObjectType, IdType, InputValueType> WriteStandardCRUDRepo<ObjectTyp
|
|||||||
interface StandardCRUDRepo<ObjectType, IdType, InputValueType> : ReadStandardCRUDRepo<ObjectType, IdType>,
|
interface StandardCRUDRepo<ObjectType, IdType, InputValueType> : ReadStandardCRUDRepo<ObjectType, IdType>,
|
||||||
WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>
|
WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>
|
||||||
typealias CRUDRepo<ObjectType, IdType, InputValueType> = StandardCRUDRepo<ObjectType, IdType, InputValueType>
|
typealias CRUDRepo<ObjectType, IdType, InputValueType> = StandardCRUDRepo<ObjectType, IdType, InputValueType>
|
||||||
|
|
||||||
|
class DelegateBasedStandardCRUDRepo<ObjectType, IdType, InputValueType>(
|
||||||
|
readDelegate: ReadStandardCRUDRepo<ObjectType, IdType>,
|
||||||
|
writeDelegate: WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>
|
||||||
|
) : StandardCRUDRepo<ObjectType, IdType, InputValueType>,
|
||||||
|
ReadStandardCRUDRepo<ObjectType, IdType> by readDelegate,
|
||||||
|
WriteStandardCRUDRepo<ObjectType, IdType, InputValueType> by writeDelegate
|
||||||
|
@ -50,3 +50,10 @@ interface StandardKeyValueRepo<Key, Value> : ReadStandardKeyValueRepo<Key, Value
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
typealias KeyValueRepo<Key,Value> = StandardKeyValueRepo<Key, Value>
|
typealias KeyValueRepo<Key,Value> = StandardKeyValueRepo<Key, Value>
|
||||||
|
|
||||||
|
class DelegateBasedStandardKeyValueRepo<Key, Value>(
|
||||||
|
readDelegate: ReadStandardKeyValueRepo<Key, Value>,
|
||||||
|
writeDelegate: WriteStandardKeyValueRepo<Key, Value>
|
||||||
|
) : StandardKeyValueRepo<Key, Value>,
|
||||||
|
ReadStandardKeyValueRepo<Key, Value> by readDelegate,
|
||||||
|
WriteStandardKeyValueRepo<Key, Value> by writeDelegate
|
||||||
|
@ -74,19 +74,24 @@ abstract class MapCRUDRepo<ObjectType, IdType, InputValueType>(
|
|||||||
|
|
||||||
fun <ObjectType, IdType, InputValueType> MapCRUDRepo(
|
fun <ObjectType, IdType, InputValueType> MapCRUDRepo(
|
||||||
map: MutableMap<IdType, ObjectType>,
|
map: MutableMap<IdType, ObjectType>,
|
||||||
updateCallback: suspend (newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType,
|
updateCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType,
|
||||||
createCallback: suspend (newValue: InputValueType) -> Pair<IdType, ObjectType>
|
createCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType) -> Pair<IdType, ObjectType>
|
||||||
) = object : MapCRUDRepo<ObjectType, IdType, InputValueType>(map) {
|
) = object : MapCRUDRepo<ObjectType, IdType, InputValueType>(map) {
|
||||||
override suspend fun updateObject(
|
override suspend fun updateObject(
|
||||||
newValue: InputValueType,
|
newValue: InputValueType,
|
||||||
id: IdType,
|
id: IdType,
|
||||||
old: ObjectType
|
old: ObjectType
|
||||||
): ObjectType = updateCallback(newValue, id, old)
|
): ObjectType = map.updateCallback(newValue, id, old)
|
||||||
|
|
||||||
override suspend fun createObject(newValue: InputValueType): Pair<IdType, ObjectType> = createCallback(newValue)
|
override suspend fun createObject(newValue: InputValueType): Pair<IdType, ObjectType> = map.createCallback(newValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <ObjectType, IdType, InputValueType> MapCRUDRepo(
|
||||||
|
updateCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType,
|
||||||
|
createCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType) -> Pair<IdType, ObjectType>
|
||||||
|
) = MapCRUDRepo(mutableMapOf(), updateCallback, createCallback)
|
||||||
|
|
||||||
fun <ObjectType, IdType, InputValueType> MutableMap<IdType, ObjectType>.asCrudRepo(
|
fun <ObjectType, IdType, InputValueType> MutableMap<IdType, ObjectType>.asCrudRepo(
|
||||||
updateCallback: suspend (newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType,
|
updateCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType,
|
||||||
createCallback: suspend (newValue: InputValueType) -> Pair<IdType, ObjectType>
|
createCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType) -> Pair<IdType, ObjectType>
|
||||||
) = MapCRUDRepo(this, updateCallback, createCallback)
|
) = MapCRUDRepo(this, updateCallback, createCallback)
|
||||||
|
@ -78,11 +78,11 @@ class WriteMapKeyValueRepo<Key, Value>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun unsetWithValues(toUnset: List<Value>) {
|
override suspend fun unsetWithValues(toUnset: List<Value>) {
|
||||||
map.forEach {
|
map.mapNotNull { (k, v) ->
|
||||||
if (it.value in toUnset) {
|
k.takeIf { v in toUnset }
|
||||||
map.remove(it.key)
|
}.forEach {
|
||||||
_onValueRemoved.emit(it.key)
|
map.remove(it)
|
||||||
}
|
_onValueRemoved.emit(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import dev.inmo.micro_utils.ktor.common.*
|
|||||||
import dev.inmo.micro_utils.pagination.*
|
import dev.inmo.micro_utils.pagination.*
|
||||||
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
|
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.idParameterName
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
import kotlinx.serialization.builtins.serializer
|
import kotlinx.serialization.builtins.serializer
|
||||||
@ -39,9 +40,7 @@ class KtorReadStandardCrudRepo<ObjectType, IdType> (
|
|||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
getByIdRouting,
|
getByIdRouting,
|
||||||
mapOf(
|
idParameterName to unifiedRequester.encodeUrlQueryValue(idsSerializer, id)
|
||||||
"id" to unifiedRequester.encodeUrlQueryValue(idsSerializer, id)
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
objectsSerializerNullable
|
objectsSerializerNullable
|
||||||
)
|
)
|
||||||
@ -50,9 +49,7 @@ class KtorReadStandardCrudRepo<ObjectType, IdType> (
|
|||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
containsRouting,
|
containsRouting,
|
||||||
mapOf(
|
idParameterName to unifiedRequester.encodeUrlQueryValue(idsSerializer, id)
|
||||||
"id" to unifiedRequester.encodeUrlQueryValue(idsSerializer, id)
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
Boolean.serializer()
|
Boolean.serializer()
|
||||||
)
|
)
|
||||||
|
@ -4,10 +4,11 @@ import dev.inmo.micro_utils.ktor.common.*
|
|||||||
import dev.inmo.micro_utils.pagination.*
|
import dev.inmo.micro_utils.pagination.*
|
||||||
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
|
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.idParameterName
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.client.call.body
|
import io.ktor.client.call.body
|
||||||
import io.ktor.client.request.get
|
import io.ktor.client.request.get
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.*
|
||||||
import io.ktor.util.reflect.TypeInfo
|
import io.ktor.util.reflect.TypeInfo
|
||||||
import io.ktor.util.reflect.typeInfo
|
import io.ktor.util.reflect.typeInfo
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.*
|
||||||
@ -16,48 +17,59 @@ class KtorReadStandardCrudRepoClient<ObjectType, IdType> (
|
|||||||
private val baseUrl: String,
|
private val baseUrl: String,
|
||||||
private val httpClient: HttpClient,
|
private val httpClient: HttpClient,
|
||||||
private val objectType: TypeInfo,
|
private val objectType: TypeInfo,
|
||||||
|
private val contentType: ContentType,
|
||||||
private val idSerializer: suspend (IdType) -> String
|
private val idSerializer: suspend (IdType) -> String
|
||||||
) : ReadStandardCRUDRepo<ObjectType, IdType> {
|
) : ReadStandardCRUDRepo<ObjectType, IdType> {
|
||||||
override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> = httpClient.get(
|
override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> = httpClient.get(
|
||||||
buildStandardUrl(baseUrl, getByPaginationRouting, pagination.asUrlQueryParts)
|
buildStandardUrl(baseUrl, getByPaginationRouting, pagination.asUrlQueryParts)
|
||||||
).body()
|
) {
|
||||||
|
contentType(contentType)
|
||||||
|
}.body()
|
||||||
|
|
||||||
override suspend fun getById(id: IdType): ObjectType? = httpClient.get(
|
override suspend fun getById(id: IdType): ObjectType? = httpClient.get(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
getByIdRouting,
|
getByIdRouting,
|
||||||
mapOf(
|
mapOf(
|
||||||
"id" to idSerializer(id)
|
idParameterName to idSerializer(id)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
).takeIf { it.status != HttpStatusCode.NoContent } ?.body<ObjectType>(objectType)
|
) {
|
||||||
|
contentType(contentType)
|
||||||
|
}.takeIf { it.status != HttpStatusCode.NoContent } ?.body<ObjectType>(objectType)
|
||||||
|
|
||||||
override suspend fun contains(id: IdType): Boolean = httpClient.get(
|
override suspend fun contains(id: IdType): Boolean = httpClient.get(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
containsRouting,
|
containsRouting,
|
||||||
mapOf(
|
mapOf(
|
||||||
"id" to idSerializer(id)
|
idParameterName to idSerializer(id)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
).body()
|
) {
|
||||||
|
contentType(contentType)
|
||||||
|
}.body()
|
||||||
|
|
||||||
override suspend fun count(): Long = httpClient.get(
|
override suspend fun count(): Long = httpClient.get(
|
||||||
buildStandardUrl(
|
buildStandardUrl(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
countRouting
|
countRouting
|
||||||
)
|
)
|
||||||
).body()
|
) {
|
||||||
|
contentType(contentType)
|
||||||
|
}.body()
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified ObjectType, IdType> KtorReadStandardCrudRepoClient(
|
inline fun <reified ObjectType, IdType> KtorReadStandardCrudRepoClient(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
|
contentType: ContentType,
|
||||||
noinline idSerializer: suspend (IdType) -> String
|
noinline idSerializer: suspend (IdType) -> String
|
||||||
) = KtorReadStandardCrudRepoClient<ObjectType, IdType>(
|
) = KtorReadStandardCrudRepoClient<ObjectType, IdType>(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
httpClient,
|
httpClient,
|
||||||
typeInfo<ObjectType>(),
|
typeInfo<ObjectType>(),
|
||||||
|
contentType,
|
||||||
idSerializer
|
idSerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -65,8 +77,9 @@ inline fun <reified ObjectType, IdType> KtorReadStandardCrudRepoClient(
|
|||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
idsSerializer: KSerializer<IdType>,
|
idsSerializer: KSerializer<IdType>,
|
||||||
serialFormat: StringFormat
|
serialFormat: StringFormat,
|
||||||
) = KtorReadStandardCrudRepoClient<ObjectType, IdType>(baseUrl, httpClient) {
|
contentType: ContentType,
|
||||||
|
) = KtorReadStandardCrudRepoClient<ObjectType, IdType>(baseUrl, httpClient, contentType) {
|
||||||
serialFormat.encodeToString(idsSerializer, it)
|
serialFormat.encodeToString(idsSerializer, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +87,8 @@ inline fun <reified ObjectType, IdType> KtorReadStandardCrudRepoClient(
|
|||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
idsSerializer: KSerializer<IdType>,
|
idsSerializer: KSerializer<IdType>,
|
||||||
serialFormat: BinaryFormat
|
serialFormat: BinaryFormat,
|
||||||
) = KtorReadStandardCrudRepoClient<ObjectType, IdType>(baseUrl, httpClient) {
|
contentType: ContentType,
|
||||||
|
) = KtorReadStandardCrudRepoClient<ObjectType, IdType>(baseUrl, httpClient, contentType) {
|
||||||
serialFormat.encodeHex(idsSerializer, it)
|
serialFormat.encodeHex(idsSerializer, it)
|
||||||
}
|
}
|
||||||
|
@ -3,91 +3,120 @@ package dev.inmo.micro_utils.repos.ktor.client.crud
|
|||||||
import dev.inmo.micro_utils.ktor.common.*
|
import dev.inmo.micro_utils.ktor.common.*
|
||||||
import dev.inmo.micro_utils.repos.*
|
import dev.inmo.micro_utils.repos.*
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
|
import io.ktor.client.utils.EmptyContent.contentType
|
||||||
|
import io.ktor.http.ContentType
|
||||||
import io.ktor.util.reflect.TypeInfo
|
import io.ktor.util.reflect.TypeInfo
|
||||||
import io.ktor.util.reflect.typeInfo
|
import io.ktor.util.reflect.typeInfo
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.*
|
||||||
|
|
||||||
class KtorStandardCrudRepoClient<ObjectType, IdType, InputValue> (
|
class KtorStandardCrudRepoClient<ObjectType, IdType, InputValue> (
|
||||||
|
readDelegate: ReadStandardCRUDRepo<ObjectType, IdType>,
|
||||||
|
writeDelegate: WriteStandardCRUDRepo<ObjectType, IdType, InputValue>
|
||||||
|
) : StandardCRUDRepo<ObjectType, IdType, InputValue> by DelegateBasedStandardCRUDRepo(
|
||||||
|
readDelegate,
|
||||||
|
writeDelegate
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
inline operator fun <reified ObjectType, reified IdType, reified InputValue> invoke(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
objectTypeInfo: TypeInfo,
|
objectTypeInfo: TypeInfo,
|
||||||
idSerializer: suspend (IdType) -> String
|
contentType: ContentType,
|
||||||
) : StandardCRUDRepo<ObjectType, IdType, InputValue>,
|
noinline idSerializer: suspend (IdType) -> String
|
||||||
ReadStandardCRUDRepo<ObjectType, IdType> by KtorReadStandardCrudRepoClient(
|
) = KtorStandardCrudRepoClient(
|
||||||
|
KtorReadStandardCrudRepoClient(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
httpClient,
|
httpClient,
|
||||||
objectTypeInfo,
|
objectTypeInfo,
|
||||||
|
contentType,
|
||||||
idSerializer
|
idSerializer
|
||||||
),
|
),
|
||||||
WriteStandardCRUDRepo<ObjectType, IdType, InputValue> by KtorWriteStandardCrudRepoClient(
|
KtorWriteStandardCrudRepoClient<ObjectType, IdType, InputValue>(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
httpClient
|
httpClient,
|
||||||
) {
|
contentType
|
||||||
constructor(
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
inline operator fun <reified ObjectType, reified IdType, reified InputValue> invoke(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
subpart: String,
|
subpart: String,
|
||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
objectTypeInfo: TypeInfo,
|
objectTypeInfo: TypeInfo,
|
||||||
idSerializer: suspend (IdType) -> String
|
contentType: ContentType,
|
||||||
) : this(
|
noinline idSerializer: suspend (IdType) -> String
|
||||||
buildStandardUrl(baseUrl, subpart), httpClient, objectTypeInfo, idSerializer
|
) = KtorStandardCrudRepoClient<ObjectType, IdType, InputValue>(
|
||||||
|
buildStandardUrl(baseUrl, subpart),
|
||||||
|
httpClient,
|
||||||
|
objectTypeInfo,
|
||||||
|
contentType,
|
||||||
|
idSerializer
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline fun <reified ObjectType, IdType, InputValue> KtorStandardCrudRepoClient(
|
inline fun <reified ObjectType, reified IdType, reified InputValue> KtorStandardCrudRepoClient(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
|
contentType: ContentType,
|
||||||
noinline idSerializer: suspend (IdType) -> String
|
noinline idSerializer: suspend (IdType) -> String
|
||||||
) = KtorStandardCrudRepoClient<ObjectType, IdType, InputValue>(
|
) = KtorStandardCrudRepoClient<ObjectType, IdType, InputValue>(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
httpClient,
|
httpClient,
|
||||||
typeInfo<ObjectType>(),
|
typeInfo<ObjectType>(),
|
||||||
|
contentType,
|
||||||
idSerializer
|
idSerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
inline fun <reified ObjectType, IdType, InputValue> KtorStandardCrudRepoClient(
|
inline fun <reified ObjectType, reified IdType, reified InputValue> KtorStandardCrudRepoClient(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
idsSerializer: KSerializer<IdType>,
|
idsSerializer: KSerializer<IdType>,
|
||||||
serialFormat: StringFormat
|
serialFormat: StringFormat,
|
||||||
) = KtorStandardCrudRepoClient<ObjectType, IdType, InputValue>(baseUrl, httpClient) {
|
contentType: ContentType,
|
||||||
|
) = KtorStandardCrudRepoClient<ObjectType, IdType, InputValue>(baseUrl, httpClient, contentType) {
|
||||||
serialFormat.encodeToString(idsSerializer, it)
|
serialFormat.encodeToString(idsSerializer, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified ObjectType, IdType, InputValue> KtorStandardCrudRepoClient(
|
inline fun <reified ObjectType, reified IdType, reified InputValue> KtorStandardCrudRepoClient(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
idsSerializer: KSerializer<IdType>,
|
idsSerializer: KSerializer<IdType>,
|
||||||
serialFormat: BinaryFormat
|
serialFormat: BinaryFormat,
|
||||||
) = KtorStandardCrudRepoClient<ObjectType, IdType, InputValue>(baseUrl, httpClient) {
|
contentType: ContentType,
|
||||||
|
) = KtorStandardCrudRepoClient<ObjectType, IdType, InputValue>(baseUrl, httpClient, contentType) {
|
||||||
serialFormat.encodeHex(idsSerializer, it)
|
serialFormat.encodeHex(idsSerializer, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline fun <reified ObjectType, IdType, InputValue> KtorStandardCrudRepoClient(
|
inline fun <reified ObjectType, reified IdType, reified InputValue> KtorStandardCrudRepoClient(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
subpart: String,
|
subpart: String,
|
||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
|
contentType: ContentType,
|
||||||
noinline idSerializer: suspend (IdType) -> String
|
noinline idSerializer: suspend (IdType) -> String
|
||||||
) = KtorStandardCrudRepoClient<ObjectType, IdType, InputValue>(
|
) = KtorStandardCrudRepoClient<ObjectType, IdType, InputValue>(
|
||||||
buildStandardUrl(baseUrl, subpart),
|
buildStandardUrl(baseUrl, subpart),
|
||||||
httpClient,
|
httpClient,
|
||||||
|
contentType,
|
||||||
idSerializer
|
idSerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
inline fun <reified ObjectType, IdType, InputValue> KtorStandardCrudRepoClient(
|
inline fun <reified ObjectType, reified IdType, reified InputValue> KtorStandardCrudRepoClient(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
subpart: String,
|
subpart: String,
|
||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
idsSerializer: KSerializer<IdType>,
|
idsSerializer: KSerializer<IdType>,
|
||||||
serialFormat: StringFormat
|
serialFormat: StringFormat,
|
||||||
) = KtorStandardCrudRepoClient<ObjectType, IdType, InputValue>(buildStandardUrl(baseUrl, subpart), httpClient, idsSerializer, serialFormat)
|
contentType: ContentType,
|
||||||
|
) = KtorStandardCrudRepoClient<ObjectType, IdType, InputValue>(buildStandardUrl(baseUrl, subpart), httpClient, idsSerializer, serialFormat, contentType)
|
||||||
|
|
||||||
inline fun <reified ObjectType, IdType, InputValue> KtorStandardCrudRepoClient(
|
inline fun <reified ObjectType, reified IdType, reified InputValue> KtorStandardCrudRepoClient(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
subpart: String,
|
subpart: String,
|
||||||
httpClient: HttpClient,
|
httpClient: HttpClient,
|
||||||
idsSerializer: KSerializer<IdType>,
|
idsSerializer: KSerializer<IdType>,
|
||||||
serialFormat: BinaryFormat
|
serialFormat: BinaryFormat,
|
||||||
) = KtorStandardCrudRepoClient<ObjectType, IdType, InputValue>(buildStandardUrl(baseUrl, subpart), httpClient, idsSerializer, serialFormat)
|
contentType: ContentType,
|
||||||
|
) = KtorStandardCrudRepoClient<ObjectType, IdType, InputValue>(buildStandardUrl(baseUrl, subpart), httpClient, idsSerializer, serialFormat, contentType)
|
||||||
|
@ -8,6 +8,9 @@ import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
|||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.client.call.body
|
import io.ktor.client.call.body
|
||||||
import io.ktor.client.request.*
|
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 io.ktor.util.reflect.typeInfo
|
import io.ktor.util.reflect.typeInfo
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
@ -16,36 +19,71 @@ import kotlinx.serialization.builtins.*
|
|||||||
|
|
||||||
class KtorWriteStandardCrudRepoClient<ObjectType, IdType, InputValue> (
|
class KtorWriteStandardCrudRepoClient<ObjectType, IdType, InputValue> (
|
||||||
private val baseUrl: String,
|
private val baseUrl: String,
|
||||||
private val httpClient: HttpClient
|
private val httpClient: HttpClient,
|
||||||
|
override val newObjectsFlow: Flow<ObjectType>,
|
||||||
|
override val updatedObjectsFlow: Flow<ObjectType>,
|
||||||
|
override val deletedObjectsIdsFlow: Flow<IdType>,
|
||||||
|
private val createSetup: suspend HttpRequestBuilder.(List<InputValue>) -> Unit,
|
||||||
|
private val updateSetup: suspend HttpRequestBuilder.(List<UpdatedValuePair<IdType, InputValue>>) -> Unit,
|
||||||
|
private val deleteByIdSetup: suspend HttpRequestBuilder.(List<IdType>) -> Unit,
|
||||||
|
private val createBodyGetter: suspend HttpResponse.() -> List<ObjectType>,
|
||||||
|
private val updateBodyGetter: suspend HttpResponse.() -> List<ObjectType>
|
||||||
) : WriteStandardCRUDRepo<ObjectType, IdType, InputValue> {
|
) : WriteStandardCRUDRepo<ObjectType, IdType, InputValue> {
|
||||||
|
override suspend fun create(values: List<InputValue>): List<ObjectType> = httpClient.post(
|
||||||
|
buildStandardUrl(baseUrl, createRouting)
|
||||||
|
) {
|
||||||
|
createSetup(values)
|
||||||
|
}.createBodyGetter()
|
||||||
|
|
||||||
override val newObjectsFlow: Flow<ObjectType> = httpClient.createStandardWebsocketFlow(
|
override suspend fun update(
|
||||||
buildStandardUrl(baseUrl, newObjectsFlowRouting),
|
values: List<UpdatedValuePair<IdType, InputValue>>
|
||||||
)
|
): List<ObjectType> = httpClient.post(
|
||||||
override val updatedObjectsFlow: Flow<ObjectType> = httpClient.createStandardWebsocketFlow(
|
buildStandardUrl(baseUrl, updateManyRouting)
|
||||||
buildStandardUrl(baseUrl, updatedObjectsFlowRouting)
|
) {
|
||||||
)
|
updateSetup(values)
|
||||||
override val deletedObjectsIdsFlow: Flow<IdType> = httpClient.createStandardWebsocketFlow(
|
}.updateBodyGetter()
|
||||||
buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
override suspend fun create(values: List<InputValue>): List<ObjectType> = httpClient.post {
|
|
||||||
url(buildStandardUrl(baseUrl, createRouting))
|
|
||||||
setBody(values)
|
|
||||||
}.body()
|
|
||||||
|
|
||||||
override suspend fun update(values: List<UpdatedValuePair<IdType, InputValue>>): List<ObjectType> = httpClient.post {
|
|
||||||
url(buildStandardUrl(baseUrl, updateManyRouting))
|
|
||||||
setBody(values)
|
|
||||||
}.body()
|
|
||||||
|
|
||||||
override suspend fun update(id: IdType, value: InputValue): ObjectType? = update(listOf(id to value)).firstOrNull()
|
override suspend fun update(id: IdType, value: InputValue): ObjectType? = update(listOf(id to value)).firstOrNull()
|
||||||
|
|
||||||
override suspend fun deleteById(ids: List<IdType>) {
|
override suspend fun deleteById(ids: List<IdType>) {
|
||||||
httpClient.post {
|
httpClient.post(
|
||||||
url(buildStandardUrl(baseUrl, deleteByIdRouting))
|
buildStandardUrl(baseUrl, deleteByIdRouting)
|
||||||
setBody(ids)
|
) {
|
||||||
}
|
deleteByIdSetup(ids)
|
||||||
|
}.status
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
inline operator fun <reified ObjectType, reified IdType, reified InputValue> invoke(
|
||||||
|
baseUrl: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
contentType: ContentType
|
||||||
|
) = KtorWriteStandardCrudRepoClient<ObjectType, IdType, InputValue>(
|
||||||
|
baseUrl,
|
||||||
|
httpClient,
|
||||||
|
httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, newObjectsFlowRouting),
|
||||||
|
),
|
||||||
|
httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, updatedObjectsFlowRouting),
|
||||||
|
),
|
||||||
|
httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting),
|
||||||
|
),
|
||||||
|
{
|
||||||
|
contentType(contentType)
|
||||||
|
setBody(it)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
contentType(contentType)
|
||||||
|
setBody(it)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
contentType(contentType)
|
||||||
|
setBody(it)
|
||||||
|
},
|
||||||
|
{ body() },
|
||||||
|
{ body() }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,144 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.ktor.client.key_value
|
||||||
|
|
||||||
|
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.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
|
||||||
|
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 KtorReadStandardKeyValueRepoClient<Key, Value>(
|
||||||
|
private val baseUrl: String,
|
||||||
|
private val httpClient: HttpClient,
|
||||||
|
private val contentType: ContentType,
|
||||||
|
private val objectType: TypeInfo,
|
||||||
|
private val paginationResultObjectsTypeInfo: TypeInfo,
|
||||||
|
private val paginationResultIdsTypeInfo: TypeInfo,
|
||||||
|
private val idSerializer: suspend (Key) -> String,
|
||||||
|
private val valueSerializer: suspend (Value) -> String
|
||||||
|
) : ReadStandardKeyValueRepo<Key, Value> {
|
||||||
|
override suspend fun get(k: Key): Value? = httpClient.get(
|
||||||
|
buildStandardUrl(
|
||||||
|
baseUrl,
|
||||||
|
getRoute,
|
||||||
|
mapOf(
|
||||||
|
idParameterName to idSerializer(k)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
contentType(contentType)
|
||||||
|
}.takeIf { it.status != HttpStatusCode.NoContent } ?.body<Value>(objectType)
|
||||||
|
|
||||||
|
override suspend fun contains(key: Key): Boolean = httpClient.get(
|
||||||
|
buildStandardUrl(
|
||||||
|
baseUrl,
|
||||||
|
containsRoute,
|
||||||
|
idParameterName to idSerializer(key)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
contentType(contentType)
|
||||||
|
}.body()
|
||||||
|
|
||||||
|
override suspend fun values(
|
||||||
|
pagination: Pagination,
|
||||||
|
reversed: Boolean
|
||||||
|
): PaginationResult<Value> = httpClient.get(
|
||||||
|
buildStandardUrl(baseUrl, valuesRoute, pagination.asUrlQueryParts + (reversedParameterName to reversed.toString()))
|
||||||
|
) {
|
||||||
|
contentType(contentType)
|
||||||
|
}.body(paginationResultObjectsTypeInfo)
|
||||||
|
|
||||||
|
override suspend fun keys(
|
||||||
|
pagination: Pagination,
|
||||||
|
reversed: Boolean
|
||||||
|
): PaginationResult<Key> = httpClient.get(
|
||||||
|
buildStandardUrl(baseUrl, keysRoute, pagination.asUrlQueryParts + (reversedParameterName to reversed.toString()))
|
||||||
|
) {
|
||||||
|
contentType(contentType)
|
||||||
|
}.body(paginationResultIdsTypeInfo)
|
||||||
|
|
||||||
|
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(paginationResultIdsTypeInfo)
|
||||||
|
|
||||||
|
override suspend fun count(): Long = httpClient.get(
|
||||||
|
buildStandardUrl(
|
||||||
|
baseUrl,
|
||||||
|
countRouting
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
contentType(contentType)
|
||||||
|
}.body()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified Key, reified Value> KtorReadStandardKeyValueRepoClient(
|
||||||
|
baseUrl: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
contentType: ContentType,
|
||||||
|
noinline idSerializer: suspend (Key) -> String,
|
||||||
|
noinline valueSerializer: suspend (Value) -> String
|
||||||
|
) = KtorReadStandardKeyValueRepoClient<Key, Value>(
|
||||||
|
baseUrl,
|
||||||
|
httpClient,
|
||||||
|
contentType,
|
||||||
|
typeInfo<Value>(),
|
||||||
|
typeInfo<PaginationResult<Value>>(),
|
||||||
|
typeInfo<PaginationResult<Key>>(),
|
||||||
|
idSerializer,
|
||||||
|
valueSerializer
|
||||||
|
)
|
||||||
|
|
||||||
|
inline fun <reified Key, reified Value> KtorReadStandardKeyValueRepoClient(
|
||||||
|
baseUrl: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
idsSerializer: KSerializer<Key>,
|
||||||
|
valueSerializer: KSerializer<Value>,
|
||||||
|
serialFormat: StringFormat,
|
||||||
|
contentType: ContentType,
|
||||||
|
) = KtorReadStandardKeyValueRepoClient<Key, Value>(
|
||||||
|
baseUrl,
|
||||||
|
httpClient,
|
||||||
|
contentType,
|
||||||
|
{
|
||||||
|
serialFormat.encodeToString(idsSerializer, it).encodeURLQueryComponent()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified Key, reified Value> KtorReadStandardKeyValueRepoClient(
|
||||||
|
baseUrl: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
idsSerializer: KSerializer<Key>,
|
||||||
|
valuesSerializer: KSerializer<Value>,
|
||||||
|
serialFormat: BinaryFormat,
|
||||||
|
contentType: ContentType,
|
||||||
|
) = KtorReadStandardKeyValueRepoClient<Key, Value>(
|
||||||
|
baseUrl,
|
||||||
|
httpClient,
|
||||||
|
contentType,
|
||||||
|
{
|
||||||
|
serialFormat.encodeHex(idsSerializer, it)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
serialFormat.encodeHex(valuesSerializer, it)
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.ktor.client.key_value
|
||||||
|
|
||||||
|
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 KtorStandardKeyValueRepoClient<Key, Value> (
|
||||||
|
readDelegate: ReadStandardKeyValueRepo<Key, Value>,
|
||||||
|
writeDelegate: WriteStandardKeyValueRepo<Key, Value>
|
||||||
|
) : StandardKeyValueRepo<Key, Value> by DelegateBasedStandardKeyValueRepo(
|
||||||
|
readDelegate,
|
||||||
|
writeDelegate
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
inline operator fun <reified Key, reified Value> invoke(
|
||||||
|
baseUrl: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
contentType: ContentType,
|
||||||
|
noinline idSerializer: suspend (Key) -> String,
|
||||||
|
noinline valueSerializer: suspend (Value) -> String
|
||||||
|
) = KtorStandardKeyValueRepoClient(
|
||||||
|
KtorReadStandardKeyValueRepoClient(
|
||||||
|
baseUrl, httpClient, contentType, idSerializer, valueSerializer
|
||||||
|
),
|
||||||
|
KtorWriteStandardKeyValueRepoClient(
|
||||||
|
baseUrl,
|
||||||
|
httpClient,
|
||||||
|
contentType
|
||||||
|
)
|
||||||
|
)
|
||||||
|
inline operator fun <reified Key, reified Value> invoke(
|
||||||
|
baseUrl: String,
|
||||||
|
subpart: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
contentType: ContentType,
|
||||||
|
noinline idSerializer: suspend (Key) -> String,
|
||||||
|
noinline valueSerializer: suspend (Value) -> String
|
||||||
|
) = KtorStandardKeyValueRepoClient(
|
||||||
|
buildStandardUrl(baseUrl, subpart),
|
||||||
|
httpClient,
|
||||||
|
contentType,
|
||||||
|
idSerializer,
|
||||||
|
valueSerializer
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified Key, reified Value> KtorStandardKeyValueRepoClient(
|
||||||
|
baseUrl: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
contentType: ContentType,
|
||||||
|
idSerializer: SerializationStrategy<Key>,
|
||||||
|
valueSerializer: SerializationStrategy<Value>,
|
||||||
|
serialFormat: StringFormat,
|
||||||
|
) = KtorStandardKeyValueRepoClient<Key, Value>(
|
||||||
|
baseUrl,
|
||||||
|
httpClient,
|
||||||
|
contentType,
|
||||||
|
{
|
||||||
|
serialFormat.encodeToString(idSerializer, it).encodeURLQueryComponent()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified Key, reified Value> KtorStandardKeyValueRepoClient(
|
||||||
|
baseUrl: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
contentType: ContentType,
|
||||||
|
idSerializer: SerializationStrategy<Key>,
|
||||||
|
valueSerializer: SerializationStrategy<Value>,
|
||||||
|
serialFormat: BinaryFormat,
|
||||||
|
) = KtorStandardKeyValueRepoClient<Key, Value>(
|
||||||
|
baseUrl,
|
||||||
|
httpClient,
|
||||||
|
contentType,
|
||||||
|
{
|
||||||
|
serialFormat.encodeHex(idSerializer, it)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
serialFormat.encodeHex(valueSerializer, it)
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.ktor.client.key_value
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.ktor.client.createStandardWebsocketFlow
|
||||||
|
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,
|
||||||
|
private val httpClient: HttpClient,
|
||||||
|
private val contentType: ContentType,
|
||||||
|
override val onNewValue: Flow<Pair<Key, Value>>,
|
||||||
|
override val onValueRemoved: Flow<Key>,
|
||||||
|
private val idsListTypeInfo: TypeInfo,
|
||||||
|
private val objectsListTypeInfo: TypeInfo,
|
||||||
|
private val idsToObjectsMapTypeInfo: TypeInfo
|
||||||
|
) : WriteStandardKeyValueRepo<Key, Value> {
|
||||||
|
@OptIn(InternalAPI::class)
|
||||||
|
override suspend fun unsetWithValues(toUnset: List<Value>) {
|
||||||
|
httpClient.post(
|
||||||
|
buildStandardUrl(baseUrl, unsetWithValuesRoute)
|
||||||
|
) {
|
||||||
|
body = toUnset
|
||||||
|
bodyType = objectsListTypeInfo
|
||||||
|
contentType(contentType)
|
||||||
|
}.status
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(InternalAPI::class)
|
||||||
|
override suspend fun unset(toUnset: List<Key>) {
|
||||||
|
httpClient.post(
|
||||||
|
buildStandardUrl(baseUrl, unsetRoute)
|
||||||
|
) {
|
||||||
|
body = toUnset
|
||||||
|
bodyType = idsListTypeInfo
|
||||||
|
contentType(contentType)
|
||||||
|
}.status
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(InternalAPI::class)
|
||||||
|
override suspend fun set(toSet: Map<Key, Value>) {
|
||||||
|
httpClient.post(
|
||||||
|
buildStandardUrl(baseUrl, setRoute)
|
||||||
|
) {
|
||||||
|
body = toSet
|
||||||
|
bodyType = idsToObjectsMapTypeInfo
|
||||||
|
contentType(contentType)
|
||||||
|
}.status
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
inline operator fun <reified Key, reified Value> invoke(
|
||||||
|
baseUrl: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
contentType: ContentType
|
||||||
|
) = KtorWriteStandardKeyValueRepoClient<Key, Value>(
|
||||||
|
baseUrl,
|
||||||
|
httpClient,
|
||||||
|
contentType,
|
||||||
|
httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onNewValueRoute),
|
||||||
|
),
|
||||||
|
httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, onValueRemovedRoute),
|
||||||
|
),
|
||||||
|
typeInfo<List<Key>>(),
|
||||||
|
typeInfo<List<Value>>(),
|
||||||
|
typeInfo<Map<Key, Value>>()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -13,5 +13,22 @@ kotlin {
|
|||||||
api internalProject("micro_utils.repos.common")
|
api internalProject("micro_utils.repos.common")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
jvmTest {
|
||||||
|
dependencies {
|
||||||
|
implementation internalProject("micro_utils.repos.common")
|
||||||
|
implementation internalProject("micro_utils.repos.ktor.client")
|
||||||
|
implementation internalProject("micro_utils.repos.ktor.server")
|
||||||
|
implementation internalProject("micro_utils.repos.inmemory")
|
||||||
|
implementation libs.kt.coroutines.test
|
||||||
|
|
||||||
|
implementation libs.ktor.server.cio
|
||||||
|
implementation libs.ktor.client.cio
|
||||||
|
implementation libs.ktor.server.content.negotiation
|
||||||
|
implementation libs.ktor.serialization.kotlinx.json
|
||||||
|
implementation libs.ktor.client.content.negotiation
|
||||||
|
implementation libs.ktor.client.logging
|
||||||
|
implementation libs.ktor.client.websockets
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package dev.inmo.micro_utils.repos.ktor.common
|
package dev.inmo.micro_utils.repos.ktor.common
|
||||||
|
|
||||||
|
const val idParameterName = "id"
|
||||||
const val keyParameterName = "key"
|
const val keyParameterName = "key"
|
||||||
const val valueParameterName = "value"
|
const val valueParameterName = "value"
|
||||||
const val reversedParameterName = "reversed"
|
const val reversedParameterName = "reversed"
|
89
repos/ktor/common/src/jvmTest/kotlin/CRUDTests.kt
Normal file
89
repos/ktor/common/src/jvmTest/kotlin/CRUDTests.kt
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import dev.inmo.micro_utils.repos.*
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.client.crud.KtorStandardCrudRepoClient
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.server.crud.configureStandardCrudRepoRoutes
|
||||||
|
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.json.Json
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class CRUDTests {
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@Test
|
||||||
|
fun testCRUDFunctions() {
|
||||||
|
runTest() {
|
||||||
|
val map = mutableMapOf<Int, ComplexData>()
|
||||||
|
val repo = MapCRUDRepo<ComplexData, Int, SimpleData>(
|
||||||
|
map,
|
||||||
|
{ newValue, id, oldValue ->
|
||||||
|
oldValue.copy(title = newValue.title)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
size to ComplexData(size, title = it.title)
|
||||||
|
}
|
||||||
|
val server = io.ktor.server.engine.embeddedServer(
|
||||||
|
CIO,
|
||||||
|
23456,
|
||||||
|
"127.0.0.1"
|
||||||
|
) {
|
||||||
|
install(ContentNegotiation) {
|
||||||
|
json()
|
||||||
|
}
|
||||||
|
install(WebSockets) {
|
||||||
|
contentConverter = KotlinxWebsocketSerializationConverter(Json)
|
||||||
|
}
|
||||||
|
routing {
|
||||||
|
configureStandardCrudRepoRoutes(
|
||||||
|
repo
|
||||||
|
) {
|
||||||
|
it.toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.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 = KtorStandardCrudRepoClient<ComplexData, Int, SimpleData>(
|
||||||
|
"http://127.0.0.1:23456",
|
||||||
|
client,
|
||||||
|
ContentType.Application.Json
|
||||||
|
) {
|
||||||
|
it.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
val created = crudClient.create(SimpleData("Example")).single()
|
||||||
|
assertEquals(map.size, 1)
|
||||||
|
assertEquals(map.size.toLong(), crudClient.count())
|
||||||
|
assertEquals(1, crudClient.count())
|
||||||
|
assertEquals(map.getValue(map.keys.first()), created)
|
||||||
|
|
||||||
|
val updated = crudClient.update(created.id, SimpleData("Example2"))
|
||||||
|
assertEquals(map.size, 1)
|
||||||
|
assertEquals(map.size.toLong(), crudClient.count())
|
||||||
|
assertEquals(1, crudClient.count())
|
||||||
|
assertEquals(map.getValue(map.keys.first()), updated)
|
||||||
|
|
||||||
|
crudClient.deleteById(created.id)
|
||||||
|
assertEquals(map.size, 0)
|
||||||
|
assertEquals(map.size.toLong(), crudClient.count())
|
||||||
|
assertEquals(0, crudClient.count())
|
||||||
|
server.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
repos/ktor/common/src/jvmTest/kotlin/ComplexData.kt
Normal file
10
repos/ktor/common/src/jvmTest/kotlin/ComplexData.kt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import com.benasher44.uuid.uuid4
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ComplexData(
|
||||||
|
val id: Int,
|
||||||
|
val simple: SimpleData = SimpleData(),
|
||||||
|
val simples: List<SimpleData> = (0 until 100).map { SimpleData(("$it")) },
|
||||||
|
val title: String = uuid4().toString()
|
||||||
|
)
|
139
repos/ktor/common/src/jvmTest/kotlin/KVTests.kt
Normal file
139
repos/ktor/common/src/jvmTest/kotlin/KVTests.kt
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
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.server.key_value.configureStandardKeyValueRepoRoutes
|
||||||
|
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 KVTests {
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@Test
|
||||||
|
fun testCRUDFunctions() {
|
||||||
|
runTest() {
|
||||||
|
val map = mutableMapOf<Int, ComplexData>()
|
||||||
|
val repo = MapKeyValueRepo<Int, ComplexData>(map)
|
||||||
|
val server = io.ktor.server.engine.embeddedServer(
|
||||||
|
CIO,
|
||||||
|
23456,
|
||||||
|
"127.0.0.1"
|
||||||
|
) {
|
||||||
|
install(ContentNegotiation) {
|
||||||
|
json()
|
||||||
|
}
|
||||||
|
install(WebSockets) {
|
||||||
|
contentConverter = KotlinxWebsocketSerializationConverter(Json)
|
||||||
|
}
|
||||||
|
routing {
|
||||||
|
configureStandardKeyValueRepoRoutes(
|
||||||
|
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 = KtorStandardKeyValueRepoClient<Int, ComplexData>(
|
||||||
|
"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 dataInOneKey
|
||||||
|
) + (0 until repeatCount).map {
|
||||||
|
(it + 2) to dataInMultipleKeys
|
||||||
|
}
|
||||||
|
|
||||||
|
dataList.forEachIndexed { i, (id, data) ->
|
||||||
|
crudClient.set(id, data)
|
||||||
|
assertEquals(map.size, i + 1)
|
||||||
|
assertEquals(map.size.toLong(), crudClient.count())
|
||||||
|
assertEquals(i + 1L, crudClient.count())
|
||||||
|
dataList.take(i + 1).forEach { (id, data) ->
|
||||||
|
assertEquals(data, map[id])
|
||||||
|
assertEquals(data, crudClient.get(id))
|
||||||
|
assertEquals(map[id], crudClient.get(id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dataList.forEach { (id, data) ->
|
||||||
|
assertTrue(crudClient.contains(id))
|
||||||
|
assertEquals(data, crudClient.get(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
dataList.mapNotNull { if (it.second == dataInMultipleKeys) it.first else null },
|
||||||
|
getAllWithNextPaging(firstPageWithOneElementPagination) {
|
||||||
|
crudClient.keys(dataInMultipleKeys, it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
dataList.mapNotNull { if (it.second == 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.second },
|
||||||
|
getAllWithNextPaging(firstPageWithOneElementPagination) {
|
||||||
|
crudClient.values(it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(dataList.size.toLong(), crudClient.count())
|
||||||
|
|
||||||
|
crudClient.unsetWithValues(dataInMultipleKeys)
|
||||||
|
assertEquals(
|
||||||
|
dataList.filter { it.second == dataInOneKey }.size.toLong(),
|
||||||
|
crudClient.count()
|
||||||
|
)
|
||||||
|
|
||||||
|
crudClient.unset(dataList.first { it.second == dataInOneKey }.first)
|
||||||
|
assertEquals(
|
||||||
|
0,
|
||||||
|
crudClient.count()
|
||||||
|
)
|
||||||
|
|
||||||
|
server.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
repos/ktor/common/src/jvmTest/kotlin/SimpleData.kt
Normal file
7
repos/ktor/common/src/jvmTest/kotlin/SimpleData.kt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import com.benasher44.uuid.uuid4
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SimpleData(
|
||||||
|
val title: String = uuid4().toString()
|
||||||
|
)
|
@ -5,6 +5,7 @@ import dev.inmo.micro_utils.ktor.server.*
|
|||||||
import dev.inmo.micro_utils.pagination.extractPagination
|
import dev.inmo.micro_utils.pagination.extractPagination
|
||||||
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
|
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
|
||||||
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.idParameterName
|
||||||
import io.ktor.http.ContentType
|
import io.ktor.http.ContentType
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.application.call
|
import io.ktor.server.application.call
|
||||||
@ -25,7 +26,7 @@ inline fun <reified ObjectType, reified IdType> Route.configureReadStandardCrudR
|
|||||||
|
|
||||||
get(getByIdRouting) {
|
get(getByIdRouting) {
|
||||||
val id = idDeserializer(
|
val id = idDeserializer(
|
||||||
call.getQueryParameterOrSendError("id") ?: return@get
|
call.getQueryParameterOrSendError(idParameterName) ?: return@get
|
||||||
)
|
)
|
||||||
|
|
||||||
val result = originalRepo.getById(id)
|
val result = originalRepo.getById(id)
|
||||||
@ -39,7 +40,7 @@ inline fun <reified ObjectType, reified IdType> Route.configureReadStandardCrudR
|
|||||||
|
|
||||||
get(containsRouting) {
|
get(containsRouting) {
|
||||||
val id = idDeserializer(
|
val id = idDeserializer(
|
||||||
call.getQueryParameterOrSendError("id") ?: return@get
|
call.getQueryParameterOrSendError(idParameterName) ?: return@get
|
||||||
)
|
)
|
||||||
|
|
||||||
call.respond(
|
call.respond(
|
||||||
|
@ -26,11 +26,7 @@ inline fun <reified ObjectType : Any, reified IdType : Any, reified InputValue :
|
|||||||
)
|
)
|
||||||
|
|
||||||
post(createRouting) {
|
post(createRouting) {
|
||||||
call.respond(
|
call.respond(originalRepo.create(call.receive()))
|
||||||
originalRepo.create(
|
|
||||||
call.receive()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
post(updateManyRouting) {
|
post(updateManyRouting) {
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.ktor.server.key_value
|
||||||
|
|
||||||
|
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.StandardCRUDRepo
|
||||||
|
import dev.inmo.micro_utils.repos.StandardKeyValueRepo
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.idParameterName
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.valueParameterName
|
||||||
|
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 kotlinx.serialization.*
|
||||||
|
import kotlinx.serialization.builtins.serializer
|
||||||
|
|
||||||
|
inline fun <reified Key : Any, reified Value : Any> Route.configureStandardKeyValueRepoRoutes (
|
||||||
|
originalRepo: StandardKeyValueRepo<Key, Value>,
|
||||||
|
noinline idDeserializer: suspend (String) -> Key,
|
||||||
|
noinline valueDeserializer: suspend (String) -> Value
|
||||||
|
) {
|
||||||
|
configureReadStandardKeyValueRepoRoutes(originalRepo, idDeserializer, valueDeserializer)
|
||||||
|
configureWriteStandardKeyValueRepoRoutes(originalRepo)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified Key : Any, reified Value : Any> Route.configureStandardKeyValueRepoRoutes(
|
||||||
|
originalRepo: StandardKeyValueRepo<Key, Value>,
|
||||||
|
idsSerializer: DeserializationStrategy<Key>,
|
||||||
|
valueSerializer: DeserializationStrategy<Value>,
|
||||||
|
serialFormat: StringFormat
|
||||||
|
) = configureStandardKeyValueRepoRoutes(
|
||||||
|
originalRepo,
|
||||||
|
{
|
||||||
|
serialFormat.decodeFromString(idsSerializer, it.decodeURLQueryComponent())
|
||||||
|
},
|
||||||
|
{
|
||||||
|
serialFormat.decodeFromString(valueSerializer, it.decodeURLQueryComponent())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
inline fun <reified Key : Any, reified Value : Any> Route.configureStandardKeyValueRepoRoutes(
|
||||||
|
originalRepo: StandardKeyValueRepo<Key, Value>,
|
||||||
|
idsSerializer: DeserializationStrategy<Key>,
|
||||||
|
valueSerializer: DeserializationStrategy<Value>,
|
||||||
|
serialFormat: BinaryFormat
|
||||||
|
) = configureStandardKeyValueRepoRoutes(
|
||||||
|
originalRepo,
|
||||||
|
{
|
||||||
|
serialFormat.decodeHex(idsSerializer, it)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
serialFormat.decodeHex(valueSerializer, it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,104 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.ktor.server.key_value
|
||||||
|
|
||||||
|
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.key_value.*
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.valueParameterName
|
||||||
|
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 (
|
||||||
|
originalRepo: ReadStandardKeyValueRepo<Key, Value>,
|
||||||
|
noinline idDeserializer: suspend (String) -> Key,
|
||||||
|
noinline valueDeserializer: suspend (String) -> Value
|
||||||
|
) {
|
||||||
|
get(getRoute) {
|
||||||
|
val key = idDeserializer(
|
||||||
|
call.getQueryParameterOrSendError(idParameterName) ?: return@get
|
||||||
|
)
|
||||||
|
|
||||||
|
originalRepo.get(key) ?.let {
|
||||||
|
call.respond(it)
|
||||||
|
} ?: 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
get(containsRoute) {
|
||||||
|
val key = idDeserializer(
|
||||||
|
call.getQueryParameterOrSendError(idParameterName) ?: return@get
|
||||||
|
)
|
||||||
|
|
||||||
|
call.respond(
|
||||||
|
originalRepo.contains(key)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
get(countRoute) {
|
||||||
|
call.respond(originalRepo.count())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified Key, reified Value> Route.configureReadStandardKeyValueRepoRoutes(
|
||||||
|
originalRepo: ReadStandardKeyValueRepo<Key, Value>,
|
||||||
|
idsSerializer: DeserializationStrategy<Key>,
|
||||||
|
valueSerializer: DeserializationStrategy<Value>,
|
||||||
|
serialFormat: StringFormat
|
||||||
|
) = configureReadStandardKeyValueRepoRoutes(
|
||||||
|
originalRepo,
|
||||||
|
{
|
||||||
|
serialFormat.decodeFromString(idsSerializer, it.decodeURLQueryComponent())
|
||||||
|
},
|
||||||
|
{
|
||||||
|
serialFormat.decodeFromString(valueSerializer, it.decodeURLQueryComponent())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
inline fun <reified Key, reified Value> Route.configureReadStandardKeyValueRepoRoutes(
|
||||||
|
originalRepo: ReadStandardKeyValueRepo<Key, Value>,
|
||||||
|
idsSerializer: DeserializationStrategy<Key>,
|
||||||
|
valueSerializer: DeserializationStrategy<Value>,
|
||||||
|
serialFormat: BinaryFormat
|
||||||
|
) = configureReadStandardKeyValueRepoRoutes(
|
||||||
|
originalRepo,
|
||||||
|
{
|
||||||
|
serialFormat.decodeHex(idsSerializer, it)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
serialFormat.decodeHex(valueSerializer, it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,45 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.ktor.server.key_value
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.ktor.server.*
|
||||||
|
import dev.inmo.micro_utils.repos.WriteStandardKeyValueRepo
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
|
||||||
|
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.configureWriteStandardKeyValueRepoRoutes (
|
||||||
|
originalRepo: WriteStandardKeyValueRepo<Key, Value>
|
||||||
|
) {
|
||||||
|
includeWebsocketHandling(
|
||||||
|
onNewValueRoute,
|
||||||
|
originalRepo.onNewValue
|
||||||
|
)
|
||||||
|
|
||||||
|
includeWebsocketHandling(
|
||||||
|
onValueRemovedRoute,
|
||||||
|
originalRepo.onValueRemoved
|
||||||
|
)
|
||||||
|
|
||||||
|
val mapType = typeInfo<Map<Key, Value>>()
|
||||||
|
val listKeysType = typeInfo<List<Key>>()
|
||||||
|
val listValuesType = typeInfo<List<Value>>()
|
||||||
|
|
||||||
|
post(setRoute) {
|
||||||
|
originalRepo.set(call.receive(mapType))
|
||||||
|
call.respond(HttpStatusCode.OK)
|
||||||
|
}
|
||||||
|
|
||||||
|
post(unsetRoute) {
|
||||||
|
originalRepo.unset(call.receive(listKeysType))
|
||||||
|
call.respond(HttpStatusCode.OK)
|
||||||
|
}
|
||||||
|
|
||||||
|
post(unsetWithValuesRoute) {
|
||||||
|
originalRepo.unsetWithValues(call.receive(listValuesType))
|
||||||
|
call.respond(HttpStatusCode.OK)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user