mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2025-09-23 17:29:21 +00:00
Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
121e513fdd | |||
9cf01ab54f | |||
c655107681 | |||
91a5af6a9a | |||
86e74c0a6f | |||
d8f01f21a0 | |||
9fb8626d8c | |||
1c52e04cdb | |||
798128256e | |||
72c2df47fd | |||
c9c6d4c0c1 | |||
2f4f9f3003 | |||
22e8f8e5d6 | |||
04cf8c3d9a | |||
52198be543 | |||
80fd5a489b | |||
b187043ee1 | |||
8965752055 | |||
b796620267 |
25
CHANGELOG.md
25
CHANGELOG.md
@@ -1,5 +1,30 @@
|
||||
# Changelog
|
||||
|
||||
## 0.11.4
|
||||
|
||||
* `Coroutines`:
|
||||
* `Compose`:
|
||||
* Add extension `StateFlow#asMutableComposeListState` and `StateFlow#asComposeList`
|
||||
* Add extension `StateFlow#asMutableComposeState`/`StateFlow#asComposeState`
|
||||
|
||||
## 0.11.3
|
||||
|
||||
* `Ktor`:
|
||||
* Support of `WebSockets` has been improved
|
||||
* `Client`:
|
||||
* New extensions: `HttpClient#openBaseWebSocketFlow`, `HttpClient#openWebSocketFlow`, `HttpClient#openSecureWebSocketFlow`
|
||||
|
||||
## 0.11.2
|
||||
|
||||
* `Ktor`:
|
||||
* Support of `WebSockets` has been improved and added fixes inside of clients
|
||||
|
||||
## 0.11.1
|
||||
|
||||
* `Repos`
|
||||
* `Ktor`
|
||||
* In `configureReadKeyValueRepoRoutes` and `configureReadKeyValuesRepoRoutes` configurators fixed requiring of `reversed` property
|
||||
|
||||
## 0.11.0
|
||||
|
||||
* `Versions`
|
||||
|
@@ -0,0 +1,26 @@
|
||||
package dev.inmo.micro_utils.coroutines.compose
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||
import dev.inmo.micro_utils.common.applyDiff
|
||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun <reified T> Flow<List<T>>.asMutableComposeListState(
|
||||
scope: CoroutineScope
|
||||
): SnapshotStateList<T> {
|
||||
val state = mutableStateListOf<T>()
|
||||
subscribeSafelyWithoutExceptions(scope) {
|
||||
state.applyDiff(it)
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun <reified T> Flow<List<T>>.asComposeList(
|
||||
scope: CoroutineScope
|
||||
): List<T> = asMutableComposeListState(scope)
|
||||
|
@@ -0,0 +1,35 @@
|
||||
package dev.inmo.micro_utils.coroutines.compose
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
fun <T> Flow<T>.asMutableComposeState(
|
||||
initial: T,
|
||||
scope: CoroutineScope
|
||||
): MutableState<T> {
|
||||
val state = mutableStateOf(initial)
|
||||
subscribeSafelyWithoutExceptions(scope) { state.value = it }
|
||||
return state
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun <T> StateFlow<T>.asMutableComposeState(
|
||||
scope: CoroutineScope
|
||||
): MutableState<T> = asMutableComposeState(value, scope)
|
||||
|
||||
fun <T> Flow<T>.asComposeState(
|
||||
initial: T,
|
||||
scope: CoroutineScope
|
||||
): State<T> {
|
||||
val state = asMutableComposeState(initial, scope)
|
||||
return derivedStateOf { state.value }
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun <T> StateFlow<T>.asComposeState(
|
||||
scope: CoroutineScope
|
||||
): State<T> = asComposeState(value, scope)
|
||||
|
@@ -14,5 +14,5 @@ crypto_js_version=4.1.1
|
||||
# Project data
|
||||
|
||||
group=dev.inmo
|
||||
version=0.11.0
|
||||
android_code_version=124
|
||||
version=0.11.4
|
||||
android_code_version=128
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package dev.inmo.micro_utils.ktor.client
|
||||
|
||||
import dev.inmo.micro_utils.common.Warning
|
||||
import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
||||
import dev.inmo.micro_utils.coroutines.safely
|
||||
import dev.inmo.micro_utils.ktor.common.*
|
||||
@@ -7,35 +8,25 @@ import io.ktor.client.HttpClient
|
||||
import io.ktor.client.plugins.pluginOrNull
|
||||
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 io.ktor.http.URLProtocol
|
||||
import kotlinx.coroutines.channels.SendChannel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.channelFlow
|
||||
import kotlinx.coroutines.isActive
|
||||
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 <reified T> HttpClient.createStandardWebsocketFlow(
|
||||
url: String,
|
||||
@Warning("This feature is internal and should not be used directly. It is can be changed without any notification and warranty on compile-time or other guaranties")
|
||||
inline fun <reified T : Any> openBaseWebSocketFlow(
|
||||
noinline checkReconnection: suspend (Throwable?) -> Boolean = { true },
|
||||
noinline requestBuilder: HttpRequestBuilder.() -> Unit = {}
|
||||
noinline webSocketSessionRequest: suspend SendChannel<T>.() -> Unit
|
||||
): Flow<T> {
|
||||
pluginOrNull(WebSockets) ?: error("Plugin $WebSockets must be installed for using createStandardWebsocketFlow")
|
||||
|
||||
val correctedUrl = url.asCorrectWebSocketUrl
|
||||
|
||||
return channelFlow {
|
||||
do {
|
||||
val reconnect = runCatchingSafely {
|
||||
ws(correctedUrl, requestBuilder) {
|
||||
for (received in incoming) {
|
||||
sendSerialized(received.data)
|
||||
}
|
||||
}
|
||||
webSocketSessionRequest()
|
||||
checkReconnection(null)
|
||||
}.getOrElse { e ->
|
||||
checkReconnection(e).also {
|
||||
@@ -53,3 +44,60 @@ inline fun <reified T> HttpClient.createStandardWebsocketFlow(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 <reified T : Any> HttpClient.openWebSocketFlow(
|
||||
url: String,
|
||||
useSecureConnection: Boolean,
|
||||
noinline checkReconnection: suspend (Throwable?) -> Boolean = { true },
|
||||
noinline requestBuilder: HttpRequestBuilder.() -> Unit = {}
|
||||
): Flow<T> {
|
||||
pluginOrNull(WebSockets) ?: error("Plugin $WebSockets must be installed for using createStandardWebsocketFlow")
|
||||
|
||||
return openBaseWebSocketFlow<T>(checkReconnection) {
|
||||
val block: suspend DefaultClientWebSocketSession.() -> Unit = {
|
||||
while (isActive) {
|
||||
send(receiveDeserialized<T>())
|
||||
}
|
||||
}
|
||||
|
||||
if (useSecureConnection) {
|
||||
wss(url, requestBuilder, block)
|
||||
} else {
|
||||
ws(url, requestBuilder, block)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 <reified T : Any> HttpClient.openWebSocketFlow(
|
||||
url: String,
|
||||
noinline checkReconnection: suspend (Throwable?) -> Boolean = { true },
|
||||
noinline requestBuilder: HttpRequestBuilder.() -> Unit = {}
|
||||
): Flow<T> = openWebSocketFlow(url, false, checkReconnection, requestBuilder)
|
||||
|
||||
/**
|
||||
* @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 <reified T : Any> HttpClient.openSecureWebSocketFlow(
|
||||
url: String,
|
||||
noinline checkReconnection: suspend (Throwable?) -> Boolean = { true },
|
||||
noinline requestBuilder: HttpRequestBuilder.() -> Unit = {}
|
||||
): Flow<T> = openWebSocketFlow(url, true, checkReconnection, requestBuilder)
|
||||
|
||||
/**
|
||||
* @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 <reified T : Any> HttpClient.createStandardWebsocketFlow(
|
||||
url: String,
|
||||
noinline checkReconnection: suspend (Throwable?) -> Boolean = { true },
|
||||
noinline requestBuilder: HttpRequestBuilder.() -> Unit = {}
|
||||
): Flow<T> = openWebSocketFlow(url, checkReconnection, requestBuilder)
|
||||
|
@@ -4,7 +4,10 @@ import dev.inmo.micro_utils.common.MPPFile
|
||||
import dev.inmo.micro_utils.ktor.common.TemporalFileId
|
||||
import io.ktor.client.HttpClient
|
||||
import kotlinx.coroutines.*
|
||||
import org.w3c.dom.mediasource.ENDED
|
||||
import org.w3c.dom.mediasource.ReadyState
|
||||
import org.w3c.xhr.*
|
||||
import org.w3c.xhr.XMLHttpRequest.Companion.DONE
|
||||
|
||||
suspend fun tempUpload(
|
||||
fullTempUploadDraftPath: String,
|
||||
@@ -12,7 +15,7 @@ suspend fun tempUpload(
|
||||
onUpload: (Long, Long) -> Unit
|
||||
): TemporalFileId {
|
||||
val formData = FormData()
|
||||
val answer = CompletableDeferred<TemporalFileId>()
|
||||
val answer = CompletableDeferred<TemporalFileId>(currentCoroutineContext().job)
|
||||
|
||||
formData.append(
|
||||
"data",
|
||||
@@ -37,17 +40,15 @@ suspend fun tempUpload(
|
||||
request.open("POST", fullTempUploadDraftPath, true)
|
||||
request.send(formData)
|
||||
|
||||
val handle = currentCoroutineContext().job.invokeOnCompletion {
|
||||
answer.invokeOnCompletion {
|
||||
runCatching {
|
||||
request.abort()
|
||||
if (request.readyState != DONE) {
|
||||
request.abort()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return runCatching {
|
||||
answer.await()
|
||||
}.also {
|
||||
handle.dispose()
|
||||
}.getOrThrow()
|
||||
return answer.await()
|
||||
}
|
||||
|
||||
|
||||
|
@@ -12,6 +12,7 @@ import io.ktor.websocket.send
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.serialization.SerializationStrategy
|
||||
|
||||
@Deprecated("This method will be removed soon")
|
||||
fun <T> Route.includeWebsocketHandling(
|
||||
suburl: String,
|
||||
flow: Flow<T>,
|
||||
|
@@ -15,7 +15,8 @@ import kotlinx.serialization.SerializationStrategy
|
||||
inline fun <reified T : Any> Route.includeWebsocketHandling(
|
||||
suburl: String,
|
||||
flow: Flow<T>,
|
||||
protocol: URLProtocol? = null
|
||||
protocol: URLProtocol? = null,
|
||||
noinline dataMapper: suspend WebSocketServerSession.(T) -> T? = { it }
|
||||
) {
|
||||
application.apply {
|
||||
pluginOrNull(WebSockets) ?: install(WebSockets)
|
||||
@@ -23,7 +24,7 @@ inline fun <reified T : Any> Route.includeWebsocketHandling(
|
||||
webSocket(suburl, protocol ?.name) {
|
||||
safely {
|
||||
flow.collect {
|
||||
sendSerialized(it)
|
||||
sendSerialized(dataMapper(it) ?: return@collect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@ import io.ktor.http.content.streamProvider
|
||||
import io.ktor.server.application.call
|
||||
import io.ktor.server.request.receiveMultipart
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.response.respondText
|
||||
import io.ktor.server.routing.Route
|
||||
import io.ktor.server.routing.post
|
||||
import kotlinx.coroutines.*
|
||||
@@ -111,7 +112,7 @@ class TemporalFilesRoutingConfigurator(
|
||||
temporalFilesMutex.withLock {
|
||||
temporalFilesMap[fileId] = file
|
||||
}
|
||||
call.respond(fileId.string)
|
||||
call.respondText(fileId.string)
|
||||
launchSafelyWithoutExceptions { filesFlow.emit(fileId) }
|
||||
} ?: call.respond(HttpStatusCode.BadRequest)
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package dev.inmo.micro_utils.repos.ktor.client.crud
|
||||
|
||||
import dev.inmo.micro_utils.ktor.common.*
|
||||
import dev.inmo.micro_utils.pagination.PaginationResult
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.http.ContentType
|
||||
@@ -19,14 +20,14 @@ class KtorCRUDRepoClient<ObjectType, IdType, InputValue> (
|
||||
inline operator fun <reified ObjectType, reified IdType, reified InputValue> invoke(
|
||||
baseUrl: String,
|
||||
httpClient: HttpClient,
|
||||
objectTypeInfo: TypeInfo,
|
||||
contentType: ContentType,
|
||||
noinline idSerializer: suspend (IdType) -> String
|
||||
) = KtorCRUDRepoClient(
|
||||
KtorReadCRUDRepoClient(
|
||||
baseUrl,
|
||||
httpClient,
|
||||
objectTypeInfo,
|
||||
typeInfo<ObjectType>(),
|
||||
typeInfo<PaginationResult<ObjectType>>(),
|
||||
contentType,
|
||||
idSerializer
|
||||
),
|
||||
@@ -41,33 +42,17 @@ class KtorCRUDRepoClient<ObjectType, IdType, InputValue> (
|
||||
baseUrl: String,
|
||||
subpart: String,
|
||||
httpClient: HttpClient,
|
||||
objectTypeInfo: TypeInfo,
|
||||
contentType: ContentType,
|
||||
noinline idSerializer: suspend (IdType) -> String
|
||||
) = KtorCRUDRepoClient<ObjectType, IdType, InputValue>(
|
||||
buildStandardUrl(baseUrl, subpart),
|
||||
httpClient,
|
||||
objectTypeInfo,
|
||||
contentType,
|
||||
idSerializer
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline fun <reified ObjectType, reified IdType, reified InputValue> KtorCRUDRepoClient(
|
||||
baseUrl: String,
|
||||
httpClient: HttpClient,
|
||||
contentType: ContentType,
|
||||
noinline idSerializer: suspend (IdType) -> String
|
||||
) = KtorCRUDRepoClient<ObjectType, IdType, InputValue>(
|
||||
baseUrl,
|
||||
httpClient,
|
||||
typeInfo<ObjectType>(),
|
||||
contentType,
|
||||
idSerializer
|
||||
)
|
||||
|
||||
inline fun <reified ObjectType, reified IdType, reified InputValue> KtorCRUDRepoClient(
|
||||
baseUrl: String,
|
||||
httpClient: HttpClient,
|
||||
|
@@ -18,6 +18,7 @@ class KtorReadCRUDRepoClient<ObjectType, IdType> (
|
||||
private val baseUrl: String,
|
||||
private val httpClient: HttpClient,
|
||||
private val objectType: TypeInfo,
|
||||
private val paginationObjectType: TypeInfo,
|
||||
private val contentType: ContentType,
|
||||
private val idSerializer: suspend (IdType) -> String
|
||||
) : ReadCRUDRepo<ObjectType, IdType> {
|
||||
@@ -25,7 +26,7 @@ class KtorReadCRUDRepoClient<ObjectType, IdType> (
|
||||
buildStandardUrl(baseUrl, getByPaginationRouting, pagination.asUrlQueryParts)
|
||||
) {
|
||||
contentType(contentType)
|
||||
}.body()
|
||||
}.body(paginationObjectType)
|
||||
|
||||
override suspend fun getById(id: IdType): ObjectType? = httpClient.get(
|
||||
buildStandardUrl(
|
||||
@@ -70,6 +71,7 @@ inline fun <reified ObjectType, IdType> KtorReadCRUDRepoClient(
|
||||
baseUrl,
|
||||
httpClient,
|
||||
typeInfo<ObjectType>(),
|
||||
typeInfo<PaginationResult<ObjectType>>(),
|
||||
contentType,
|
||||
idSerializer
|
||||
)
|
||||
|
@@ -1,7 +1,7 @@
|
||||
swagger: "2.0"
|
||||
openapi: "3.0.0"
|
||||
info:
|
||||
description: "This is a template for the CRUD repositories from [microutils](https://github.com/InsanusMokrassar/MicroUtils/tree/master/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud)"
|
||||
version: "0.11.0"
|
||||
version: "0.11.3"
|
||||
title: "CRUD Repo"
|
||||
contact:
|
||||
email: "ovsyannikov.alexey95@gmail.com"
|
||||
@@ -11,91 +11,61 @@ tags:
|
||||
- name: "Write"
|
||||
description: "Operations with `post` request in most cases"
|
||||
|
||||
parameters:
|
||||
IdInQuery:
|
||||
in: "query"
|
||||
name: "id"
|
||||
allOf:
|
||||
- $ref: "#/definitions/Key"
|
||||
IdsInBody:
|
||||
in: "body"
|
||||
name: "body"
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/Key"
|
||||
NewValuesInBody:
|
||||
in: "body"
|
||||
name: "body"
|
||||
type: array
|
||||
allOf:
|
||||
- $ref: "#/definitions/NewValues"
|
||||
NewValuesWithIdsInBody:
|
||||
in: "body"
|
||||
name: "body"
|
||||
type: array
|
||||
items:
|
||||
allOf:
|
||||
- $ref: "#/definitions/Pair"
|
||||
- properties:
|
||||
first:
|
||||
$ref: "#/definitions/Key"
|
||||
second:
|
||||
$ref: "#/definitions/NewValue"
|
||||
PaginationInQueryPage:
|
||||
in: "query"
|
||||
type: integer
|
||||
name: "ppage"
|
||||
description: "Page of pagination"
|
||||
required: false
|
||||
PaginationInQuerySize:
|
||||
in: "query"
|
||||
type: integer
|
||||
name: "psize"
|
||||
description: "Size of each page in pagination"
|
||||
required: false
|
||||
components:
|
||||
parameters:
|
||||
IdInQuery:
|
||||
in: "query"
|
||||
name: "id"
|
||||
schema:
|
||||
$ref: "#/components/schemas/Key"
|
||||
PaginationInQueryPage:
|
||||
in: "query"
|
||||
name: "ppage"
|
||||
description: "Page of pagination"
|
||||
schema:
|
||||
type: integer
|
||||
required: false
|
||||
PaginationInQuerySize:
|
||||
in: "query"
|
||||
name: "psize"
|
||||
description: "Size of each page in pagination"
|
||||
schema:
|
||||
type: integer
|
||||
required: false
|
||||
schemas:
|
||||
|
||||
|
||||
definitions:
|
||||
Key:
|
||||
type: integer
|
||||
description: "REWRITE THIS TYPE AS KEY IN SWAGGER FILE"
|
||||
Value:
|
||||
type: integer
|
||||
description: "REWRITE THIS TYPE AS VALUE IN SWAGGER FILE"
|
||||
Values:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/Value"
|
||||
NewValue:
|
||||
type: integer
|
||||
description: "REWRITE THIS TYPE AS NEW VALUE IN SWAGGER FILE"
|
||||
Pair:
|
||||
type: object
|
||||
description: "Pair of objects"
|
||||
properties:
|
||||
first:
|
||||
second:
|
||||
NewValues:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/NewValue"
|
||||
PaginationResult:
|
||||
type: object
|
||||
properties:
|
||||
page:
|
||||
type: integer
|
||||
description: "Page of pagination"
|
||||
pagesNumber:
|
||||
type: integer
|
||||
description: "Count of pages with the size from this pagination"
|
||||
size:
|
||||
type: integer
|
||||
description: "Size of each page in pagination"
|
||||
results:
|
||||
type: array
|
||||
description: "Array of all elements on that page. Size of pagination and size of array can be different and it can be interpreted like current page is the last one"
|
||||
items:
|
||||
type: object
|
||||
Key:
|
||||
type: integer
|
||||
description: "REWRITE THIS TYPE AS KEY IN SWAGGER FILE"
|
||||
Value:
|
||||
type: integer
|
||||
description: "REWRITE THIS TYPE AS VALUE IN SWAGGER FILE"
|
||||
NewValue:
|
||||
type: integer
|
||||
description: "REWRITE THIS TYPE AS NEW VALUE IN SWAGGER FILE"
|
||||
Pair:
|
||||
type: object
|
||||
description: "Pair of objects"
|
||||
properties:
|
||||
first:
|
||||
second:
|
||||
PaginationResult:
|
||||
type: object
|
||||
properties:
|
||||
page:
|
||||
type: integer
|
||||
description: "Page of pagination"
|
||||
pagesNumber:
|
||||
type: integer
|
||||
description: "Count of pages with the size from this pagination"
|
||||
size:
|
||||
type: integer
|
||||
description: "Size of each page in pagination"
|
||||
results:
|
||||
type: array
|
||||
description: "Array of all elements on that page. Size of pagination and size of array can be different and it can be interpreted like current page is the last one"
|
||||
items:
|
||||
type: object
|
||||
|
||||
paths:
|
||||
/getByPagination:
|
||||
@@ -103,30 +73,34 @@ paths:
|
||||
tags:
|
||||
- "Read"
|
||||
parameters:
|
||||
- $ref: "#/parameters/PaginationInQueryPage"
|
||||
- $ref: "#/parameters/PaginationInQuerySize"
|
||||
- $ref: "#/components/parameters/PaginationInQueryPage"
|
||||
- $ref: "#/components/parameters/PaginationInQuerySize"
|
||||
responses:
|
||||
"200":
|
||||
description: "Pagination with elements"
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: "#/definitions/PaginationResult"
|
||||
- properties:
|
||||
results:
|
||||
items:
|
||||
$ref: "#/definitions/Value"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/PaginationResult"
|
||||
- properties:
|
||||
results:
|
||||
items:
|
||||
$ref: "#/components/schemas/Value"
|
||||
/getById:
|
||||
get:
|
||||
tags:
|
||||
- "Read"
|
||||
parameters:
|
||||
- $ref: "#/parameters/IdInQuery"
|
||||
- $ref: "#/components/parameters/IdInQuery"
|
||||
required: true
|
||||
responses:
|
||||
"200":
|
||||
description: "Result object"
|
||||
schema:
|
||||
$ref: "#/definitions/Value"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Value"
|
||||
"204":
|
||||
description: "No value by id"
|
||||
/contains:
|
||||
@@ -134,13 +108,15 @@ paths:
|
||||
tags:
|
||||
- "Read"
|
||||
parameters:
|
||||
- $ref: "#/parameters/IdInQuery"
|
||||
- $ref: "#/components/parameters/IdInQuery"
|
||||
required: true
|
||||
responses:
|
||||
"200":
|
||||
description: "Object with id availability in repo"
|
||||
schema:
|
||||
type: boolean
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: boolean
|
||||
/count:
|
||||
get:
|
||||
tags:
|
||||
@@ -148,40 +124,75 @@ paths:
|
||||
responses:
|
||||
"200":
|
||||
description: "Amount of objects in repo"
|
||||
schema:
|
||||
type: integer
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: integer
|
||||
|
||||
|
||||
/create:
|
||||
post:
|
||||
tags:
|
||||
- "Write"
|
||||
parameters:
|
||||
- $ref: "#/parameters/NewValuesInBody"
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/NewValue"
|
||||
responses:
|
||||
"200":
|
||||
description: "Objects has been created and saved"
|
||||
schema:
|
||||
$ref: "#/definitions/Values"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Value"
|
||||
/update:
|
||||
post:
|
||||
tags:
|
||||
- "Write"
|
||||
parameters:
|
||||
- $ref: "#/parameters/NewValuesWithIdsInBody"
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/Pair"
|
||||
- properties:
|
||||
first:
|
||||
$ref: "#/components/schemas/Key"
|
||||
second:
|
||||
$ref: "#/components/schemas/NewValue"
|
||||
responses:
|
||||
"200":
|
||||
description: "Objects has been updated"
|
||||
schema:
|
||||
$ref: "#/definitions/Values"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Value"
|
||||
/deleteById:
|
||||
post:
|
||||
tags:
|
||||
- "Write"
|
||||
parameters:
|
||||
- $ref: "#/parameters/IdsInBody"
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Key"
|
||||
responses:
|
||||
"200":
|
||||
description: "Objects has been updated"
|
||||
schema:
|
||||
$ref: "#/definitions/Values"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Value"
|
||||
|
@@ -1,7 +1,7 @@
|
||||
swagger: "2.0"
|
||||
openapi: "3.0.0"
|
||||
info:
|
||||
description: "This is a template for the KeyValue repositories from [microutils](https://github.com/InsanusMokrassar/MicroUtils/tree/master/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key/value)"
|
||||
version: "0.11.0"
|
||||
version: "0.11.1"
|
||||
title: "KeyValue Repo"
|
||||
contact:
|
||||
email: "ovsyannikov.alexey95@gmail.com"
|
||||
@@ -11,81 +11,63 @@ tags:
|
||||
- name: "Write"
|
||||
description: "Operations with `post` request in most cases"
|
||||
|
||||
parameters:
|
||||
KeyInQuery:
|
||||
in: "query"
|
||||
name: "key"
|
||||
allOf:
|
||||
- $ref: "#/definitions/Key"
|
||||
KeysInBody:
|
||||
in: "body"
|
||||
name: "body"
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/Key"
|
||||
ValuesInBody:
|
||||
in: "body"
|
||||
name: "body"
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/Value"
|
||||
PaginationInQueryPage:
|
||||
in: "query"
|
||||
type: integer
|
||||
name: "ppage"
|
||||
description: "Page of pagination"
|
||||
required: false
|
||||
PaginationInQuerySize:
|
||||
in: "query"
|
||||
type: integer
|
||||
name: "psize"
|
||||
description: "Size of each page in pagination"
|
||||
required: false
|
||||
ReversedInQuery:
|
||||
in: "query"
|
||||
type: boolean
|
||||
name: "reversed"
|
||||
description: "If passed, will tell to reverse the result pages"
|
||||
required: false
|
||||
ValueInQuery:
|
||||
in: "query"
|
||||
name: "value"
|
||||
allOf:
|
||||
- $ref: "#/definitions/Value"
|
||||
MapInBody:
|
||||
in: "body"
|
||||
name: "body"
|
||||
allOf:
|
||||
- $ref: "#/definitions/Map"
|
||||
|
||||
|
||||
definitions:
|
||||
Key:
|
||||
type: integer
|
||||
description: "REWRITE THIS TYPE AS KEY IN SWAGGER FILE"
|
||||
Value:
|
||||
type: integer
|
||||
description: "REWRITE THIS TYPE AS VALUE IN SWAGGER FILE"
|
||||
Map:
|
||||
type: object
|
||||
description: "Map of objects"
|
||||
PaginationResult:
|
||||
type: object
|
||||
properties:
|
||||
page:
|
||||
components:
|
||||
parameters:
|
||||
KeyInQuery:
|
||||
in: "query"
|
||||
name: "key"
|
||||
schema:
|
||||
$ref: "#/components/schemas/Key"
|
||||
PaginationInQueryPage:
|
||||
in: "query"
|
||||
name: "ppage"
|
||||
description: "Page of pagination"
|
||||
schema:
|
||||
type: integer
|
||||
description: "Page of pagination"
|
||||
pagesNumber:
|
||||
required: false
|
||||
PaginationInQuerySize:
|
||||
in: "query"
|
||||
name: "psize"
|
||||
description: "Size of each page in pagination"
|
||||
schema:
|
||||
type: integer
|
||||
description: "Count of pages with the size from this pagination"
|
||||
size:
|
||||
type: integer
|
||||
description: "Size of each page in pagination"
|
||||
results:
|
||||
type: array
|
||||
description: "Array of all elements on that page. Size of pagination and size of array can be different and it can be interpreted like current page is the last one"
|
||||
items:
|
||||
type: object
|
||||
required: false
|
||||
ReversedInQuery:
|
||||
in: "query"
|
||||
name: "reversed"
|
||||
description: "If passed, will tell to reverse the result pages"
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
ValueInQuery:
|
||||
in: "query"
|
||||
name: "value"
|
||||
schema:
|
||||
$ref: "#/components/schemas/Value"
|
||||
schemas:
|
||||
Key:
|
||||
type: integer
|
||||
description: "REWRITE THIS TYPE AS KEY IN SWAGGER FILE"
|
||||
Value:
|
||||
type: integer
|
||||
description: "REWRITE THIS TYPE AS VALUE IN SWAGGER FILE"
|
||||
PaginationResult:
|
||||
type: object
|
||||
properties:
|
||||
page:
|
||||
type: integer
|
||||
description: "Page of pagination"
|
||||
pagesNumber:
|
||||
type: integer
|
||||
description: "Count of pages with the size from this pagination"
|
||||
size:
|
||||
type: integer
|
||||
description: "Size of each page in pagination"
|
||||
results:
|
||||
type: array
|
||||
description: "Array of all elements on that page. Size of pagination and size of array can be different and it can be interpreted like current page is the last one"
|
||||
items:
|
||||
type: object
|
||||
|
||||
paths:
|
||||
/get:
|
||||
@@ -93,13 +75,16 @@ paths:
|
||||
tags:
|
||||
- "Read"
|
||||
parameters:
|
||||
- $ref: "#/parameters/KeyInQuery"
|
||||
required: true
|
||||
- allOf:
|
||||
- $ref: "#/components/parameters/KeyInQuery"
|
||||
- required: true
|
||||
responses:
|
||||
"200":
|
||||
description: "Element by key"
|
||||
schema:
|
||||
$ref: "#/definitions/Value"
|
||||
content:
|
||||
"*/*":
|
||||
schema:
|
||||
$ref: "#/components/schemas/Value"
|
||||
"204":
|
||||
description: "No value by id"
|
||||
/values:
|
||||
@@ -107,51 +92,57 @@ paths:
|
||||
tags:
|
||||
- "Read"
|
||||
parameters:
|
||||
- $ref: "#/parameters/PaginationInQueryPage"
|
||||
- $ref: "#/parameters/PaginationInQuerySize"
|
||||
- $ref: "#/parameters/ReversedInQuery"
|
||||
- $ref: "#/components/parameters/PaginationInQueryPage"
|
||||
- $ref: "#/components/parameters/PaginationInQuerySize"
|
||||
- $ref: "#/components/parameters/ReversedInQuery"
|
||||
responses:
|
||||
"200":
|
||||
description: "Pagination with elements"
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: "#/definitions/PaginationResult"
|
||||
- properties:
|
||||
results:
|
||||
items:
|
||||
$ref: "#/definitions/Value"
|
||||
content:
|
||||
"*/*":
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/PaginationResult"
|
||||
- properties:
|
||||
results:
|
||||
items:
|
||||
$ref: "#/components/schemas/Value"
|
||||
/keys:
|
||||
get:
|
||||
tags:
|
||||
- "Read"
|
||||
parameters:
|
||||
- $ref: "#/parameters/PaginationInQueryPage"
|
||||
- $ref: "#/parameters/PaginationInQuerySize"
|
||||
- $ref: "#/parameters/ReversedInQuery"
|
||||
- $ref: "#/parameters/ValueInQuery"
|
||||
- $ref: "#/components/parameters/PaginationInQueryPage"
|
||||
- $ref: "#/components/parameters/PaginationInQuerySize"
|
||||
- $ref: "#/components/parameters/ReversedInQuery"
|
||||
- $ref: "#/components/parameters/ValueInQuery"
|
||||
required: false
|
||||
responses:
|
||||
"200":
|
||||
description: "Pagination with elements"
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: "#/definitions/PaginationResult"
|
||||
- properties:
|
||||
results:
|
||||
items:
|
||||
$ref: "#/definitions/Key"
|
||||
content:
|
||||
"*/*":
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/PaginationResult"
|
||||
- properties:
|
||||
results:
|
||||
items:
|
||||
$ref: "#/components/schemas/Key"
|
||||
/contains:
|
||||
get:
|
||||
tags:
|
||||
- "Read"
|
||||
parameters:
|
||||
- $ref: "#/parameters/KeyInQuery"
|
||||
- $ref: "#/components/parameters/KeyInQuery"
|
||||
required: true
|
||||
responses:
|
||||
"200":
|
||||
description: "Object with id availability in repo"
|
||||
schema:
|
||||
type: boolean
|
||||
content:
|
||||
"*/*":
|
||||
schema:
|
||||
type: boolean
|
||||
/count:
|
||||
get:
|
||||
tags:
|
||||
@@ -159,19 +150,23 @@ paths:
|
||||
responses:
|
||||
"200":
|
||||
description: "Amount of objects in repo"
|
||||
schema:
|
||||
type: integer
|
||||
content:
|
||||
"*/*":
|
||||
schema:
|
||||
type: integer
|
||||
|
||||
|
||||
/set:
|
||||
post:
|
||||
tags:
|
||||
- "Write"
|
||||
parameters:
|
||||
- allOf:
|
||||
- $ref: "#/parameters/MapInBody"
|
||||
- additionalProperties:
|
||||
$ref: "#/definitions/Value"
|
||||
requestBody:
|
||||
content:
|
||||
"*/*":
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties:
|
||||
$ref: "#/components/schemas/Value"
|
||||
description: "Map with new elements to set. Use keys as a keys of this map"
|
||||
responses:
|
||||
"200":
|
||||
@@ -180,8 +175,13 @@ paths:
|
||||
post:
|
||||
tags:
|
||||
- "Write"
|
||||
parameters:
|
||||
- $ref: "#/parameters/KeysInBody"
|
||||
requestBody:
|
||||
content:
|
||||
"*/*":
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Key"
|
||||
responses:
|
||||
"200":
|
||||
description: "Objects with keys from body has been unset"
|
||||
@@ -189,8 +189,13 @@ paths:
|
||||
post:
|
||||
tags:
|
||||
- "Write"
|
||||
parameters:
|
||||
- $ref: "#/parameters/ValuesInBody"
|
||||
requestBody:
|
||||
content:
|
||||
"*/*":
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Value"
|
||||
responses:
|
||||
"200":
|
||||
description: "Objects with values from body has been unset"
|
||||
|
@@ -51,7 +51,7 @@ inline fun <reified Key, reified Value> Route.configureReadKeyValueRepoRoutes (
|
||||
|
||||
get(keysRoute) {
|
||||
val pagination = call.request.queryParameters.extractPagination
|
||||
val reversed = call.getQueryParameterOrSendError(reversedParameterName) ?.toBoolean() ?: false
|
||||
val reversed = call.getQueryParameter(reversedParameterName) ?.toBoolean() ?: false
|
||||
val value = call.getQueryParameter(valueParameterName) ?.let {
|
||||
valueDeserializer(it)
|
||||
}
|
||||
|
@@ -42,7 +42,7 @@ inline fun <reified Key, reified Value> Route.configureReadKeyValuesRepoRoutes (
|
||||
|
||||
get(keysRoute) {
|
||||
val pagination = call.request.queryParameters.extractPagination
|
||||
val reversed = call.getQueryParameterOrSendError(reversedParameterName) ?.toBoolean() ?: false
|
||||
val reversed = call.getQueryParameter(reversedParameterName) ?.toBoolean() ?: false
|
||||
val value = call.getQueryParameter(valueParameterName) ?.let {
|
||||
valueDeserializer(it)
|
||||
}
|
||||
|
Reference in New Issue
Block a user