diff --git a/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/NewFlowsWebsockets.kt b/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/NewFlowsWebsockets.kt index ba84f813bac..4ee959eceb3 100644 --- a/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/NewFlowsWebsockets.kt +++ b/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/NewFlowsWebsockets.kt @@ -9,6 +9,7 @@ import io.ktor.client.plugins.websocket.* import io.ktor.client.request.HttpRequestBuilder import io.ktor.websocket.Frame import io.ktor.websocket.readBytes +import io.ktor.websocket.serialization.sendSerializedBase import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.channelFlow 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 * connection. Must return true in case if must be reconnected. By default always reconnecting */ -inline fun HttpClient.createStandardWebsocketFlow( +inline fun HttpClient.createStandardWebsocketFlow( url: String, - crossinline checkReconnection: suspend (Throwable?) -> Boolean = { true }, + noinline checkReconnection: suspend (Throwable?) -> Boolean = { true }, noinline requestBuilder: HttpRequestBuilder.() -> Unit = {} ): Flow { pluginOrNull(WebSockets) ?: error("Plugin $WebSockets must be installed for using createStandardWebsocketFlow") diff --git a/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/StandartCRUDRepo.kt b/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/StandartCRUDRepo.kt index df64fc47de7..33911b8d8ed 100644 --- a/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/StandartCRUDRepo.kt +++ b/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/StandartCRUDRepo.kt @@ -42,4 +42,11 @@ suspend fun WriteStandardCRUDRepo : ReadStandardCRUDRepo, WriteStandardCRUDRepo -typealias CRUDRepo = StandardCRUDRepo \ No newline at end of file +typealias CRUDRepo = StandardCRUDRepo + +class DelegateBasedStandardCRUDRepo( + readDelegate: ReadStandardCRUDRepo, + writeDelegate: WriteStandardCRUDRepo +) : StandardCRUDRepo, + ReadStandardCRUDRepo by readDelegate, + WriteStandardCRUDRepo by writeDelegate diff --git a/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapCRUDRepo.kt b/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapCRUDRepo.kt index 1d605a4c77b..e040c478112 100644 --- a/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapCRUDRepo.kt +++ b/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapCRUDRepo.kt @@ -74,19 +74,24 @@ abstract class MapCRUDRepo( fun MapCRUDRepo( map: MutableMap, - updateCallback: suspend (newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType, - createCallback: suspend (newValue: InputValueType) -> Pair + updateCallback: suspend MutableMap.(newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType, + createCallback: suspend MutableMap.(newValue: InputValueType) -> Pair ) = object : MapCRUDRepo(map) { override suspend fun updateObject( newValue: InputValueType, id: IdType, old: ObjectType - ): ObjectType = updateCallback(newValue, id, old) + ): ObjectType = map.updateCallback(newValue, id, old) - override suspend fun createObject(newValue: InputValueType): Pair = createCallback(newValue) + override suspend fun createObject(newValue: InputValueType): Pair = map.createCallback(newValue) } +fun MapCRUDRepo( + updateCallback: suspend MutableMap.(newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType, + createCallback: suspend MutableMap.(newValue: InputValueType) -> Pair +) = MapCRUDRepo(mutableMapOf(), updateCallback, createCallback) + fun MutableMap.asCrudRepo( - updateCallback: suspend (newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType, - createCallback: suspend (newValue: InputValueType) -> Pair + updateCallback: suspend MutableMap.(newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType, + createCallback: suspend MutableMap.(newValue: InputValueType) -> Pair ) = MapCRUDRepo(this, updateCallback, createCallback) diff --git a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepoClient.kt b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepoClient.kt index e7f00f3a40e..ce280f2c8bf 100644 --- a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepoClient.kt +++ b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepoClient.kt @@ -7,7 +7,7 @@ import dev.inmo.micro_utils.repos.ktor.common.crud.* import io.ktor.client.HttpClient import io.ktor.client.call.body 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 kotlinx.serialization.* @@ -16,11 +16,14 @@ class KtorReadStandardCrudRepoClient ( private val baseUrl: String, private val httpClient: HttpClient, private val objectType: TypeInfo, + private val contentType: ContentType, private val idSerializer: suspend (IdType) -> String ) : ReadStandardCRUDRepo { override suspend fun getByPagination(pagination: Pagination): PaginationResult = httpClient.get( buildStandardUrl(baseUrl, getByPaginationRouting, pagination.asUrlQueryParts) - ).body() + ) { + contentType(contentType) + }.body() override suspend fun getById(id: IdType): ObjectType? = httpClient.get( buildStandardUrl( @@ -30,7 +33,9 @@ class KtorReadStandardCrudRepoClient ( "id" to idSerializer(id) ) ) - ).takeIf { it.status != HttpStatusCode.NoContent } ?.body(objectType) + ) { + contentType(contentType) + }.takeIf { it.status != HttpStatusCode.NoContent } ?.body(objectType) override suspend fun contains(id: IdType): Boolean = httpClient.get( buildStandardUrl( @@ -40,24 +45,30 @@ class KtorReadStandardCrudRepoClient ( "id" to idSerializer(id) ) ) - ).body() + ) { + contentType(contentType) + }.body() override suspend fun count(): Long = httpClient.get( buildStandardUrl( baseUrl, countRouting ) - ).body() + ) { + contentType(contentType) + }.body() } inline fun KtorReadStandardCrudRepoClient( baseUrl: String, httpClient: HttpClient, + contentType: ContentType, noinline idSerializer: suspend (IdType) -> String ) = KtorReadStandardCrudRepoClient( baseUrl, httpClient, typeInfo(), + contentType, idSerializer ) @@ -65,8 +76,9 @@ inline fun KtorReadStandardCrudRepoClient( baseUrl: String, httpClient: HttpClient, idsSerializer: KSerializer, - serialFormat: StringFormat -) = KtorReadStandardCrudRepoClient(baseUrl, httpClient) { + serialFormat: StringFormat, + contentType: ContentType, +) = KtorReadStandardCrudRepoClient(baseUrl, httpClient, contentType) { serialFormat.encodeToString(idsSerializer, it) } @@ -74,7 +86,8 @@ inline fun KtorReadStandardCrudRepoClient( baseUrl: String, httpClient: HttpClient, idsSerializer: KSerializer, - serialFormat: BinaryFormat -) = KtorReadStandardCrudRepoClient(baseUrl, httpClient) { + serialFormat: BinaryFormat, + contentType: ContentType, +) = KtorReadStandardCrudRepoClient(baseUrl, httpClient, contentType) { serialFormat.encodeHex(idsSerializer, it) } diff --git a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorStandardCrudRepoClient.kt b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorStandardCrudRepoClient.kt index aa6bc86600e..d32a072f26c 100644 --- a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorStandardCrudRepoClient.kt +++ b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorStandardCrudRepoClient.kt @@ -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.repos.* 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 kotlinx.serialization.* class KtorStandardCrudRepoClient ( - baseUrl: String, - httpClient: HttpClient, - objectTypeInfo: TypeInfo, - idSerializer: suspend (IdType) -> String -) : StandardCRUDRepo, - ReadStandardCRUDRepo by KtorReadStandardCrudRepoClient( - baseUrl, - httpClient, - objectTypeInfo, - idSerializer - ), - WriteStandardCRUDRepo by KtorWriteStandardCrudRepoClient( - baseUrl, - httpClient - ) { - constructor( - baseUrl: String, - subpart: String, - httpClient: HttpClient, - objectTypeInfo: TypeInfo, - idSerializer: suspend (IdType) -> String - ) : this( - buildStandardUrl(baseUrl, subpart), httpClient, objectTypeInfo, idSerializer - ) + readDelegate: ReadStandardCRUDRepo, + writeDelegate: WriteStandardCRUDRepo +) : StandardCRUDRepo by DelegateBasedStandardCRUDRepo( + readDelegate, + writeDelegate +) { + companion object { + inline operator fun invoke( + baseUrl: String, + httpClient: HttpClient, + objectTypeInfo: TypeInfo, + contentType: ContentType, + noinline idSerializer: suspend (IdType) -> String + ) = KtorStandardCrudRepoClient( + KtorReadStandardCrudRepoClient( + baseUrl, + httpClient, + objectTypeInfo, + contentType, + idSerializer + ), + KtorWriteStandardCrudRepoClient( + baseUrl, + httpClient, + contentType + ) + ) + + inline operator fun invoke( + baseUrl: String, + subpart: String, + httpClient: HttpClient, + objectTypeInfo: TypeInfo, + contentType: ContentType, + noinline idSerializer: suspend (IdType) -> String + ) = KtorStandardCrudRepoClient( + buildStandardUrl(baseUrl, subpart), + httpClient, + objectTypeInfo, + contentType, + idSerializer + ) + } } -inline fun KtorStandardCrudRepoClient( +inline fun KtorStandardCrudRepoClient( baseUrl: String, httpClient: HttpClient, + contentType: ContentType, noinline idSerializer: suspend (IdType) -> String ) = KtorStandardCrudRepoClient( baseUrl, httpClient, typeInfo(), + contentType, idSerializer ) -inline fun KtorStandardCrudRepoClient( +inline fun KtorStandardCrudRepoClient( baseUrl: String, httpClient: HttpClient, idsSerializer: KSerializer, - serialFormat: StringFormat -) = KtorStandardCrudRepoClient(baseUrl, httpClient) { + serialFormat: StringFormat, + contentType: ContentType, +) = KtorStandardCrudRepoClient(baseUrl, httpClient, contentType) { serialFormat.encodeToString(idsSerializer, it) } -inline fun KtorStandardCrudRepoClient( +inline fun KtorStandardCrudRepoClient( baseUrl: String, httpClient: HttpClient, idsSerializer: KSerializer, - serialFormat: BinaryFormat -) = KtorStandardCrudRepoClient(baseUrl, httpClient) { + serialFormat: BinaryFormat, + contentType: ContentType, +) = KtorStandardCrudRepoClient(baseUrl, httpClient, contentType) { serialFormat.encodeHex(idsSerializer, it) } -inline fun KtorStandardCrudRepoClient( +inline fun KtorStandardCrudRepoClient( baseUrl: String, subpart: String, httpClient: HttpClient, + contentType: ContentType, noinline idSerializer: suspend (IdType) -> String ) = KtorStandardCrudRepoClient( buildStandardUrl(baseUrl, subpart), httpClient, + contentType, idSerializer ) -inline fun KtorStandardCrudRepoClient( +inline fun KtorStandardCrudRepoClient( baseUrl: String, subpart: String, httpClient: HttpClient, idsSerializer: KSerializer, - serialFormat: StringFormat -) = KtorStandardCrudRepoClient(buildStandardUrl(baseUrl, subpart), httpClient, idsSerializer, serialFormat) + serialFormat: StringFormat, + contentType: ContentType, +) = KtorStandardCrudRepoClient(buildStandardUrl(baseUrl, subpart), httpClient, idsSerializer, serialFormat, contentType) -inline fun KtorStandardCrudRepoClient( +inline fun KtorStandardCrudRepoClient( baseUrl: String, subpart: String, httpClient: HttpClient, idsSerializer: KSerializer, - serialFormat: BinaryFormat -) = KtorStandardCrudRepoClient(buildStandardUrl(baseUrl, subpart), httpClient, idsSerializer, serialFormat) + serialFormat: BinaryFormat, + contentType: ContentType, +) = KtorStandardCrudRepoClient(buildStandardUrl(baseUrl, subpart), httpClient, idsSerializer, serialFormat, contentType) diff --git a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorWriteStandardCrudRepoClient.kt b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorWriteStandardCrudRepoClient.kt index b0f9e27a9f0..0c5e6673b12 100644 --- a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorWriteStandardCrudRepoClient.kt +++ b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorWriteStandardCrudRepoClient.kt @@ -8,6 +8,9 @@ import dev.inmo.micro_utils.repos.ktor.common.crud.* import io.ktor.client.HttpClient import io.ktor.client.call.body 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 @@ -16,36 +19,71 @@ import kotlinx.serialization.builtins.* class KtorWriteStandardCrudRepoClient ( private val baseUrl: String, - private val httpClient: HttpClient + private val httpClient: HttpClient, + override val newObjectsFlow: Flow, + override val updatedObjectsFlow: Flow, + override val deletedObjectsIdsFlow: Flow, + private val createSetup: suspend HttpRequestBuilder.(List) -> Unit, + private val updateSetup: suspend HttpRequestBuilder.(List>) -> Unit, + private val deleteByIdSetup: suspend HttpRequestBuilder.(List) -> Unit, + private val createBodyGetter: suspend HttpResponse.() -> List, + private val updateBodyGetter: suspend HttpResponse.() -> List ) : WriteStandardCRUDRepo { + override suspend fun create(values: List): List = httpClient.post( + buildStandardUrl(baseUrl, createRouting) + ) { + createSetup(values) + }.createBodyGetter() - override val newObjectsFlow: Flow = httpClient.createStandardWebsocketFlow( - buildStandardUrl(baseUrl, newObjectsFlowRouting), - ) - override val updatedObjectsFlow: Flow = httpClient.createStandardWebsocketFlow( - buildStandardUrl(baseUrl, updatedObjectsFlowRouting) - ) - override val deletedObjectsIdsFlow: Flow = httpClient.createStandardWebsocketFlow( - buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting) - ) - - - override suspend fun create(values: List): List = httpClient.post { - url(buildStandardUrl(baseUrl, createRouting)) - setBody(values) - }.body() - - override suspend fun update(values: List>): List = httpClient.post { - url(buildStandardUrl(baseUrl, updateManyRouting)) - setBody(values) - }.body() + override suspend fun update( + values: List> + ): List = httpClient.post( + buildStandardUrl(baseUrl, updateManyRouting) + ) { + updateSetup(values) + }.updateBodyGetter() override suspend fun update(id: IdType, value: InputValue): ObjectType? = update(listOf(id to value)).firstOrNull() override suspend fun deleteById(ids: List) { - httpClient.post { - url(buildStandardUrl(baseUrl, deleteByIdRouting)) - setBody(ids) - } + httpClient.post( + buildStandardUrl(baseUrl, deleteByIdRouting) + ) { + deleteByIdSetup(ids) + }.status + } + + companion object { + inline operator fun invoke( + baseUrl: String, + httpClient: HttpClient, + contentType: ContentType + ) = KtorWriteStandardCrudRepoClient( + 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() } + ) } }