mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-11-04 06:00:22 +00:00 
			
		
		
		
	complete improvements in repos ktor parts
This commit is contained in:
		@@ -2,6 +2,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## 0.11.0
 | 
					## 0.11.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Ktor`
 | 
				
			||||||
 | 
					  * 
 | 
				
			||||||
 | 
					* `Repos`
 | 
				
			||||||
 | 
					  * `Ktor`:
 | 
				
			||||||
 | 
					    * Fully rewritten work with all declared repositories
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 0.10.8
 | 
					## 0.10.8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* `Common`
 | 
					* `Common`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.ktor.client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import io.ktor.client.plugins.ClientRequestException
 | 
				
			||||||
 | 
					import io.ktor.client.statement.HttpResponse
 | 
				
			||||||
 | 
					import io.ktor.http.isSuccess
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun HttpResponse.throwOnUnsuccess(
 | 
				
			||||||
 | 
					    unsuccessMessage: () -> String
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    if (status.isSuccess()) {
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    throw ClientRequestException(this, unsuccessMessage())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.ktor.server
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import io.ktor.server.application.ApplicationCall
 | 
				
			||||||
 | 
					import io.ktor.server.response.responseType
 | 
				
			||||||
 | 
					import io.ktor.util.InternalAPI
 | 
				
			||||||
 | 
					import io.ktor.util.reflect.TypeInfo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@InternalAPI
 | 
				
			||||||
 | 
					suspend fun <T : Any> ApplicationCall.respond(
 | 
				
			||||||
 | 
					    message: T,
 | 
				
			||||||
 | 
					    typeInfo: TypeInfo
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    response.responseType = typeInfo
 | 
				
			||||||
 | 
					    response.pipeline.execute(this, message as Any)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -104,6 +104,13 @@ interface OneToManyKeyValueRepo<Key, Value> : ReadOneToManyKeyValueRepo<Key, Val
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
typealias KeyValuesRepo<Key,Value> = OneToManyKeyValueRepo<Key, Value>
 | 
					typealias KeyValuesRepo<Key,Value> = OneToManyKeyValueRepo<Key, Value>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DelegateBasedOneToManyKeyValueRepo<Key, Value>(
 | 
				
			||||||
 | 
					    readDelegate: ReadOneToManyKeyValueRepo<Key, Value>,
 | 
				
			||||||
 | 
					    writeDelegate: WriteOneToManyKeyValueRepo<Key, Value>
 | 
				
			||||||
 | 
					) : OneToManyKeyValueRepo<Key, Value>,
 | 
				
			||||||
 | 
					    ReadOneToManyKeyValueRepo<Key, Value> by readDelegate,
 | 
				
			||||||
 | 
					    WriteOneToManyKeyValueRepo<Key, Value> by writeDelegate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.remove(
 | 
					suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.remove(
 | 
				
			||||||
    keysAndValues: List<Pair<Key, List<Value>>>
 | 
					    keysAndValues: List<Pair<Key, List<Value>>>
 | 
				
			||||||
) = remove(keysAndValues.toMap())
 | 
					) = remove(keysAndValues.toMap())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -80,6 +80,10 @@ class MapWriteOneToManyKeyValueRepo<Key, Value>(
 | 
				
			|||||||
                    _onValueRemoved.emit(k to v)
 | 
					                    _onValueRemoved.emit(k to v)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            if (map[k] ?.isEmpty() == true) {
 | 
				
			||||||
 | 
					                map.remove(k)
 | 
				
			||||||
 | 
					                _onDataCleared.emit(k)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@ import dev.inmo.micro_utils.ktor.client.*
 | 
				
			|||||||
import dev.inmo.micro_utils.ktor.common.*
 | 
					import dev.inmo.micro_utils.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.countRouting
 | 
				
			||||||
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 dev.inmo.micro_utils.repos.ktor.common.idParameterName
 | 
				
			||||||
import io.ktor.client.HttpClient
 | 
					import io.ktor.client.HttpClient
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ package dev.inmo.micro_utils.repos.ktor.client.crud
 | 
				
			|||||||
import dev.inmo.micro_utils.ktor.common.*
 | 
					import dev.inmo.micro_utils.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.countRouting
 | 
				
			||||||
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 dev.inmo.micro_utils.repos.ktor.common.idParameterName
 | 
				
			||||||
import io.ktor.client.HttpClient
 | 
					import io.ktor.client.HttpClient
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,11 +11,7 @@ import io.ktor.client.request.*
 | 
				
			|||||||
import io.ktor.client.statement.HttpResponse
 | 
					import io.ktor.client.statement.HttpResponse
 | 
				
			||||||
import io.ktor.http.ContentType
 | 
					import io.ktor.http.ContentType
 | 
				
			||||||
import io.ktor.http.contentType
 | 
					import io.ktor.http.contentType
 | 
				
			||||||
import io.ktor.util.reflect.TypeInfo
 | 
					 | 
				
			||||||
import io.ktor.util.reflect.typeInfo
 | 
					 | 
				
			||||||
import kotlinx.coroutines.flow.Flow
 | 
					import kotlinx.coroutines.flow.Flow
 | 
				
			||||||
import kotlinx.serialization.KSerializer
 | 
					 | 
				
			||||||
import kotlinx.serialization.builtins.*
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class KtorWriteStandardCrudRepoClient<ObjectType, IdType, InputValue> (
 | 
					class KtorWriteStandardCrudRepoClient<ObjectType, IdType, InputValue> (
 | 
				
			||||||
    private val baseUrl: String,
 | 
					    private val baseUrl: String,
 | 
				
			||||||
@@ -50,7 +46,7 @@ class KtorWriteStandardCrudRepoClient<ObjectType, IdType, InputValue> (
 | 
				
			|||||||
            buildStandardUrl(baseUrl, deleteByIdRouting)
 | 
					            buildStandardUrl(baseUrl, deleteByIdRouting)
 | 
				
			||||||
        ) {
 | 
					        ) {
 | 
				
			||||||
            deleteByIdSetup(ids)
 | 
					            deleteByIdSetup(ids)
 | 
				
			||||||
        }.status
 | 
					        }.throwOnUnsuccess { "Unable to delete $ids" }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,8 +4,12 @@ import dev.inmo.micro_utils.ktor.client.*
 | 
				
			|||||||
import dev.inmo.micro_utils.ktor.common.*
 | 
					import dev.inmo.micro_utils.ktor.common.*
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.*
 | 
					import dev.inmo.micro_utils.pagination.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
 | 
					import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.common.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.common.containsRoute
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.common.countRoute
 | 
				
			||||||
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
 | 
					import dev.inmo.micro_utils.repos.ktor.common.key_value.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.ktor.common.valueParameterName
 | 
					import dev.inmo.micro_utils.repos.ktor.common.key_value.keyParameterName
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.common.key_value.reversedParameterName
 | 
				
			||||||
import io.ktor.client.HttpClient
 | 
					import io.ktor.client.HttpClient
 | 
				
			||||||
import kotlinx.serialization.*
 | 
					import kotlinx.serialization.*
 | 
				
			||||||
import kotlinx.serialization.builtins.serializer
 | 
					import kotlinx.serialization.builtins.serializer
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,9 +4,8 @@ import dev.inmo.micro_utils.ktor.common.*
 | 
				
			|||||||
import dev.inmo.micro_utils.pagination.*
 | 
					import dev.inmo.micro_utils.pagination.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
 | 
					import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
 | 
				
			||||||
import dev.inmo.micro_utils.repos.ktor.common.*
 | 
					import dev.inmo.micro_utils.repos.ktor.common.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.ktor.common.crud.*
 | 
					import dev.inmo.micro_utils.repos.ktor.common.containsRoute
 | 
				
			||||||
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
 | 
					import dev.inmo.micro_utils.repos.ktor.common.key_value.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.containsByKeyRoute
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName
 | 
					import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName
 | 
				
			||||||
import io.ktor.client.HttpClient
 | 
					import io.ktor.client.HttpClient
 | 
				
			||||||
import io.ktor.client.call.body
 | 
					import io.ktor.client.call.body
 | 
				
			||||||
@@ -83,7 +82,7 @@ class KtorReadStandardKeyValueRepoClient<Key, Value>(
 | 
				
			|||||||
    override suspend fun count(): Long = httpClient.get(
 | 
					    override suspend fun count(): Long = httpClient.get(
 | 
				
			||||||
        buildStandardUrl(
 | 
					        buildStandardUrl(
 | 
				
			||||||
            baseUrl,
 | 
					            baseUrl,
 | 
				
			||||||
            countRouting
 | 
					            dev.inmo.micro_utils.repos.ktor.common.countRoute
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        contentType(contentType)
 | 
					        contentType(contentType)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,17 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.ktor.client.key_value
 | 
					package dev.inmo.micro_utils.repos.ktor.client.key_value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.inmo.micro_utils.ktor.client.createStandardWebsocketFlow
 | 
					import dev.inmo.micro_utils.ktor.client.createStandardWebsocketFlow
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.ktor.client.throwOnUnsuccess
 | 
				
			||||||
import dev.inmo.micro_utils.ktor.common.*
 | 
					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.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 dev.inmo.micro_utils.repos.ktor.common.key_value.*
 | 
				
			||||||
import io.ktor.client.HttpClient
 | 
					import io.ktor.client.HttpClient
 | 
				
			||||||
import io.ktor.client.request.get
 | 
					 | 
				
			||||||
import io.ktor.client.request.post
 | 
					import io.ktor.client.request.post
 | 
				
			||||||
import io.ktor.http.*
 | 
					import io.ktor.http.*
 | 
				
			||||||
import io.ktor.util.InternalAPI
 | 
					import io.ktor.util.InternalAPI
 | 
				
			||||||
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
 | 
				
			||||||
import kotlinx.serialization.*
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class KtorWriteStandardKeyValueRepoClient<Key, Value>(
 | 
					class KtorWriteStandardKeyValueRepoClient<Key, Value>(
 | 
				
			||||||
    private val baseUrl: String,
 | 
					    private val baseUrl: String,
 | 
				
			||||||
@@ -35,7 +31,7 @@ class KtorWriteStandardKeyValueRepoClient<Key, Value>(
 | 
				
			|||||||
            body = toUnset
 | 
					            body = toUnset
 | 
				
			||||||
            bodyType = objectsListTypeInfo
 | 
					            bodyType = objectsListTypeInfo
 | 
				
			||||||
            contentType(contentType)
 | 
					            contentType(contentType)
 | 
				
			||||||
        }.status
 | 
					        }.throwOnUnsuccess { "Unable to unset data with values $toUnset" }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @OptIn(InternalAPI::class)
 | 
					    @OptIn(InternalAPI::class)
 | 
				
			||||||
@@ -46,7 +42,7 @@ class KtorWriteStandardKeyValueRepoClient<Key, Value>(
 | 
				
			|||||||
            body = toUnset
 | 
					            body = toUnset
 | 
				
			||||||
            bodyType = idsListTypeInfo
 | 
					            bodyType = idsListTypeInfo
 | 
				
			||||||
            contentType(contentType)
 | 
					            contentType(contentType)
 | 
				
			||||||
        }.status
 | 
					        }.throwOnUnsuccess { "Unable to unset $toUnset" }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @OptIn(InternalAPI::class)
 | 
					    @OptIn(InternalAPI::class)
 | 
				
			||||||
@@ -57,7 +53,7 @@ class KtorWriteStandardKeyValueRepoClient<Key, Value>(
 | 
				
			|||||||
            body = toSet
 | 
					            body = toSet
 | 
				
			||||||
            bodyType = idsToObjectsMapTypeInfo
 | 
					            bodyType = idsToObjectsMapTypeInfo
 | 
				
			||||||
            contentType(contentType)
 | 
					            contentType(contentType)
 | 
				
			||||||
        }.status
 | 
					        }.throwOnUnsuccess { "Unable to set $toSet" }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,159 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.repos.ktor.client.one_to_many
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.ktor.common.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.pagination.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.common.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.common.crud.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName
 | 
				
			||||||
 | 
					import io.ktor.client.HttpClient
 | 
				
			||||||
 | 
					import io.ktor.client.call.body
 | 
				
			||||||
 | 
					import io.ktor.client.request.get
 | 
				
			||||||
 | 
					import io.ktor.http.*
 | 
				
			||||||
 | 
					import io.ktor.util.reflect.TypeInfo
 | 
				
			||||||
 | 
					import io.ktor.util.reflect.typeInfo
 | 
				
			||||||
 | 
					import kotlinx.serialization.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class KtorReadStandardKeyValuesRepoClient<Key, Value>(
 | 
				
			||||||
 | 
					    private val baseUrl: String,
 | 
				
			||||||
 | 
					    private val httpClient: HttpClient,
 | 
				
			||||||
 | 
					    private val contentType: ContentType,
 | 
				
			||||||
 | 
					    private val paginationResultValuesTypeInfo: TypeInfo,
 | 
				
			||||||
 | 
					    private val paginationResultKeysTypeInfo: TypeInfo,
 | 
				
			||||||
 | 
					    private val keySerializer: suspend (Key) -> String,
 | 
				
			||||||
 | 
					    private val valueSerializer: suspend (Value) -> String
 | 
				
			||||||
 | 
					) : ReadOneToManyKeyValueRepo<Key, Value> {
 | 
				
			||||||
 | 
					    override suspend fun get(
 | 
				
			||||||
 | 
					        k: Key,
 | 
				
			||||||
 | 
					        pagination: Pagination,
 | 
				
			||||||
 | 
					        reversed: Boolean
 | 
				
			||||||
 | 
					    ): PaginationResult<Value> = httpClient.get(
 | 
				
			||||||
 | 
					        buildStandardUrl(
 | 
				
			||||||
 | 
					            baseUrl,
 | 
				
			||||||
 | 
					            getRoute,
 | 
				
			||||||
 | 
					            pagination.asUrlQueryParts + (reversedParameterName to reversed.toString()) + (keyParameterName to keySerializer(k))
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        contentType(contentType)
 | 
				
			||||||
 | 
					    }.body(paginationResultValuesTypeInfo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override suspend fun keys(
 | 
				
			||||||
 | 
					        pagination: Pagination,
 | 
				
			||||||
 | 
					        reversed: Boolean
 | 
				
			||||||
 | 
					    ): PaginationResult<Key> = httpClient.get(
 | 
				
			||||||
 | 
					        buildStandardUrl(
 | 
				
			||||||
 | 
					            baseUrl,
 | 
				
			||||||
 | 
					            keysRoute,
 | 
				
			||||||
 | 
					            pagination.asUrlQueryParts + (reversedParameterName to reversed.toString())
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        contentType(contentType)
 | 
				
			||||||
 | 
					    }.body(paginationResultKeysTypeInfo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override suspend fun keys(
 | 
				
			||||||
 | 
					        v: Value,
 | 
				
			||||||
 | 
					        pagination: Pagination,
 | 
				
			||||||
 | 
					        reversed: Boolean
 | 
				
			||||||
 | 
					    ): PaginationResult<Key> = httpClient.get(
 | 
				
			||||||
 | 
					        buildStandardUrl(
 | 
				
			||||||
 | 
					            baseUrl,
 | 
				
			||||||
 | 
					            keysRoute,
 | 
				
			||||||
 | 
					            pagination.asUrlQueryParts + (reversedParameterName to reversed.toString()) + (valueParameterName to valueSerializer(v))
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        contentType(contentType)
 | 
				
			||||||
 | 
					    }.body(paginationResultKeysTypeInfo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override suspend fun contains(k: Key): Boolean = httpClient.get(
 | 
				
			||||||
 | 
					        buildStandardUrl(
 | 
				
			||||||
 | 
					            baseUrl,
 | 
				
			||||||
 | 
					            containsRoute,
 | 
				
			||||||
 | 
					            keyParameterName to keySerializer(k)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        contentType(contentType)
 | 
				
			||||||
 | 
					    }.body()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override suspend fun contains(k: Key, v: Value): Boolean = httpClient.get(
 | 
				
			||||||
 | 
					        buildStandardUrl(
 | 
				
			||||||
 | 
					            baseUrl,
 | 
				
			||||||
 | 
					            containsRoute,
 | 
				
			||||||
 | 
					            keyParameterName to keySerializer(k),
 | 
				
			||||||
 | 
					            valueParameterName to valueSerializer(v)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        contentType(contentType)
 | 
				
			||||||
 | 
					    }.body()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override suspend fun count(): Long = httpClient.get(
 | 
				
			||||||
 | 
					        buildStandardUrl(
 | 
				
			||||||
 | 
					            baseUrl,
 | 
				
			||||||
 | 
					            countRouting
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        contentType(contentType)
 | 
				
			||||||
 | 
					    }.body()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override suspend fun count(k: Key): Long = httpClient.get(
 | 
				
			||||||
 | 
					        buildStandardUrl(
 | 
				
			||||||
 | 
					            baseUrl,
 | 
				
			||||||
 | 
					            countRouting,
 | 
				
			||||||
 | 
					            keyParameterName to keySerializer(k),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        contentType(contentType)
 | 
				
			||||||
 | 
					    }.body()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified Key, reified Value> KtorReadStandardKeyValuesRepoClient(
 | 
				
			||||||
 | 
					    baseUrl: String,
 | 
				
			||||||
 | 
					    httpClient: HttpClient,
 | 
				
			||||||
 | 
					    contentType: ContentType,
 | 
				
			||||||
 | 
					    noinline keySerializer: suspend (Key) -> String,
 | 
				
			||||||
 | 
					    noinline valueSerializer: suspend (Value) -> String
 | 
				
			||||||
 | 
					) = KtorReadStandardKeyValuesRepoClient<Key, Value>(
 | 
				
			||||||
 | 
					    baseUrl,
 | 
				
			||||||
 | 
					    httpClient,
 | 
				
			||||||
 | 
					    contentType,
 | 
				
			||||||
 | 
					    typeInfo<PaginationResult<Value>>(),
 | 
				
			||||||
 | 
					    typeInfo<PaginationResult<Key>>(),
 | 
				
			||||||
 | 
					    keySerializer,
 | 
				
			||||||
 | 
					    valueSerializer
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified Key, reified Value> KtorReadStandardKeyValuesRepoClient(
 | 
				
			||||||
 | 
					    baseUrl: String,
 | 
				
			||||||
 | 
					    httpClient: HttpClient,
 | 
				
			||||||
 | 
					    idsSerializer: KSerializer<Key>,
 | 
				
			||||||
 | 
					    valueSerializer: KSerializer<Value>,
 | 
				
			||||||
 | 
					    serialFormat: StringFormat,
 | 
				
			||||||
 | 
					    contentType: ContentType,
 | 
				
			||||||
 | 
					) = KtorReadStandardKeyValuesRepoClient<Key, Value>(
 | 
				
			||||||
 | 
					    baseUrl,
 | 
				
			||||||
 | 
					    httpClient,
 | 
				
			||||||
 | 
					    contentType,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        serialFormat.encodeToString(idsSerializer, it).encodeURLQueryComponent()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified Key, reified Value> KtorReadStandardKeyValuesRepoClient(
 | 
				
			||||||
 | 
					    baseUrl: String,
 | 
				
			||||||
 | 
					    httpClient: HttpClient,
 | 
				
			||||||
 | 
					    idsSerializer: KSerializer<Key>,
 | 
				
			||||||
 | 
					    valuesSerializer: KSerializer<Value>,
 | 
				
			||||||
 | 
					    serialFormat: BinaryFormat,
 | 
				
			||||||
 | 
					    contentType: ContentType,
 | 
				
			||||||
 | 
					) = KtorReadStandardKeyValuesRepoClient<Key, Value>(
 | 
				
			||||||
 | 
					    baseUrl,
 | 
				
			||||||
 | 
					    httpClient,
 | 
				
			||||||
 | 
					    contentType,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        serialFormat.encodeHex(idsSerializer, it)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    serialFormat.encodeHex(valuesSerializer, it)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,89 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.repos.ktor.client.one_to_many
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.ktor.common.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
 | 
					import io.ktor.client.HttpClient
 | 
				
			||||||
 | 
					import io.ktor.http.ContentType
 | 
				
			||||||
 | 
					import io.ktor.http.encodeURLQueryComponent
 | 
				
			||||||
 | 
					import kotlinx.serialization.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class KtorStandardKeyValuesRepoClient<Key, Value> (
 | 
				
			||||||
 | 
					    readDelegate: ReadOneToManyKeyValueRepo<Key, Value>,
 | 
				
			||||||
 | 
					    writeDelegate: WriteOneToManyKeyValueRepo<Key, Value>
 | 
				
			||||||
 | 
					) : OneToManyKeyValueRepo<Key, Value> by DelegateBasedOneToManyKeyValueRepo(
 | 
				
			||||||
 | 
					    readDelegate,
 | 
				
			||||||
 | 
					    writeDelegate
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    companion object {
 | 
				
			||||||
 | 
					        inline operator fun <reified Key : Any, reified Value : Any> invoke(
 | 
				
			||||||
 | 
					            baseUrl: String,
 | 
				
			||||||
 | 
					            httpClient: HttpClient,
 | 
				
			||||||
 | 
					            contentType: ContentType,
 | 
				
			||||||
 | 
					            noinline keySerializer: suspend (Key) -> String,
 | 
				
			||||||
 | 
					            noinline valueSerializer: suspend (Value) -> String
 | 
				
			||||||
 | 
					        ) = KtorStandardKeyValuesRepoClient(
 | 
				
			||||||
 | 
					            KtorReadStandardKeyValuesRepoClient(
 | 
				
			||||||
 | 
					                baseUrl,
 | 
				
			||||||
 | 
					                httpClient,
 | 
				
			||||||
 | 
					                contentType,
 | 
				
			||||||
 | 
					                keySerializer,
 | 
				
			||||||
 | 
					                valueSerializer
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            KtorWriteStandardKeyValuesRepoClient(
 | 
				
			||||||
 | 
					                baseUrl,
 | 
				
			||||||
 | 
					                httpClient,
 | 
				
			||||||
 | 
					                contentType
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        inline operator fun <reified Key : Any, reified Value : Any> invoke(
 | 
				
			||||||
 | 
					            baseUrl: String,
 | 
				
			||||||
 | 
					            subpart: String,
 | 
				
			||||||
 | 
					            httpClient: HttpClient,
 | 
				
			||||||
 | 
					            contentType: ContentType,
 | 
				
			||||||
 | 
					            noinline keySerializer: suspend (Key) -> String,
 | 
				
			||||||
 | 
					            noinline valueSerializer: suspend (Value) -> String
 | 
				
			||||||
 | 
					        ) = KtorStandardKeyValuesRepoClient(
 | 
				
			||||||
 | 
					            buildStandardUrl(baseUrl, subpart),
 | 
				
			||||||
 | 
					            httpClient,
 | 
				
			||||||
 | 
					            contentType,
 | 
				
			||||||
 | 
					            keySerializer,
 | 
				
			||||||
 | 
					            valueSerializer
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified Key : Any, reified Value : Any> KtorStandardKeyValuesRepoClient(
 | 
				
			||||||
 | 
					    baseUrl: String,
 | 
				
			||||||
 | 
					    httpClient: HttpClient,
 | 
				
			||||||
 | 
					    contentType: ContentType,
 | 
				
			||||||
 | 
					    keySerializer: SerializationStrategy<Key>,
 | 
				
			||||||
 | 
					    valueSerializer: SerializationStrategy<Value>,
 | 
				
			||||||
 | 
					    serialFormat: StringFormat,
 | 
				
			||||||
 | 
					) = KtorStandardKeyValuesRepoClient<Key, Value>(
 | 
				
			||||||
 | 
					    baseUrl,
 | 
				
			||||||
 | 
					    httpClient,
 | 
				
			||||||
 | 
					    contentType,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        serialFormat.encodeToString(keySerializer, it).encodeURLQueryComponent()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified Key : Any, reified Value : Any> KtorStandardKeyValuesRepoClient(
 | 
				
			||||||
 | 
					    baseUrl: String,
 | 
				
			||||||
 | 
					    httpClient: HttpClient,
 | 
				
			||||||
 | 
					    contentType: ContentType,
 | 
				
			||||||
 | 
					    keySerializer: SerializationStrategy<Key>,
 | 
				
			||||||
 | 
					    valueSerializer: SerializationStrategy<Value>,
 | 
				
			||||||
 | 
					    serialFormat: BinaryFormat,
 | 
				
			||||||
 | 
					) = KtorStandardKeyValuesRepoClient<Key, Value>(
 | 
				
			||||||
 | 
					    baseUrl,
 | 
				
			||||||
 | 
					    httpClient,
 | 
				
			||||||
 | 
					    contentType,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        serialFormat.encodeHex(keySerializer, it)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    serialFormat.encodeHex(valueSerializer, it)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,106 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.repos.ktor.client.one_to_many
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.ktor.client.createStandardWebsocketFlow
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.ktor.client.throwOnUnsuccess
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.ktor.common.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.WriteOneToManyKeyValueRepo
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
 | 
				
			||||||
 | 
					import io.ktor.client.HttpClient
 | 
				
			||||||
 | 
					import io.ktor.client.request.post
 | 
				
			||||||
 | 
					import io.ktor.http.*
 | 
				
			||||||
 | 
					import io.ktor.util.InternalAPI
 | 
				
			||||||
 | 
					import io.ktor.util.reflect.TypeInfo
 | 
				
			||||||
 | 
					import io.ktor.util.reflect.typeInfo
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.Flow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class KtorWriteStandardKeyValuesRepoClient<Key : Any, Value : Any>(
 | 
				
			||||||
 | 
					    private val baseUrl: String,
 | 
				
			||||||
 | 
					    private val httpClient: HttpClient,
 | 
				
			||||||
 | 
					    private val contentType: ContentType,
 | 
				
			||||||
 | 
					    override val onNewValue: Flow<Pair<Key, Value>>,
 | 
				
			||||||
 | 
					    override val onValueRemoved: Flow<Pair<Key, Value>>,
 | 
				
			||||||
 | 
					    override val onDataCleared: Flow<Key>,
 | 
				
			||||||
 | 
					    private val keyTypeInfo: TypeInfo,
 | 
				
			||||||
 | 
					    private val valueTypeInfo: TypeInfo,
 | 
				
			||||||
 | 
					    private val keyToValuesMapTypeInfo: TypeInfo
 | 
				
			||||||
 | 
					) : WriteOneToManyKeyValueRepo<Key, Value> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @OptIn(InternalAPI::class)
 | 
				
			||||||
 | 
					    override suspend fun add(toAdd: Map<Key, List<Value>>) {
 | 
				
			||||||
 | 
					        httpClient.post(
 | 
				
			||||||
 | 
					            buildStandardUrl(baseUrl, addRoute)
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					            body = toAdd
 | 
				
			||||||
 | 
					            bodyType = keyToValuesMapTypeInfo
 | 
				
			||||||
 | 
					            contentType(contentType)
 | 
				
			||||||
 | 
					        }.throwOnUnsuccess { "Unable to add $toAdd" }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @OptIn(InternalAPI::class)
 | 
				
			||||||
 | 
					    override suspend fun remove(toRemove: Map<Key, List<Value>>) {
 | 
				
			||||||
 | 
					        httpClient.post(
 | 
				
			||||||
 | 
					            buildStandardUrl(baseUrl, removeRoute)
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					            body = toRemove
 | 
				
			||||||
 | 
					            bodyType = keyToValuesMapTypeInfo
 | 
				
			||||||
 | 
					            contentType(contentType)
 | 
				
			||||||
 | 
					        }.throwOnUnsuccess { "Unable to remove $toRemove" }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @OptIn(InternalAPI::class)
 | 
				
			||||||
 | 
					    override suspend fun clear(k: Key) {
 | 
				
			||||||
 | 
					        httpClient.post(
 | 
				
			||||||
 | 
					            buildStandardUrl(baseUrl, clearRoute)
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					            body = k
 | 
				
			||||||
 | 
					            bodyType = keyTypeInfo
 | 
				
			||||||
 | 
					            contentType(contentType)
 | 
				
			||||||
 | 
					        }.throwOnUnsuccess { "Unable to clear data with key $k" }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @OptIn(InternalAPI::class)
 | 
				
			||||||
 | 
					    override suspend fun clearWithValue(v: Value) {
 | 
				
			||||||
 | 
					        httpClient.post(
 | 
				
			||||||
 | 
					            buildStandardUrl(baseUrl, clearWithValueRoute)
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					            body = v
 | 
				
			||||||
 | 
					            bodyType = valueTypeInfo
 | 
				
			||||||
 | 
					            contentType(contentType)
 | 
				
			||||||
 | 
					        }.throwOnUnsuccess { "Unable to clear data with value $v" }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @OptIn(InternalAPI::class)
 | 
				
			||||||
 | 
					    override suspend fun set(toSet: Map<Key, List<Value>>) {
 | 
				
			||||||
 | 
					        httpClient.post(
 | 
				
			||||||
 | 
					            buildStandardUrl(baseUrl, setRoute)
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					            body = toSet
 | 
				
			||||||
 | 
					            bodyType = keyToValuesMapTypeInfo
 | 
				
			||||||
 | 
					            contentType(contentType)
 | 
				
			||||||
 | 
					        }.throwOnUnsuccess { "Unable to set data $toSet" }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    companion object {
 | 
				
			||||||
 | 
					        inline operator fun <reified Key : Any, reified Value : Any> invoke(
 | 
				
			||||||
 | 
					            baseUrl: String,
 | 
				
			||||||
 | 
					            httpClient: HttpClient,
 | 
				
			||||||
 | 
					            contentType: ContentType
 | 
				
			||||||
 | 
					        ) = KtorWriteStandardKeyValuesRepoClient<Key, Value>(
 | 
				
			||||||
 | 
					            baseUrl,
 | 
				
			||||||
 | 
					            httpClient,
 | 
				
			||||||
 | 
					            contentType,
 | 
				
			||||||
 | 
					            httpClient.createStandardWebsocketFlow(
 | 
				
			||||||
 | 
					                buildStandardUrl(baseUrl, onNewValueRoute),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            httpClient.createStandardWebsocketFlow(
 | 
				
			||||||
 | 
					                buildStandardUrl(baseUrl, onValueRemovedRoute),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            httpClient.createStandardWebsocketFlow(
 | 
				
			||||||
 | 
					                buildStandardUrl(baseUrl, onDataClearedRoute),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            typeInfo<Key>(),
 | 
				
			||||||
 | 
					            typeInfo<Value>(),
 | 
				
			||||||
 | 
					            typeInfo<Map<Key, List<Value>>>()
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.repos.ktor.common
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const val containsRoute = "contains"
 | 
				
			||||||
@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.repos.ktor.common
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const val countRoute = "count"
 | 
				
			||||||
@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.repos.ktor.common
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const val countRouting = "count"
 | 
				
			||||||
@@ -3,4 +3,3 @@ package dev.inmo.micro_utils.repos.ktor.common.crud
 | 
				
			|||||||
const val getByPaginationRouting = "getByPagination"
 | 
					const val getByPaginationRouting = "getByPagination"
 | 
				
			||||||
const val getByIdRouting = "getById"
 | 
					const val getByIdRouting = "getById"
 | 
				
			||||||
const val containsRouting = "contains"
 | 
					const val containsRouting = "contains"
 | 
				
			||||||
const val countRouting = "count"
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,8 +3,8 @@ package dev.inmo.micro_utils.repos.ktor.common.key_value
 | 
				
			|||||||
const val getRoute = "get"
 | 
					const val getRoute = "get"
 | 
				
			||||||
const val valuesRoute = "values"
 | 
					const val valuesRoute = "values"
 | 
				
			||||||
const val keysRoute = "keys"
 | 
					const val keysRoute = "keys"
 | 
				
			||||||
const val containsRoute = "contains"
 | 
					const val containsRoute = dev.inmo.micro_utils.repos.ktor.common.containsRoute
 | 
				
			||||||
const val countRoute = "count"
 | 
					const val countRoute = dev.inmo.micro_utils.repos.ktor.common.countRoute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const val onNewValueRoute = "onNewValue"
 | 
					const val onNewValueRoute = "onNewValue"
 | 
				
			||||||
const val onValueRemovedRoute = "onValueRemoved"
 | 
					const val onValueRemovedRoute = "onValueRemoved"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@ const val keysRoute = "keys"
 | 
				
			|||||||
const val containsByKeyRoute = "containsByKey"
 | 
					const val containsByKeyRoute = "containsByKey"
 | 
				
			||||||
const val containsByKeyValueRoute = "containsByKeyValue"
 | 
					const val containsByKeyValueRoute = "containsByKeyValue"
 | 
				
			||||||
const val countByKeyRoute = "countByKey"
 | 
					const val countByKeyRoute = "countByKey"
 | 
				
			||||||
const val countRoute = "count"
 | 
					const val countRoute = dev.inmo.micro_utils.repos.ktor.common.countRoute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const val onNewValueRoute = "onNewValue"
 | 
					const val onNewValueRoute = "onNewValue"
 | 
				
			||||||
const val onValueRemovedRoute = "onValueRemoved"
 | 
					const val onValueRemovedRoute = "onValueRemoved"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,7 @@ class CRUDTests {
 | 
				
			|||||||
    @OptIn(ExperimentalCoroutinesApi::class)
 | 
					    @OptIn(ExperimentalCoroutinesApi::class)
 | 
				
			||||||
    @Test
 | 
					    @Test
 | 
				
			||||||
    fun testCRUDFunctions() {
 | 
					    fun testCRUDFunctions() {
 | 
				
			||||||
        runTest() {
 | 
					        runTest {
 | 
				
			||||||
            val map = mutableMapOf<Int, ComplexData>()
 | 
					            val map = mutableMapOf<Int, ComplexData>()
 | 
				
			||||||
            val repo = MapCRUDRepo<ComplexData, Int, SimpleData>(
 | 
					            val repo = MapCRUDRepo<ComplexData, Int, SimpleData>(
 | 
				
			||||||
                map,
 | 
					                map,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,8 +22,8 @@ import kotlin.test.*
 | 
				
			|||||||
class KVTests {
 | 
					class KVTests {
 | 
				
			||||||
    @OptIn(ExperimentalCoroutinesApi::class)
 | 
					    @OptIn(ExperimentalCoroutinesApi::class)
 | 
				
			||||||
    @Test
 | 
					    @Test
 | 
				
			||||||
    fun testCRUDFunctions() {
 | 
					    fun testKVFunctions() {
 | 
				
			||||||
        runTest() {
 | 
					        runTest {
 | 
				
			||||||
            val map = mutableMapOf<Int, ComplexData>()
 | 
					            val map = mutableMapOf<Int, ComplexData>()
 | 
				
			||||||
            val repo = MapKeyValueRepo<Int, ComplexData>(map)
 | 
					            val repo = MapKeyValueRepo<Int, ComplexData>(map)
 | 
				
			||||||
            val server = io.ktor.server.engine.embeddedServer(
 | 
					            val server = io.ktor.server.engine.embeddedServer(
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										141
									
								
								repos/ktor/common/src/jvmTest/kotlin/KVsTests.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								repos/ktor/common/src/jvmTest/kotlin/KVsTests.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,141 @@
 | 
				
			|||||||
 | 
					import dev.inmo.micro_utils.pagination.firstPageWithOneElementPagination
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.client.key_value.KtorStandardKeyValueRepoClient
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.client.one_to_many.KtorStandardKeyValuesRepoClient
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.server.one_to_many.configureStandardKeyValuesRepoRoutes
 | 
				
			||||||
 | 
					import io.ktor.client.HttpClient
 | 
				
			||||||
 | 
					import io.ktor.client.plugins.logging.Logging
 | 
				
			||||||
 | 
					import io.ktor.http.ContentType
 | 
				
			||||||
 | 
					import io.ktor.serialization.kotlinx.KotlinxWebsocketSerializationConverter
 | 
				
			||||||
 | 
					import io.ktor.serialization.kotlinx.json.json
 | 
				
			||||||
 | 
					import io.ktor.server.application.install
 | 
				
			||||||
 | 
					import io.ktor.server.cio.CIO
 | 
				
			||||||
 | 
					import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
 | 
				
			||||||
 | 
					import io.ktor.server.routing.routing
 | 
				
			||||||
 | 
					import io.ktor.server.websocket.WebSockets
 | 
				
			||||||
 | 
					import kotlinx.coroutines.ExperimentalCoroutinesApi
 | 
				
			||||||
 | 
					import kotlinx.coroutines.test.runTest
 | 
				
			||||||
 | 
					import kotlinx.serialization.builtins.serializer
 | 
				
			||||||
 | 
					import kotlinx.serialization.json.Json
 | 
				
			||||||
 | 
					import kotlin.test.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class KVsTests {
 | 
				
			||||||
 | 
					    @OptIn(ExperimentalCoroutinesApi::class)
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    fun testKVsFunctions() {
 | 
				
			||||||
 | 
					        runTest {
 | 
				
			||||||
 | 
					            val map = mutableMapOf<Int, MutableList<ComplexData>>()
 | 
				
			||||||
 | 
					            val repo = MapOneToManyKeyValueRepo(map)
 | 
				
			||||||
 | 
					            val server = io.ktor.server.engine.embeddedServer(
 | 
				
			||||||
 | 
					                CIO,
 | 
				
			||||||
 | 
					                23456,
 | 
				
			||||||
 | 
					                "127.0.0.1"
 | 
				
			||||||
 | 
					            ) {
 | 
				
			||||||
 | 
					                install(ContentNegotiation) {
 | 
				
			||||||
 | 
					                    json()
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                install(WebSockets) {
 | 
				
			||||||
 | 
					                    contentConverter = KotlinxWebsocketSerializationConverter(Json)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                routing {
 | 
				
			||||||
 | 
					                    configureStandardKeyValuesRepoRoutes(
 | 
				
			||||||
 | 
					                        repo,
 | 
				
			||||||
 | 
					                        Int.serializer(),
 | 
				
			||||||
 | 
					                        ComplexData.serializer(),
 | 
				
			||||||
 | 
					                        Json {}
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }.start(false)
 | 
				
			||||||
 | 
					            val client = HttpClient {
 | 
				
			||||||
 | 
					                install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) {
 | 
				
			||||||
 | 
					                    json()
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                install(Logging)
 | 
				
			||||||
 | 
					                install(io.ktor.client.plugins.websocket.WebSockets) {
 | 
				
			||||||
 | 
					                    contentConverter = KotlinxWebsocketSerializationConverter(Json)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            val crudClient = KtorStandardKeyValuesRepoClient(
 | 
				
			||||||
 | 
					                "http://127.0.0.1:23456",
 | 
				
			||||||
 | 
					                client,
 | 
				
			||||||
 | 
					                ContentType.Application.Json,
 | 
				
			||||||
 | 
					                Int.serializer(),
 | 
				
			||||||
 | 
					                ComplexData.serializer(),
 | 
				
			||||||
 | 
					                Json
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val dataInOneKey = ComplexData(1, title = "Example1")
 | 
				
			||||||
 | 
					            val dataInMultipleKeys = ComplexData(2, title = "Example2")
 | 
				
			||||||
 | 
					            val repeatCount = 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val dataList = listOf(
 | 
				
			||||||
 | 
					                1 to listOf(dataInOneKey)
 | 
				
			||||||
 | 
					            ) + (0 until repeatCount).map {
 | 
				
			||||||
 | 
					                (it + 2) to listOf(dataInMultipleKeys)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            dataList.forEachIndexed { i, (id, data) ->
 | 
				
			||||||
 | 
					                crudClient.set(id, data)
 | 
				
			||||||
 | 
					                assertEquals(i + 1, map.size)
 | 
				
			||||||
 | 
					                assertEquals(map.size.toLong(), crudClient.count())
 | 
				
			||||||
 | 
					                assertEquals(i + 1L, crudClient.count())
 | 
				
			||||||
 | 
					                dataList.take(i + 1).forEach { (id, data) ->
 | 
				
			||||||
 | 
					                    assertContentEquals(data, map[id])
 | 
				
			||||||
 | 
					                    assertContentEquals(data, crudClient.getAll(id))
 | 
				
			||||||
 | 
					                    assertContentEquals(map[id], crudClient.getAll(id))
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            dataList.forEach { (key, data) ->
 | 
				
			||||||
 | 
					                assertTrue(crudClient.contains(key))
 | 
				
			||||||
 | 
					                assertContentEquals(data, crudClient.getAll(key))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            assertEquals(
 | 
				
			||||||
 | 
					                dataList.mapNotNull { if (it.second.contains(dataInMultipleKeys)) it.first else null },
 | 
				
			||||||
 | 
					                getAllWithNextPaging(firstPageWithOneElementPagination) {
 | 
				
			||||||
 | 
					                    crudClient.keys(dataInMultipleKeys, it)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            assertEquals(
 | 
				
			||||||
 | 
					                dataList.mapNotNull { if (it.second.contains(dataInOneKey)) it.first else null },
 | 
				
			||||||
 | 
					                getAllWithNextPaging(firstPageWithOneElementPagination) {
 | 
				
			||||||
 | 
					                    crudClient.keys(dataInOneKey, it)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            assertEquals(
 | 
				
			||||||
 | 
					                dataList.map { it.first },
 | 
				
			||||||
 | 
					                getAllWithNextPaging(firstPageWithOneElementPagination) {
 | 
				
			||||||
 | 
					                    crudClient.keys(it)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            assertEquals(
 | 
				
			||||||
 | 
					                dataList.map { it.first },
 | 
				
			||||||
 | 
					                getAllWithNextPaging(firstPageWithOneElementPagination) {
 | 
				
			||||||
 | 
					                    crudClient.keys(it)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            assertEquals(dataList.size.toLong(), crudClient.count())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            crudClient.remove(dataList.filter { it.second.contains(dataInMultipleKeys) })
 | 
				
			||||||
 | 
					            println(map)
 | 
				
			||||||
 | 
					            assertEquals(
 | 
				
			||||||
 | 
					                dataList.filter { it.second.contains(dataInOneKey) }.size.toLong(),
 | 
				
			||||||
 | 
					                crudClient.count()
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            crudClient.remove(dataList.filter { it.second.contains(dataInOneKey) })
 | 
				
			||||||
 | 
					            assertEquals(
 | 
				
			||||||
 | 
					                0,
 | 
				
			||||||
 | 
					                crudClient.count()
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            server.stop()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -6,6 +6,7 @@ import dev.inmo.micro_utils.ktor.server.*
 | 
				
			|||||||
import dev.inmo.micro_utils.pagination.PaginationResult
 | 
					import dev.inmo.micro_utils.pagination.PaginationResult
 | 
				
			||||||
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.countRouting
 | 
				
			||||||
import dev.inmo.micro_utils.repos.ktor.common.crud.*
 | 
					import dev.inmo.micro_utils.repos.ktor.common.crud.*
 | 
				
			||||||
import io.ktor.http.ContentType
 | 
					import io.ktor.http.ContentType
 | 
				
			||||||
import io.ktor.server.application.call
 | 
					import io.ktor.server.application.call
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@ import dev.inmo.micro_utils.ktor.common.decodeHex
 | 
				
			|||||||
import dev.inmo.micro_utils.ktor.server.*
 | 
					import dev.inmo.micro_utils.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.countRouting
 | 
				
			||||||
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 dev.inmo.micro_utils.repos.ktor.common.idParameterName
 | 
				
			||||||
import io.ktor.http.ContentType
 | 
					import io.ktor.http.ContentType
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,8 +6,12 @@ import dev.inmo.micro_utils.ktor.server.*
 | 
				
			|||||||
import dev.inmo.micro_utils.pagination.PaginationResult
 | 
					import dev.inmo.micro_utils.pagination.PaginationResult
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.extractPagination
 | 
					import dev.inmo.micro_utils.pagination.extractPagination
 | 
				
			||||||
import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
 | 
					import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.common.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.common.containsRoute
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.common.countRoute
 | 
				
			||||||
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
 | 
					import dev.inmo.micro_utils.repos.ktor.common.key_value.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.ktor.common.valueParameterName
 | 
					import dev.inmo.micro_utils.repos.ktor.common.key_value.keyParameterName
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.common.key_value.reversedParameterName
 | 
				
			||||||
import io.ktor.http.ContentType
 | 
					import io.ktor.http.ContentType
 | 
				
			||||||
import io.ktor.server.application.call
 | 
					import io.ktor.server.application.call
 | 
				
			||||||
import io.ktor.server.routing.Route
 | 
					import io.ktor.server.routing.Route
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,21 +4,20 @@ import dev.inmo.micro_utils.ktor.common.*
 | 
				
			|||||||
import dev.inmo.micro_utils.ktor.server.*
 | 
					import dev.inmo.micro_utils.ktor.server.*
 | 
				
			||||||
import dev.inmo.micro_utils.pagination.PaginationResult
 | 
					import dev.inmo.micro_utils.pagination.PaginationResult
 | 
				
			||||||
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.ReadStandardKeyValueRepo
 | 
					import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
 | 
				
			||||||
import dev.inmo.micro_utils.repos.ktor.common.idParameterName
 | 
					import dev.inmo.micro_utils.repos.ktor.common.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.common.containsRoute
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.common.countRoute
 | 
				
			||||||
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
 | 
					import dev.inmo.micro_utils.repos.ktor.common.key_value.*
 | 
				
			||||||
import dev.inmo.micro_utils.repos.ktor.common.valueParameterName
 | 
					import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName
 | 
				
			||||||
import io.ktor.http.*
 | 
					import io.ktor.http.*
 | 
				
			||||||
import io.ktor.server.application.call
 | 
					import io.ktor.server.application.call
 | 
				
			||||||
import io.ktor.server.response.respond
 | 
					import io.ktor.server.response.respond
 | 
				
			||||||
import io.ktor.server.response.responseType
 | 
					 | 
				
			||||||
import io.ktor.server.routing.Route
 | 
					import io.ktor.server.routing.Route
 | 
				
			||||||
import io.ktor.server.routing.get
 | 
					import io.ktor.server.routing.get
 | 
				
			||||||
import io.ktor.util.InternalAPI
 | 
					import io.ktor.util.InternalAPI
 | 
				
			||||||
import io.ktor.util.reflect.typeInfo
 | 
					import io.ktor.util.reflect.typeInfo
 | 
				
			||||||
import kotlinx.serialization.*
 | 
					import kotlinx.serialization.*
 | 
				
			||||||
import kotlinx.serialization.builtins.serializer
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
@OptIn(InternalAPI::class)
 | 
					@OptIn(InternalAPI::class)
 | 
				
			||||||
inline fun <reified Key, reified Value> Route.configureReadStandardKeyValueRepoRoutes (
 | 
					inline fun <reified Key, reified Value> Route.configureReadStandardKeyValueRepoRoutes (
 | 
				
			||||||
@@ -26,6 +25,9 @@ inline fun <reified Key, reified Value> Route.configureReadStandardKeyValueRepoR
 | 
				
			|||||||
    noinline idDeserializer: suspend (String) -> Key,
 | 
					    noinline idDeserializer: suspend (String) -> Key,
 | 
				
			||||||
    noinline valueDeserializer: suspend (String) -> Value
 | 
					    noinline valueDeserializer: suspend (String) -> Value
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
 | 
					    val paginationWithValuesTypeInfo = typeInfo<PaginationResult<Value>>()
 | 
				
			||||||
 | 
					    val paginationWithKeysTypeInfo = typeInfo<PaginationResult<Key>>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get(getRoute) {
 | 
					    get(getRoute) {
 | 
				
			||||||
        val key = idDeserializer(
 | 
					        val key = idDeserializer(
 | 
				
			||||||
            call.getQueryParameterOrSendError(idParameterName) ?: return@get
 | 
					            call.getQueryParameterOrSendError(idParameterName) ?: return@get
 | 
				
			||||||
@@ -36,13 +38,14 @@ inline fun <reified Key, reified Value> Route.configureReadStandardKeyValueRepoR
 | 
				
			|||||||
        } ?: call.respond(HttpStatusCode.NoContent)
 | 
					        } ?: call.respond(HttpStatusCode.NoContent)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val paginationWithValuesTypeInfo = typeInfo<PaginationResult<Value>>()
 | 
					 | 
				
			||||||
    get(valuesRoute) {
 | 
					    get(valuesRoute) {
 | 
				
			||||||
        val pagination = call.request.queryParameters.extractPagination
 | 
					        val pagination = call.request.queryParameters.extractPagination
 | 
				
			||||||
        val reversed = call.getQueryParameter(reversedParameterName) ?.toBoolean() ?: false
 | 
					        val reversed = call.getQueryParameter(reversedParameterName) ?.toBoolean() ?: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        call.response.responseType = paginationWithValuesTypeInfo
 | 
					        call.respond(
 | 
				
			||||||
        call.response.pipeline.execute(call, originalRepo.values(pagination, reversed) as Any)
 | 
					            originalRepo.values(pagination, reversed),
 | 
				
			||||||
 | 
					            paginationWithValuesTypeInfo
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get(keysRoute) {
 | 
					    get(keysRoute) {
 | 
				
			||||||
@@ -53,7 +56,8 @@ inline fun <reified Key, reified Value> Route.configureReadStandardKeyValueRepoR
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        call.respond(
 | 
					        call.respond(
 | 
				
			||||||
            value ?.let { originalRepo.keys(value, pagination, reversed) } ?: originalRepo.keys(pagination, reversed)
 | 
					            value ?.let { originalRepo.keys(value, pagination, reversed) } ?: originalRepo.keys(pagination, reversed),
 | 
				
			||||||
 | 
					            paginationWithKeysTypeInfo
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -62,9 +66,7 @@ inline fun <reified Key, reified Value> Route.configureReadStandardKeyValueRepoR
 | 
				
			|||||||
            call.getQueryParameterOrSendError(idParameterName) ?: return@get
 | 
					            call.getQueryParameterOrSendError(idParameterName) ?: return@get
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        call.respond(
 | 
					        call.respond(originalRepo.contains(key))
 | 
				
			||||||
            originalRepo.contains(key)
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get(countRoute) {
 | 
					    get(countRoute) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.repos.ktor.server.one_to_many
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.ktor.common.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.*
 | 
				
			||||||
 | 
					import io.ktor.http.*
 | 
				
			||||||
 | 
					import io.ktor.server.routing.Route
 | 
				
			||||||
 | 
					import kotlinx.serialization.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified Key : Any, reified Value : Any> Route.configureStandardKeyValuesRepoRoutes (
 | 
				
			||||||
 | 
					    originalRepo: OneToManyKeyValueRepo<Key, Value>,
 | 
				
			||||||
 | 
					    noinline idDeserializer: suspend (String) -> Key,
 | 
				
			||||||
 | 
					    noinline valueDeserializer: suspend (String) -> Value
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    configureReadStandardKeyValuesRepoRoutes(originalRepo, idDeserializer, valueDeserializer)
 | 
				
			||||||
 | 
					    configureWriteStandardKeyValuesRepoRoutes(originalRepo)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified Key : Any, reified Value : Any> Route.configureStandardKeyValuesRepoRoutes(
 | 
				
			||||||
 | 
					    originalRepo: OneToManyKeyValueRepo<Key, Value>,
 | 
				
			||||||
 | 
					    idsSerializer: DeserializationStrategy<Key>,
 | 
				
			||||||
 | 
					    valueSerializer: DeserializationStrategy<Value>,
 | 
				
			||||||
 | 
					    serialFormat: StringFormat
 | 
				
			||||||
 | 
					) = configureStandardKeyValuesRepoRoutes(
 | 
				
			||||||
 | 
					    originalRepo,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        serialFormat.decodeFromString(idsSerializer, it.decodeURLQueryComponent())
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        serialFormat.decodeFromString(valueSerializer, it.decodeURLQueryComponent())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified Key : Any, reified Value : Any> Route.configureStandardKeyValuesRepoRoutes(
 | 
				
			||||||
 | 
					    originalRepo: OneToManyKeyValueRepo<Key, Value>,
 | 
				
			||||||
 | 
					    idsSerializer: DeserializationStrategy<Key>,
 | 
				
			||||||
 | 
					    valueSerializer: DeserializationStrategy<Value>,
 | 
				
			||||||
 | 
					    serialFormat: BinaryFormat
 | 
				
			||||||
 | 
					) = configureStandardKeyValuesRepoRoutes(
 | 
				
			||||||
 | 
					    originalRepo,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        serialFormat.decodeHex(idsSerializer, it)
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        serialFormat.decodeHex(valueSerializer, it)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.repos.ktor.server.one_to_many
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.ktor.common.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.ktor.server.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.pagination.PaginationResult
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.pagination.extractPagination
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.common.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.common.containsRoute
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
 | 
				
			||||||
 | 
					import io.ktor.http.*
 | 
				
			||||||
 | 
					import io.ktor.server.application.call
 | 
				
			||||||
 | 
					import io.ktor.server.response.respond
 | 
				
			||||||
 | 
					import io.ktor.server.routing.Route
 | 
				
			||||||
 | 
					import io.ktor.server.routing.get
 | 
				
			||||||
 | 
					import io.ktor.util.InternalAPI
 | 
				
			||||||
 | 
					import io.ktor.util.reflect.typeInfo
 | 
				
			||||||
 | 
					import kotlinx.serialization.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@OptIn(InternalAPI::class)
 | 
				
			||||||
 | 
					inline fun <reified Key, reified Value> Route.configureReadStandardKeyValuesRepoRoutes (
 | 
				
			||||||
 | 
					    originalRepo: ReadOneToManyKeyValueRepo<Key, Value>,
 | 
				
			||||||
 | 
					    noinline idDeserializer: suspend (String) -> Key,
 | 
				
			||||||
 | 
					    noinline valueDeserializer: suspend (String) -> Value
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    val paginationWithValuesTypeInfo = typeInfo<PaginationResult<Value>>()
 | 
				
			||||||
 | 
					    val paginationWithKeysTypeInfo = typeInfo<PaginationResult<Key>>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get(getRoute) {
 | 
				
			||||||
 | 
					        val key = idDeserializer(
 | 
				
			||||||
 | 
					            call.getQueryParameterOrSendError(keyParameterName) ?: return@get
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        val pagination = call.request.queryParameters.extractPagination
 | 
				
			||||||
 | 
					        val reversed = call.getQueryParameter(reversedParameterName) ?.toBoolean() ?: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        call.respond(
 | 
				
			||||||
 | 
					            originalRepo.get(key, pagination, reversed),
 | 
				
			||||||
 | 
					            paginationWithValuesTypeInfo
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get(keysRoute) {
 | 
				
			||||||
 | 
					        val pagination = call.request.queryParameters.extractPagination
 | 
				
			||||||
 | 
					        val reversed = call.getQueryParameterOrSendError(reversedParameterName) ?.toBoolean() ?: false
 | 
				
			||||||
 | 
					        val value = call.getQueryParameter(valueParameterName) ?.let {
 | 
				
			||||||
 | 
					            valueDeserializer(it)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        call.respond(
 | 
				
			||||||
 | 
					            value ?.let { originalRepo.keys(value, pagination, reversed) } ?: originalRepo.keys(pagination, reversed),
 | 
				
			||||||
 | 
					            paginationWithKeysTypeInfo
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get(containsRoute) {
 | 
				
			||||||
 | 
					        val key = idDeserializer(
 | 
				
			||||||
 | 
					            call.getQueryParameterOrSendError(keyParameterName) ?: return@get
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        val value = call.getQueryParameter(valueParameterName) ?.let {
 | 
				
			||||||
 | 
					            valueDeserializer(it)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        call.respond(
 | 
				
			||||||
 | 
					            value ?.let { originalRepo.contains(key, value) } ?: originalRepo.contains(key)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get(dev.inmo.micro_utils.repos.ktor.common.countRoute) {
 | 
				
			||||||
 | 
					        val id = call.getQueryParameter(keyParameterName) ?.let {
 | 
				
			||||||
 | 
					            idDeserializer(it)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        call.respond(
 | 
				
			||||||
 | 
					            id ?.let { originalRepo.count(it) } ?: originalRepo.count()
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified Key, reified Value> Route.configureReadStandardKeyValuesRepoRoutes(
 | 
				
			||||||
 | 
					    originalRepo: ReadOneToManyKeyValueRepo<Key, Value>,
 | 
				
			||||||
 | 
					    idsSerializer: DeserializationStrategy<Key>,
 | 
				
			||||||
 | 
					    valueSerializer: DeserializationStrategy<Value>,
 | 
				
			||||||
 | 
					    serialFormat: StringFormat
 | 
				
			||||||
 | 
					) = configureReadStandardKeyValuesRepoRoutes(
 | 
				
			||||||
 | 
					    originalRepo,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        serialFormat.decodeFromString(idsSerializer, it.decodeURLQueryComponent())
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        serialFormat.decodeFromString(valueSerializer, it.decodeURLQueryComponent())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified Key, reified Value> Route.configureReadStandardKeyValuesRepoRoutes(
 | 
				
			||||||
 | 
					    originalRepo: ReadOneToManyKeyValueRepo<Key, Value>,
 | 
				
			||||||
 | 
					    idsSerializer: DeserializationStrategy<Key>,
 | 
				
			||||||
 | 
					    valueSerializer: DeserializationStrategy<Value>,
 | 
				
			||||||
 | 
					    serialFormat: BinaryFormat
 | 
				
			||||||
 | 
					) = configureReadStandardKeyValuesRepoRoutes(
 | 
				
			||||||
 | 
					    originalRepo,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        serialFormat.decodeHex(idsSerializer, it)
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        serialFormat.decodeHex(valueSerializer, it)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.repos.ktor.server.one_to_many
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.ktor.server.*
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.WriteOneToManyKeyValueRepo
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
 | 
				
			||||||
 | 
					import io.ktor.http.HttpStatusCode
 | 
				
			||||||
 | 
					import io.ktor.server.application.call
 | 
				
			||||||
 | 
					import io.ktor.server.request.receive
 | 
				
			||||||
 | 
					import io.ktor.server.response.respond
 | 
				
			||||||
 | 
					import io.ktor.server.routing.Route
 | 
				
			||||||
 | 
					import io.ktor.server.routing.post
 | 
				
			||||||
 | 
					import io.ktor.util.reflect.typeInfo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified Key : Any, reified Value : Any> Route.configureWriteStandardKeyValuesRepoRoutes (
 | 
				
			||||||
 | 
					    originalRepo: WriteOneToManyKeyValueRepo<Key, Value>
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    includeWebsocketHandling(
 | 
				
			||||||
 | 
					        onNewValueRoute,
 | 
				
			||||||
 | 
					        originalRepo.onNewValue
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    includeWebsocketHandling(
 | 
				
			||||||
 | 
					        onValueRemovedRoute,
 | 
				
			||||||
 | 
					        originalRepo.onValueRemoved
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    includeWebsocketHandling(
 | 
				
			||||||
 | 
					        onDataClearedRoute,
 | 
				
			||||||
 | 
					        originalRepo.onDataCleared
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val mapType = typeInfo<Map<Key, List<Value>>>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    post(addRoute) {
 | 
				
			||||||
 | 
					        originalRepo.add(call.receive(mapType))
 | 
				
			||||||
 | 
					        call.respond(HttpStatusCode.OK)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    post(setRoute) {
 | 
				
			||||||
 | 
					        originalRepo.set(call.receive(mapType))
 | 
				
			||||||
 | 
					        call.respond(HttpStatusCode.OK)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    post(removeRoute) {
 | 
				
			||||||
 | 
					        originalRepo.remove(call.receive(mapType))
 | 
				
			||||||
 | 
					        call.respond(HttpStatusCode.OK)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    post(clearRoute) {
 | 
				
			||||||
 | 
					        originalRepo.clear(call.receive())
 | 
				
			||||||
 | 
					        call.respond(HttpStatusCode.OK)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    post(clearWithValueRoute) {
 | 
				
			||||||
 | 
					        originalRepo.clearWithValue(call.receive())
 | 
				
			||||||
 | 
					        call.respond(HttpStatusCode.OK)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user