mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2026-01-13 08:49:31 +00:00
Compare commits
33 Commits
0.10.2
...
8eed435302
| Author | SHA1 | Date | |
|---|---|---|---|
| 8eed435302 | |||
| 0e4a63057f | |||
| 1af5faa440 | |||
| 7412217b0c | |||
| 3e749d75b7 | |||
| 846b5c87c9 | |||
| 7b5e84f80b | |||
| 27822a8a66 | |||
| 36f4e7ec37 | |||
| 187e84ad65 | |||
| 195fe221c4 | |||
| 6f9c19bbf6 | |||
| 65bdab4f7e | |||
| c4d5fcfc22 | |||
| 43232afa62 | |||
| 18908a01d7 | |||
| b22fbfb3bc | |||
| 57aaea88b6 | |||
| 140949c5ea | |||
| 639241e0d3 | |||
| e0eb42bc2d | |||
| 7990b21cc5 | |||
| 2ba5c97709 | |||
| 33b7c85fc2 | |||
| 7f6c02ffdf | |||
| f368616e6f | |||
| dd632f4203 | |||
| a8f3ae501b | |||
| ea76963ac2 | |||
| 99dfa97958 | |||
| f68270a5b3 | |||
| 542ed81034 | |||
| 404a11f5e7 |
42
CHANGELOG.md
42
CHANGELOG.md
@@ -1,5 +1,47 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.11.0
|
||||||
|
|
||||||
|
## 0.10.8
|
||||||
|
|
||||||
|
* `Common`
|
||||||
|
* Add `Element.isOverflow*` extension properties
|
||||||
|
|
||||||
|
## 0.10.7
|
||||||
|
|
||||||
|
* `Pagination`:
|
||||||
|
* Now it is possible to use `doForAll*` and `getForAll` functions in non suspend places
|
||||||
|
|
||||||
|
## 0.10.6
|
||||||
|
|
||||||
|
* `Versions`
|
||||||
|
* `Ktor`: `2.0.1` -> `2.0.2`
|
||||||
|
* `Common`
|
||||||
|
* `JS`:
|
||||||
|
* Add `ResizeObserver` functionality
|
||||||
|
|
||||||
|
## 0.10.5
|
||||||
|
|
||||||
|
* `Versions`
|
||||||
|
* `Compose`: `1.2.0-alpha01-dev683` -> `1.2.0-alpha01-dev686`
|
||||||
|
* `Repos`
|
||||||
|
* `Android`:
|
||||||
|
* New function `SharedPreferencesKeyValueRepo`
|
||||||
|
* `FSM`
|
||||||
|
* Add `StateHandlingErrorHandler` and opportunity to handle states handling errors
|
||||||
|
|
||||||
|
## 0.10.4
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Serialization`: `1.3.2` -> `1.3.3`
|
||||||
|
|
||||||
|
## 0.10.3
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Compose`: `1.2.0-alpha01-dev682` -> `1.2.0-alpha01-dev683`
|
||||||
|
* `Coroutines`:
|
||||||
|
* Fixes in `AccumulatorFlow`
|
||||||
|
|
||||||
## 0.10.2
|
## 0.10.2
|
||||||
|
|
||||||
* `Versions`:
|
* `Versions`:
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
|
||||||
|
inline val Element.isOverflowWidth
|
||||||
|
get() = scrollWidth > clientWidth
|
||||||
|
|
||||||
|
inline val Element.isOverflowHeight
|
||||||
|
get() = scrollHeight > clientHeight
|
||||||
|
|
||||||
|
inline val Element.isOverflow
|
||||||
|
get() = isOverflowHeight || isOverflowWidth
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
import org.w3c.dom.*
|
||||||
|
import kotlin.js.Json
|
||||||
|
import kotlin.js.json
|
||||||
|
|
||||||
|
external class ResizeObserver(
|
||||||
|
callback: (Array<ResizeObserverEntry>, ResizeObserver) -> Unit
|
||||||
|
) {
|
||||||
|
fun observe(target: Element, options: Json = definedExternally)
|
||||||
|
|
||||||
|
fun unobserve(target: Element)
|
||||||
|
|
||||||
|
fun disconnect()
|
||||||
|
}
|
||||||
|
|
||||||
|
external interface ResizeObserverSize {
|
||||||
|
val blockSize: Float
|
||||||
|
val inlineSize: Float
|
||||||
|
}
|
||||||
|
|
||||||
|
external interface ResizeObserverEntry {
|
||||||
|
val borderBoxSize: Array<ResizeObserverSize>
|
||||||
|
val contentBoxSize: Array<ResizeObserverSize>
|
||||||
|
val devicePixelContentBoxSize: Array<ResizeObserverSize>
|
||||||
|
val contentRect: DOMRectReadOnly
|
||||||
|
val target: Element
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ResizeObserver.observe(target: Element, options: ResizeObserverObserveOptions) = observe(
|
||||||
|
target,
|
||||||
|
json(
|
||||||
|
"box" to options.box ?.name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
class ResizeObserverObserveOptions(
|
||||||
|
val box: Box? = null
|
||||||
|
) {
|
||||||
|
sealed interface Box {
|
||||||
|
val name: String
|
||||||
|
|
||||||
|
object Content : Box {
|
||||||
|
override val name: String
|
||||||
|
get() = "content-box"
|
||||||
|
}
|
||||||
|
|
||||||
|
object Border : Box {
|
||||||
|
override val name: String
|
||||||
|
get() = "border-box"
|
||||||
|
}
|
||||||
|
|
||||||
|
object DevicePixelContent : Box {
|
||||||
|
override val name: String
|
||||||
|
get() = "device-pixel-content-box"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,11 +6,12 @@ import kotlinx.coroutines.channels.Channel
|
|||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
import kotlin.coroutines.cancellation.CancellationException
|
||||||
|
|
||||||
private sealed interface AccumulatorFlowStep
|
private sealed interface AccumulatorFlowStep<T>
|
||||||
private data class DataRetrievedAccumulatorFlowStep(val data: Any) : AccumulatorFlowStep
|
private data class DataRetrievedAccumulatorFlowStep<T>(val data: T) : AccumulatorFlowStep<T>
|
||||||
private data class SubscribeAccumulatorFlowStep(val channel: Channel<Any>) : AccumulatorFlowStep
|
private data class SubscribeAccumulatorFlowStep<T>(val channel: Channel<T>) : AccumulatorFlowStep<T>
|
||||||
private data class UnsubscribeAccumulatorFlowStep(val channel: Channel<Any>) : AccumulatorFlowStep
|
private data class UnsubscribeAccumulatorFlowStep<T>(val channel: Channel<T>) : AccumulatorFlowStep<T>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This [Flow] will have behaviour very similar to [SharedFlow], but there are several differences:
|
* This [Flow] will have behaviour very similar to [SharedFlow], but there are several differences:
|
||||||
@@ -26,12 +27,12 @@ class AccumulatorFlow<T>(
|
|||||||
private val subscope = scope.LinkedSupervisorScope()
|
private val subscope = scope.LinkedSupervisorScope()
|
||||||
private val activeData = ArrayDeque<T>()
|
private val activeData = ArrayDeque<T>()
|
||||||
private val dataMutex = Mutex()
|
private val dataMutex = Mutex()
|
||||||
private val channelsForBroadcast = mutableListOf<Channel<Any>>()
|
private val channelsForBroadcast = mutableListOf<Channel<T>>()
|
||||||
private val channelsMutex = Mutex()
|
private val channelsMutex = Mutex()
|
||||||
private val steps = subscope.actor<AccumulatorFlowStep> { step ->
|
private val steps = subscope.actor<AccumulatorFlowStep<T>> { step ->
|
||||||
when (step) {
|
when (step) {
|
||||||
is DataRetrievedAccumulatorFlowStep -> {
|
is DataRetrievedAccumulatorFlowStep -> {
|
||||||
if (activeData.first() === step.data) {
|
if (activeData.firstOrNull() === step.data) {
|
||||||
dataMutex.withLock {
|
dataMutex.withLock {
|
||||||
activeData.removeFirst()
|
activeData.removeFirst()
|
||||||
}
|
}
|
||||||
@@ -42,7 +43,7 @@ class AccumulatorFlow<T>(
|
|||||||
dataMutex.withLock {
|
dataMutex.withLock {
|
||||||
val dataToSend = activeData.toList()
|
val dataToSend = activeData.toList()
|
||||||
safelyWithoutExceptions {
|
safelyWithoutExceptions {
|
||||||
dataToSend.forEach { step.channel.send(it as Any) }
|
dataToSend.forEach { step.channel.send(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,24 +59,29 @@ class AccumulatorFlow<T>(
|
|||||||
channelsMutex.withLock {
|
channelsMutex.withLock {
|
||||||
channelsForBroadcast.forEach { channel ->
|
channelsForBroadcast.forEach { channel ->
|
||||||
safelyWithResult {
|
safelyWithResult {
|
||||||
channel.send(it as Any)
|
channel.send(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun collectSafely(collector: FlowCollector<T>) {
|
override suspend fun collectSafely(collector: FlowCollector<T>) {
|
||||||
val channel = Channel<Any>(Channel.UNLIMITED, BufferOverflow.SUSPEND)
|
val channel = Channel<T>(Channel.UNLIMITED, BufferOverflow.SUSPEND)
|
||||||
steps.send(SubscribeAccumulatorFlowStep(channel))
|
steps.send(SubscribeAccumulatorFlowStep(channel))
|
||||||
for (data in channel) {
|
val result = runCatchingSafely {
|
||||||
try {
|
for (data in channel) {
|
||||||
collector.emit(data as T)
|
val emitResult = runCatchingSafely {
|
||||||
steps.send(DataRetrievedAccumulatorFlowStep(data))
|
collector.emit(data)
|
||||||
} finally {
|
}
|
||||||
channel.cancel()
|
if (emitResult.isSuccess || emitResult.exceptionOrNull() is CancellationException) {
|
||||||
steps.send(UnsubscribeAccumulatorFlowStep(channel))
|
steps.send(DataRetrievedAccumulatorFlowStep(data))
|
||||||
|
}
|
||||||
|
emitResult.getOrThrow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
channel.cancel()
|
||||||
|
steps.send(UnsubscribeAccumulatorFlowStep(channel))
|
||||||
|
result.getOrThrow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package dev.inmo.micro_utils.fsm.common
|
|||||||
import dev.inmo.micro_utils.common.Optional
|
import dev.inmo.micro_utils.common.Optional
|
||||||
import dev.inmo.micro_utils.common.onPresented
|
import dev.inmo.micro_utils.common.onPresented
|
||||||
import dev.inmo.micro_utils.coroutines.*
|
import dev.inmo.micro_utils.coroutines.*
|
||||||
|
import dev.inmo.micro_utils.fsm.common.utils.StateHandlingErrorHandler
|
||||||
|
import dev.inmo.micro_utils.fsm.common.utils.defaultStateHandlingErrorHandler
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
@@ -13,13 +15,24 @@ import kotlinx.coroutines.sync.withLock
|
|||||||
* handling until [start] method will be called
|
* handling until [start] method will be called
|
||||||
*/
|
*/
|
||||||
interface StatesMachine<T : State> : StatesHandler<T, T> {
|
interface StatesMachine<T : State> : StatesHandler<T, T> {
|
||||||
|
suspend fun launchStateHandling(
|
||||||
|
state: T,
|
||||||
|
handlers: List<CheckableHandlerHolder<in T, T>>,
|
||||||
|
onStateHandlingErrorHandler: StateHandlingErrorHandler<T>
|
||||||
|
): T? {
|
||||||
|
return runCatchingSafely {
|
||||||
|
handlers.firstOrNull { it.checkHandleable(state) } ?.run {
|
||||||
|
handleState(state)
|
||||||
|
}
|
||||||
|
}.getOrElse {
|
||||||
|
onStateHandlingErrorHandler(state, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
suspend fun launchStateHandling(
|
suspend fun launchStateHandling(
|
||||||
state: T,
|
state: T,
|
||||||
handlers: List<CheckableHandlerHolder<in T, T>>
|
handlers: List<CheckableHandlerHolder<in T, T>>
|
||||||
): T? {
|
): T? {
|
||||||
return handlers.firstOrNull { it.checkHandleable(state) } ?.run {
|
return launchStateHandling(state, handlers, defaultStateHandlingErrorHandler())
|
||||||
handleState(state)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,8 +51,9 @@ interface StatesMachine<T : State> : StatesHandler<T, T> {
|
|||||||
*/
|
*/
|
||||||
operator fun <T: State> invoke(
|
operator fun <T: State> invoke(
|
||||||
statesManager: StatesManager<T>,
|
statesManager: StatesManager<T>,
|
||||||
handlers: List<CheckableHandlerHolder<in T, T>>
|
handlers: List<CheckableHandlerHolder<in T, T>>,
|
||||||
) = DefaultStatesMachine(statesManager, handlers)
|
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler()
|
||||||
|
) = DefaultStatesMachine(statesManager, handlers, onStateHandlingErrorHandler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,12 +66,17 @@ interface StatesMachine<T : State> : StatesHandler<T, T> {
|
|||||||
open class DefaultStatesMachine <T: State>(
|
open class DefaultStatesMachine <T: State>(
|
||||||
protected val statesManager: StatesManager<T>,
|
protected val statesManager: StatesManager<T>,
|
||||||
protected val handlers: List<CheckableHandlerHolder<in T, T>>,
|
protected val handlers: List<CheckableHandlerHolder<in T, T>>,
|
||||||
|
protected val onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler()
|
||||||
) : StatesMachine<T> {
|
) : StatesMachine<T> {
|
||||||
/**
|
/**
|
||||||
* Will call [launchStateHandling] for state handling
|
* Will call [launchStateHandling] for state handling
|
||||||
*/
|
*/
|
||||||
override suspend fun StatesMachine<in T>.handleState(state: T): T? = launchStateHandling(state, handlers)
|
override suspend fun StatesMachine<in T>.handleState(state: T): T? = launchStateHandling(state, handlers)
|
||||||
|
|
||||||
|
override suspend fun launchStateHandling(state: T, handlers: List<CheckableHandlerHolder<in T, T>>): T? {
|
||||||
|
return launchStateHandling(state, handlers, onStateHandlingErrorHandler)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This
|
* This
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package dev.inmo.micro_utils.fsm.common
|
package dev.inmo.micro_utils.fsm.common
|
||||||
|
|
||||||
import dev.inmo.micro_utils.common.*
|
import dev.inmo.micro_utils.common.*
|
||||||
|
import dev.inmo.micro_utils.fsm.common.utils.StateHandlingErrorHandler
|
||||||
|
import dev.inmo.micro_utils.fsm.common.utils.defaultStateHandlingErrorHandler
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
|
||||||
@@ -20,9 +22,11 @@ interface UpdatableStatesMachine<T : State> : StatesMachine<T> {
|
|||||||
open class DefaultUpdatableStatesMachine<T : State>(
|
open class DefaultUpdatableStatesMachine<T : State>(
|
||||||
statesManager: StatesManager<T>,
|
statesManager: StatesManager<T>,
|
||||||
handlers: List<CheckableHandlerHolder<in T, T>>,
|
handlers: List<CheckableHandlerHolder<in T, T>>,
|
||||||
|
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler()
|
||||||
) : DefaultStatesMachine<T>(
|
) : DefaultStatesMachine<T>(
|
||||||
statesManager,
|
statesManager,
|
||||||
handlers
|
handlers,
|
||||||
|
onStateHandlingErrorHandler
|
||||||
), UpdatableStatesMachine<T> {
|
), UpdatableStatesMachine<T> {
|
||||||
protected val jobsStates = mutableMapOf<Job, T>()
|
protected val jobsStates = mutableMapOf<Job, T>()
|
||||||
|
|
||||||
@@ -34,7 +38,7 @@ open class DefaultUpdatableStatesMachine<T : State>(
|
|||||||
*/
|
*/
|
||||||
override suspend fun performStateUpdate(previousState: Optional<T>, actualState: T, scope: CoroutineScope) {
|
override suspend fun performStateUpdate(previousState: Optional<T>, actualState: T, scope: CoroutineScope) {
|
||||||
statesJobsMutex.withLock {
|
statesJobsMutex.withLock {
|
||||||
if (compare(previousState, actualState)) {
|
if (shouldReplaceJob(previousState, actualState)) {
|
||||||
statesJobs[actualState] ?.cancel()
|
statesJobs[actualState] ?.cancel()
|
||||||
}
|
}
|
||||||
val job = previousState.mapOnPresented {
|
val job = previousState.mapOnPresented {
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package dev.inmo.micro_utils.fsm.common.utils
|
||||||
|
|
||||||
|
typealias StateHandlingErrorHandler<T> = suspend (T, Throwable) -> T?
|
||||||
|
val DefaultStateHandlingErrorHandler: StateHandlingErrorHandler<*> = { _, _ -> null }
|
||||||
|
inline fun <T> defaultStateHandlingErrorHandler(): StateHandlingErrorHandler<T> = DefaultStateHandlingErrorHandler as StateHandlingErrorHandler<T>
|
||||||
|
|
||||||
@@ -14,5 +14,5 @@ crypto_js_version=4.1.1
|
|||||||
# Project data
|
# Project data
|
||||||
|
|
||||||
group=dev.inmo
|
group=dev.inmo
|
||||||
version=0.10.2
|
version=0.11.0
|
||||||
android_code_version=117
|
android_code_version=124
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
[versions]
|
[versions]
|
||||||
|
|
||||||
kt = "1.6.21"
|
kt = "1.6.21"
|
||||||
kt-serialization = "1.3.2"
|
kt-serialization = "1.3.3"
|
||||||
kt-coroutines = "1.6.1"
|
kt-coroutines = "1.6.1"
|
||||||
|
|
||||||
jb-compose = "1.2.0-alpha01-dev682"
|
jb-compose = "1.2.0-alpha01-dev686"
|
||||||
jb-exposed = "0.38.2"
|
jb-exposed = "0.38.2"
|
||||||
jb-dokka = "1.6.21"
|
jb-dokka = "1.6.21"
|
||||||
|
|
||||||
klock = "2.7.0"
|
klock = "2.7.0"
|
||||||
uuid = "0.4.0"
|
uuid = "0.4.0"
|
||||||
|
|
||||||
ktor = "2.0.1"
|
ktor = "2.0.2"
|
||||||
|
|
||||||
gh-release = "2.3.7"
|
gh-release = "2.3.7"
|
||||||
|
|
||||||
android-gradle = "7.0.4"
|
android-gradle = "7.0.4"
|
||||||
dexcount = "3.0.1"
|
dexcount = "3.1.0"
|
||||||
|
|
||||||
android-coreKtx = "1.7.0"
|
android-coreKtx = "1.7.0"
|
||||||
android-recyclerView = "1.2.1"
|
android-recyclerView = "1.2.1"
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package dev.inmo.micro_utils.ktor.client
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
||||||
|
import dev.inmo.micro_utils.coroutines.safely
|
||||||
|
import dev.inmo.micro_utils.ktor.common.*
|
||||||
|
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 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 <T> HttpClient.createStandardWebsocketFlow(
|
||||||
|
url: String,
|
||||||
|
crossinline checkReconnection: suspend (Throwable?) -> Boolean = { true },
|
||||||
|
noinline requestBuilder: HttpRequestBuilder.() -> 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkReconnection(null)
|
||||||
|
}.getOrElse { e ->
|
||||||
|
checkReconnection(e).also {
|
||||||
|
if (!it) {
|
||||||
|
close(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (reconnect && isActive)
|
||||||
|
|
||||||
|
if (isActive) {
|
||||||
|
safely {
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package dev.inmo.micro_utils.ktor.server
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.coroutines.safely
|
||||||
|
import dev.inmo.micro_utils.ktor.common.*
|
||||||
|
import io.ktor.http.URLProtocol
|
||||||
|
import io.ktor.server.application.install
|
||||||
|
import io.ktor.server.application.pluginOrNull
|
||||||
|
import io.ktor.server.routing.Route
|
||||||
|
import io.ktor.server.routing.application
|
||||||
|
import io.ktor.server.websocket.*
|
||||||
|
import io.ktor.websocket.send
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.serialization.SerializationStrategy
|
||||||
|
|
||||||
|
inline fun <reified T : Any> Route.includeWebsocketHandling(
|
||||||
|
suburl: String,
|
||||||
|
flow: Flow<T>,
|
||||||
|
protocol: URLProtocol? = null
|
||||||
|
) {
|
||||||
|
application.apply {
|
||||||
|
pluginOrNull(WebSockets) ?: install(WebSockets)
|
||||||
|
}
|
||||||
|
webSocket(suburl, protocol ?.name) {
|
||||||
|
safely {
|
||||||
|
flow.collect {
|
||||||
|
sendSerialized(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,19 +2,19 @@ package dev.inmo.micro_utils.pagination.utils
|
|||||||
|
|
||||||
import dev.inmo.micro_utils.pagination.*
|
import dev.inmo.micro_utils.pagination.*
|
||||||
|
|
||||||
suspend fun <T> doForAll(
|
inline fun <T> doForAll(
|
||||||
initialPagination: Pagination = FirstPagePagination(),
|
initialPagination: Pagination = FirstPagePagination(),
|
||||||
paginationMapper: (PaginationResult<T>) -> Pagination?,
|
paginationMapper: (PaginationResult<T>) -> Pagination?,
|
||||||
block: suspend (Pagination) -> PaginationResult<T>
|
block: (Pagination) -> PaginationResult<T>
|
||||||
) {
|
) {
|
||||||
doWithPagination(initialPagination) {
|
doWithPagination(initialPagination) {
|
||||||
block(it).let(paginationMapper)
|
block(it).let(paginationMapper)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun <T> doForAllWithNextPaging(
|
inline fun <T> doForAllWithNextPaging(
|
||||||
initialPagination: Pagination = FirstPagePagination(),
|
initialPagination: Pagination = FirstPagePagination(),
|
||||||
block: suspend (Pagination) -> PaginationResult<T>
|
block: (Pagination) -> PaginationResult<T>
|
||||||
) {
|
) {
|
||||||
doForAll(
|
doForAll(
|
||||||
initialPagination,
|
initialPagination,
|
||||||
@@ -23,9 +23,9 @@ suspend fun <T> doForAllWithNextPaging(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun <T> doAllWithCurrentPaging(
|
inline fun <T> doAllWithCurrentPaging(
|
||||||
initialPagination: Pagination = FirstPagePagination(),
|
initialPagination: Pagination = FirstPagePagination(),
|
||||||
block: suspend (Pagination) -> PaginationResult<T>
|
block: (Pagination) -> PaginationResult<T>
|
||||||
) {
|
) {
|
||||||
doForAll(
|
doForAll(
|
||||||
initialPagination,
|
initialPagination,
|
||||||
@@ -34,7 +34,7 @@ suspend fun <T> doAllWithCurrentPaging(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun <T> doForAllWithCurrentPaging(
|
inline fun <T> doForAllWithCurrentPaging(
|
||||||
initialPagination: Pagination = FirstPagePagination(),
|
initialPagination: Pagination = FirstPagePagination(),
|
||||||
block: suspend (Pagination) -> PaginationResult<T>
|
block: (Pagination) -> PaginationResult<T>
|
||||||
) = doAllWithCurrentPaging(initialPagination, block)
|
) = doAllWithCurrentPaging(initialPagination, block)
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package dev.inmo.micro_utils.pagination.utils
|
|||||||
|
|
||||||
import dev.inmo.micro_utils.pagination.*
|
import dev.inmo.micro_utils.pagination.*
|
||||||
|
|
||||||
suspend fun <T> getAll(
|
inline fun <T> getAll(
|
||||||
initialPagination: Pagination = FirstPagePagination(),
|
initialPagination: Pagination = FirstPagePagination(),
|
||||||
paginationMapper: (PaginationResult<T>) -> Pagination?,
|
paginationMapper: (PaginationResult<T>) -> Pagination?,
|
||||||
block: suspend (Pagination) -> PaginationResult<T>
|
block: (Pagination) -> PaginationResult<T>
|
||||||
): List<T> {
|
): List<T> {
|
||||||
val results = mutableListOf<T>()
|
val results = mutableListOf<T>()
|
||||||
doForAll(initialPagination, paginationMapper) {
|
doForAll(initialPagination, paginationMapper) {
|
||||||
@@ -16,46 +16,45 @@ suspend fun <T> getAll(
|
|||||||
return results.toList()
|
return results.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun <T, R> R.getAllBy(
|
inline fun <T, R> R.getAllBy(
|
||||||
initialPagination: Pagination = FirstPagePagination(),
|
initialPagination: Pagination = FirstPagePagination(),
|
||||||
paginationMapper: R.(PaginationResult<T>) -> Pagination?,
|
paginationMapper: R.(PaginationResult<T>) -> Pagination?,
|
||||||
block: suspend R.(Pagination) -> PaginationResult<T>
|
block: R.(Pagination) -> PaginationResult<T>
|
||||||
): List<T> = getAll(
|
): List<T> = getAll(
|
||||||
initialPagination,
|
initialPagination,
|
||||||
{ paginationMapper(it) },
|
{ paginationMapper(it) },
|
||||||
{ block(it) }
|
{ block(it) }
|
||||||
)
|
)
|
||||||
|
|
||||||
suspend fun <T> getAllWithNextPaging(
|
inline fun <T> getAllWithNextPaging(
|
||||||
initialPagination: Pagination = FirstPagePagination(),
|
initialPagination: Pagination = FirstPagePagination(),
|
||||||
block: suspend (Pagination) -> PaginationResult<T>
|
block: (Pagination) -> PaginationResult<T>
|
||||||
): List<T> = getAll(
|
): List<T> = getAll(
|
||||||
initialPagination,
|
initialPagination,
|
||||||
{ it.nextPageIfNotEmpty() },
|
{ it.nextPageIfNotEmpty() },
|
||||||
block
|
block
|
||||||
)
|
)
|
||||||
|
|
||||||
suspend fun <T, R> R.getAllByWithNextPaging(
|
inline fun <T, R> R.getAllByWithNextPaging(
|
||||||
initialPagination: Pagination = FirstPagePagination(),
|
initialPagination: Pagination = FirstPagePagination(),
|
||||||
block: suspend R.(Pagination) -> PaginationResult<T>
|
block: R.(Pagination) -> PaginationResult<T>
|
||||||
): List<T> = getAllWithNextPaging(
|
): List<T> = getAllWithNextPaging(
|
||||||
initialPagination,
|
initialPagination,
|
||||||
{ block(it) }
|
{ block(it) }
|
||||||
)
|
)
|
||||||
|
|
||||||
suspend fun <T> getAllWithCurrentPaging(
|
inline fun <T> getAllWithCurrentPaging(
|
||||||
initialPagination: Pagination = FirstPagePagination(),
|
initialPagination: Pagination = FirstPagePagination(),
|
||||||
block: suspend (Pagination) -> PaginationResult<T>
|
block: (Pagination) -> PaginationResult<T>
|
||||||
): List<T> = getAll(
|
): List<T> = getAll(
|
||||||
initialPagination,
|
initialPagination,
|
||||||
{ it.currentPageIfNotEmpty() },
|
{ it.currentPageIfNotEmpty() },
|
||||||
block
|
block
|
||||||
)
|
)
|
||||||
|
|
||||||
suspend fun <T, R> R.getAllByWithCurrentPaging(
|
inline fun <T, R> R.getAllByWithCurrentPaging(
|
||||||
initialPagination: Pagination = FirstPagePagination(),
|
initialPagination: Pagination = FirstPagePagination(),
|
||||||
block: suspend R.(Pagination) -> PaginationResult<T>
|
block: R.(Pagination) -> PaginationResult<T>
|
||||||
): List<T> = getAllWithCurrentPaging(
|
): List<T> = getAllWithCurrentPaging(
|
||||||
initialPagination,
|
initialPagination
|
||||||
{ block(it) }
|
) { block(it) }
|
||||||
)
|
|
||||||
|
|||||||
@@ -160,3 +160,9 @@ class KeyValueStore<T : Any> internal constructor (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun <T : Any> SharedPreferencesKeyValueRepo(
|
||||||
|
context: Context,
|
||||||
|
name: String = "default",
|
||||||
|
cacheValues: Boolean = false
|
||||||
|
) = context.keyValueStore<T>(name, cacheValues)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import io.ktor.client.HttpClient
|
|||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
import kotlinx.serialization.builtins.serializer
|
import kotlinx.serialization.builtins.serializer
|
||||||
|
|
||||||
|
@Deprecated("Use KtorReadStandardCrudRepoClient instead")
|
||||||
class KtorReadStandardCrudRepo<ObjectType, IdType> (
|
class KtorReadStandardCrudRepo<ObjectType, IdType> (
|
||||||
private val baseUrl: String,
|
private val baseUrl: String,
|
||||||
private val unifiedRequester: UnifiedRequester,
|
private val unifiedRequester: UnifiedRequester,
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.ktor.client.crud
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.ktor.common.*
|
||||||
|
import dev.inmo.micro_utils.pagination.*
|
||||||
|
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
||||||
|
import io.ktor.client.HttpClient
|
||||||
|
import io.ktor.client.call.body
|
||||||
|
import io.ktor.client.request.get
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
|
import io.ktor.util.reflect.TypeInfo
|
||||||
|
import io.ktor.util.reflect.typeInfo
|
||||||
|
import kotlinx.serialization.*
|
||||||
|
|
||||||
|
class KtorReadStandardCrudRepoClient<ObjectType, IdType> (
|
||||||
|
private val baseUrl: String,
|
||||||
|
private val httpClient: HttpClient,
|
||||||
|
private val objectType: TypeInfo,
|
||||||
|
private val idSerializer: suspend (IdType) -> String
|
||||||
|
) : ReadStandardCRUDRepo<ObjectType, IdType> {
|
||||||
|
override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> = httpClient.get(
|
||||||
|
buildStandardUrl(baseUrl, getByPaginationRouting, pagination.asUrlQueryParts)
|
||||||
|
).body()
|
||||||
|
|
||||||
|
override suspend fun getById(id: IdType): ObjectType? = httpClient.get(
|
||||||
|
buildStandardUrl(
|
||||||
|
baseUrl,
|
||||||
|
getByIdRouting,
|
||||||
|
mapOf(
|
||||||
|
"id" to idSerializer(id)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).takeIf { it.status != HttpStatusCode.NoContent } ?.body<ObjectType>(objectType)
|
||||||
|
|
||||||
|
override suspend fun contains(id: IdType): Boolean = httpClient.get(
|
||||||
|
buildStandardUrl(
|
||||||
|
baseUrl,
|
||||||
|
containsRouting,
|
||||||
|
mapOf(
|
||||||
|
"id" to idSerializer(id)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).body()
|
||||||
|
|
||||||
|
override suspend fun count(): Long = httpClient.get(
|
||||||
|
buildStandardUrl(
|
||||||
|
baseUrl,
|
||||||
|
countRouting
|
||||||
|
)
|
||||||
|
).body()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified ObjectType, IdType> KtorReadStandardCrudRepoClient(
|
||||||
|
baseUrl: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
noinline idSerializer: suspend (IdType) -> String
|
||||||
|
) = KtorReadStandardCrudRepoClient<ObjectType, IdType>(
|
||||||
|
baseUrl,
|
||||||
|
httpClient,
|
||||||
|
typeInfo<ObjectType>(),
|
||||||
|
idSerializer
|
||||||
|
)
|
||||||
|
|
||||||
|
inline fun <reified ObjectType, IdType> KtorReadStandardCrudRepoClient(
|
||||||
|
baseUrl: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
idsSerializer: KSerializer<IdType>,
|
||||||
|
serialFormat: StringFormat
|
||||||
|
) = KtorReadStandardCrudRepoClient<ObjectType, IdType>(baseUrl, httpClient) {
|
||||||
|
serialFormat.encodeToString(idsSerializer, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified ObjectType, IdType> KtorReadStandardCrudRepoClient(
|
||||||
|
baseUrl: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
idsSerializer: KSerializer<IdType>,
|
||||||
|
serialFormat: BinaryFormat
|
||||||
|
) = KtorReadStandardCrudRepoClient<ObjectType, IdType>(baseUrl, httpClient) {
|
||||||
|
serialFormat.encodeHex(idsSerializer, it)
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import dev.inmo.micro_utils.repos.*
|
|||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
|
|
||||||
|
@Deprecated("Use KtorStandardCrudRepoClient instead")
|
||||||
class KtorStandardCrudRepo<ObjectType, IdType, InputValue> (
|
class KtorStandardCrudRepo<ObjectType, IdType, InputValue> (
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
baseSubpart: String,
|
baseSubpart: String,
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.ktor.client.crud
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.ktor.common.*
|
||||||
|
import dev.inmo.micro_utils.repos.*
|
||||||
|
import io.ktor.client.HttpClient
|
||||||
|
import io.ktor.util.reflect.TypeInfo
|
||||||
|
import io.ktor.util.reflect.typeInfo
|
||||||
|
import kotlinx.serialization.*
|
||||||
|
|
||||||
|
class KtorStandardCrudRepoClient<ObjectType, IdType, InputValue> (
|
||||||
|
baseUrl: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
objectTypeInfo: TypeInfo,
|
||||||
|
idSerializer: suspend (IdType) -> String
|
||||||
|
) : StandardCRUDRepo<ObjectType, IdType, InputValue>,
|
||||||
|
ReadStandardCRUDRepo<ObjectType, IdType> by KtorReadStandardCrudRepoClient(
|
||||||
|
baseUrl,
|
||||||
|
httpClient,
|
||||||
|
objectTypeInfo,
|
||||||
|
idSerializer
|
||||||
|
),
|
||||||
|
WriteStandardCRUDRepo<ObjectType, IdType, InputValue> by KtorWriteStandardCrudRepoClient(
|
||||||
|
baseUrl,
|
||||||
|
httpClient
|
||||||
|
) {
|
||||||
|
constructor(
|
||||||
|
baseUrl: String,
|
||||||
|
subpart: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
objectTypeInfo: TypeInfo,
|
||||||
|
idSerializer: suspend (IdType) -> String
|
||||||
|
) : this(
|
||||||
|
buildStandardUrl(baseUrl, subpart), httpClient, objectTypeInfo, idSerializer
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline fun <reified ObjectType, IdType, InputValue> KtorStandardCrudRepoClient(
|
||||||
|
baseUrl: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
noinline idSerializer: suspend (IdType) -> String
|
||||||
|
) = KtorStandardCrudRepoClient<ObjectType, IdType, InputValue>(
|
||||||
|
baseUrl,
|
||||||
|
httpClient,
|
||||||
|
typeInfo<ObjectType>(),
|
||||||
|
idSerializer
|
||||||
|
)
|
||||||
|
|
||||||
|
inline fun <reified ObjectType, IdType, InputValue> KtorStandardCrudRepoClient(
|
||||||
|
baseUrl: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
idsSerializer: KSerializer<IdType>,
|
||||||
|
serialFormat: StringFormat
|
||||||
|
) = KtorStandardCrudRepoClient<ObjectType, IdType, InputValue>(baseUrl, httpClient) {
|
||||||
|
serialFormat.encodeToString(idsSerializer, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified ObjectType, IdType, InputValue> KtorStandardCrudRepoClient(
|
||||||
|
baseUrl: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
idsSerializer: KSerializer<IdType>,
|
||||||
|
serialFormat: BinaryFormat
|
||||||
|
) = KtorStandardCrudRepoClient<ObjectType, IdType, InputValue>(baseUrl, httpClient) {
|
||||||
|
serialFormat.encodeHex(idsSerializer, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline fun <reified ObjectType, IdType, InputValue> KtorStandardCrudRepoClient(
|
||||||
|
baseUrl: String,
|
||||||
|
subpart: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
noinline idSerializer: suspend (IdType) -> String
|
||||||
|
) = KtorStandardCrudRepoClient<ObjectType, IdType, InputValue>(
|
||||||
|
buildStandardUrl(baseUrl, subpart),
|
||||||
|
httpClient,
|
||||||
|
idSerializer
|
||||||
|
)
|
||||||
|
|
||||||
|
inline fun <reified ObjectType, IdType, InputValue> KtorStandardCrudRepoClient(
|
||||||
|
baseUrl: String,
|
||||||
|
subpart: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
idsSerializer: KSerializer<IdType>,
|
||||||
|
serialFormat: StringFormat
|
||||||
|
) = KtorStandardCrudRepoClient<ObjectType, IdType, InputValue>(buildStandardUrl(baseUrl, subpart), httpClient, idsSerializer, serialFormat)
|
||||||
|
|
||||||
|
inline fun <reified ObjectType, IdType, InputValue> KtorStandardCrudRepoClient(
|
||||||
|
baseUrl: String,
|
||||||
|
subpart: String,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
idsSerializer: KSerializer<IdType>,
|
||||||
|
serialFormat: BinaryFormat
|
||||||
|
) = KtorStandardCrudRepoClient<ObjectType, IdType, InputValue>(buildStandardUrl(baseUrl, subpart), httpClient, idsSerializer, serialFormat)
|
||||||
@@ -10,6 +10,7 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
import kotlinx.serialization.builtins.*
|
import kotlinx.serialization.builtins.*
|
||||||
|
|
||||||
|
@Deprecated("Use KtorWriteStandardCrudRepoClient instead")
|
||||||
class KtorWriteStandardCrudRepo<ObjectType, IdType, InputValue> (
|
class KtorWriteStandardCrudRepo<ObjectType, IdType, InputValue> (
|
||||||
private val baseUrl: String,
|
private val baseUrl: String,
|
||||||
private val unifiedRequester: UnifiedRequester,
|
private val unifiedRequester: UnifiedRequester,
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.ktor.client.crud
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.ktor.client.*
|
||||||
|
import dev.inmo.micro_utils.ktor.common.*
|
||||||
|
import dev.inmo.micro_utils.repos.UpdatedValuePair
|
||||||
|
import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
||||||
|
import io.ktor.client.HttpClient
|
||||||
|
import io.ktor.client.call.body
|
||||||
|
import io.ktor.client.request.*
|
||||||
|
import io.ktor.util.reflect.TypeInfo
|
||||||
|
import io.ktor.util.reflect.typeInfo
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.builtins.*
|
||||||
|
|
||||||
|
class KtorWriteStandardCrudRepoClient<ObjectType, IdType, InputValue> (
|
||||||
|
private val baseUrl: String,
|
||||||
|
private val httpClient: HttpClient
|
||||||
|
) : WriteStandardCRUDRepo<ObjectType, IdType, InputValue> {
|
||||||
|
|
||||||
|
override val newObjectsFlow: Flow<ObjectType> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, newObjectsFlowRouting),
|
||||||
|
)
|
||||||
|
override val updatedObjectsFlow: Flow<ObjectType> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, updatedObjectsFlowRouting)
|
||||||
|
)
|
||||||
|
override val deletedObjectsIdsFlow: Flow<IdType> = httpClient.createStandardWebsocketFlow(
|
||||||
|
buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
override suspend fun create(values: List<InputValue>): List<ObjectType> = httpClient.post {
|
||||||
|
url(buildStandardUrl(baseUrl, createRouting))
|
||||||
|
setBody(values)
|
||||||
|
}.body()
|
||||||
|
|
||||||
|
override suspend fun update(values: List<UpdatedValuePair<IdType, InputValue>>): List<ObjectType> = httpClient.post {
|
||||||
|
url(buildStandardUrl(baseUrl, updateManyRouting))
|
||||||
|
setBody(values)
|
||||||
|
}.body()
|
||||||
|
|
||||||
|
override suspend fun update(id: IdType, value: InputValue): ObjectType? = update(listOf(id to value)).firstOrNull()
|
||||||
|
|
||||||
|
override suspend fun deleteById(ids: List<IdType>) {
|
||||||
|
httpClient.post {
|
||||||
|
url(buildStandardUrl(baseUrl, deleteByIdRouting))
|
||||||
|
setBody(ids)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.ktor.server.crud
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.ktor.common.decodeHex
|
||||||
|
import dev.inmo.micro_utils.ktor.server.*
|
||||||
|
import dev.inmo.micro_utils.pagination.extractPagination
|
||||||
|
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
||||||
|
import io.ktor.http.ContentType
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
|
import io.ktor.server.application.call
|
||||||
|
import io.ktor.server.response.respond
|
||||||
|
import io.ktor.server.routing.Route
|
||||||
|
import io.ktor.server.routing.get
|
||||||
|
import kotlinx.serialization.*
|
||||||
|
|
||||||
|
inline fun <reified ObjectType, reified IdType> Route.configureReadStandardCrudRepoRoutes(
|
||||||
|
originalRepo: ReadStandardCRUDRepo<ObjectType, IdType>,
|
||||||
|
noinline idDeserializer: suspend (String) -> IdType
|
||||||
|
) {
|
||||||
|
get(getByPaginationRouting) {
|
||||||
|
val pagination = call.request.queryParameters.extractPagination
|
||||||
|
|
||||||
|
call.respond(originalRepo.getByPagination(pagination))
|
||||||
|
}
|
||||||
|
|
||||||
|
get(getByIdRouting) {
|
||||||
|
val id = idDeserializer(
|
||||||
|
call.getQueryParameterOrSendError("id") ?: return@get
|
||||||
|
)
|
||||||
|
|
||||||
|
val result = originalRepo.getById(id)
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
call.respond(HttpStatusCode.NoContent)
|
||||||
|
} else {
|
||||||
|
call.respond(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get(containsRouting) {
|
||||||
|
val id = idDeserializer(
|
||||||
|
call.getQueryParameterOrSendError("id") ?: return@get
|
||||||
|
)
|
||||||
|
|
||||||
|
call.respond(
|
||||||
|
originalRepo.contains(id)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
get(countRouting) {
|
||||||
|
call.respond(
|
||||||
|
originalRepo.count()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified ObjectType, reified IdType> Route.configureReadStandardCrudRepoRoutes(
|
||||||
|
originalRepo: ReadStandardCRUDRepo<ObjectType, IdType>,
|
||||||
|
idsSerializer: KSerializer<IdType>,
|
||||||
|
serialFormat: StringFormat
|
||||||
|
) = configureReadStandardCrudRepoRoutes(originalRepo) {
|
||||||
|
serialFormat.decodeFromString(idsSerializer, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified ObjectType, reified IdType> Route.configureReadStandardCrudRepoRoutes(
|
||||||
|
originalRepo: ReadStandardCRUDRepo<ObjectType, IdType>,
|
||||||
|
idsSerializer: KSerializer<IdType>,
|
||||||
|
serialFormat: BinaryFormat
|
||||||
|
) = configureReadStandardCrudRepoRoutes(originalRepo) {
|
||||||
|
serialFormat.decodeHex(idsSerializer, it)
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.ktor.server.crud
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.ktor.common.*
|
||||||
|
import dev.inmo.micro_utils.ktor.server.UnifiedRouter
|
||||||
|
import dev.inmo.micro_utils.ktor.server.standardKtorSerialFormatContentType
|
||||||
|
import dev.inmo.micro_utils.repos.StandardCRUDRepo
|
||||||
|
import io.ktor.http.ContentType
|
||||||
|
import io.ktor.server.routing.Route
|
||||||
|
import io.ktor.server.routing.route
|
||||||
|
import kotlinx.serialization.*
|
||||||
|
|
||||||
|
inline fun <reified ObjectType : Any, reified IdType : Any, reified InputValue : Any> Route.configureStandardCrudRepoRoutes(
|
||||||
|
originalRepo: StandardCRUDRepo<ObjectType, IdType, InputValue>,
|
||||||
|
noinline idDeserializer: suspend (String) -> IdType
|
||||||
|
) {
|
||||||
|
configureReadStandardCrudRepoRoutes(originalRepo, idDeserializer)
|
||||||
|
configureWriteStandardCrudRepoRoutes(originalRepo)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified ObjectType : Any, reified IdType : Any, reified InputValue : Any> Route.configureStandardCrudRepoRoutes(
|
||||||
|
originalRepo: StandardCRUDRepo<ObjectType, IdType, InputValue>,
|
||||||
|
idsSerializer: KSerializer<IdType>,
|
||||||
|
serialFormat: StringFormat
|
||||||
|
) = configureStandardCrudRepoRoutes(originalRepo) {
|
||||||
|
serialFormat.decodeFromString(idsSerializer, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified ObjectType : Any, reified IdType : Any, reified InputValue : Any> Route.configureStandardCrudRepoRoutes(
|
||||||
|
originalRepo: StandardCRUDRepo<ObjectType, IdType, InputValue>,
|
||||||
|
idsSerializer: KSerializer<IdType>,
|
||||||
|
serialFormat: BinaryFormat
|
||||||
|
) = configureStandardCrudRepoRoutes(originalRepo) {
|
||||||
|
serialFormat.decodeHex(idsSerializer, it)
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.ktor.server.crud
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.ktor.server.*
|
||||||
|
import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo
|
||||||
|
import dev.inmo.micro_utils.repos.ktor.common.crud.*
|
||||||
|
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
|
||||||
|
|
||||||
|
inline fun <reified ObjectType : Any, reified IdType : Any, reified InputValue : Any> Route.configureWriteStandardCrudRepoRoutes(
|
||||||
|
originalRepo: WriteStandardCRUDRepo<ObjectType, IdType, InputValue>
|
||||||
|
) {
|
||||||
|
includeWebsocketHandling(
|
||||||
|
newObjectsFlowRouting,
|
||||||
|
originalRepo.newObjectsFlow,
|
||||||
|
)
|
||||||
|
includeWebsocketHandling(
|
||||||
|
updatedObjectsFlowRouting,
|
||||||
|
originalRepo.updatedObjectsFlow
|
||||||
|
)
|
||||||
|
includeWebsocketHandling(
|
||||||
|
deletedObjectsIdsFlowRouting,
|
||||||
|
originalRepo.deletedObjectsIdsFlow
|
||||||
|
)
|
||||||
|
|
||||||
|
post(createRouting) {
|
||||||
|
call.respond(
|
||||||
|
originalRepo.create(
|
||||||
|
call.receive()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
post(updateManyRouting) {
|
||||||
|
call.respond(originalRepo.update(call.receive()))
|
||||||
|
}
|
||||||
|
|
||||||
|
post(deleteByIdRouting) {
|
||||||
|
call.respond(originalRepo.deleteById(call.receive()))
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user