mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2025-12-19 12:46:03 +00:00
Compare commits
28 Commits
0.10.3
...
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 | |||
| 99dfa97958 |
35
CHANGELOG.md
35
CHANGELOG.md
@@ -1,5 +1,40 @@
|
||||
# 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`:
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package dev.inmo.micro_utils.fsm.common
|
||||
import dev.inmo.micro_utils.common.Optional
|
||||
import dev.inmo.micro_utils.common.onPresented
|
||||
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.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
@@ -13,13 +15,24 @@ import kotlinx.coroutines.sync.withLock
|
||||
* handling until [start] method will be called
|
||||
*/
|
||||
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(
|
||||
state: T,
|
||||
handlers: List<CheckableHandlerHolder<in T, T>>
|
||||
): T? {
|
||||
return handlers.firstOrNull { it.checkHandleable(state) } ?.run {
|
||||
handleState(state)
|
||||
}
|
||||
return launchStateHandling(state, handlers, defaultStateHandlingErrorHandler())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -38,8 +51,9 @@ interface StatesMachine<T : State> : StatesHandler<T, T> {
|
||||
*/
|
||||
operator fun <T: State> invoke(
|
||||
statesManager: StatesManager<T>,
|
||||
handlers: List<CheckableHandlerHolder<in T, T>>
|
||||
) = DefaultStatesMachine(statesManager, handlers)
|
||||
handlers: List<CheckableHandlerHolder<in T, T>>,
|
||||
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler()
|
||||
) = DefaultStatesMachine(statesManager, handlers, onStateHandlingErrorHandler)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,12 +66,17 @@ interface StatesMachine<T : State> : StatesHandler<T, T> {
|
||||
open class DefaultStatesMachine <T: State>(
|
||||
protected val statesManager: StatesManager<T>,
|
||||
protected val handlers: List<CheckableHandlerHolder<in T, T>>,
|
||||
protected val onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler()
|
||||
) : StatesMachine<T> {
|
||||
/**
|
||||
* Will call [launchStateHandling] for state handling
|
||||
*/
|
||||
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
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package dev.inmo.micro_utils.fsm.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.sync.withLock
|
||||
|
||||
@@ -20,9 +22,11 @@ interface UpdatableStatesMachine<T : State> : StatesMachine<T> {
|
||||
open class DefaultUpdatableStatesMachine<T : State>(
|
||||
statesManager: StatesManager<T>,
|
||||
handlers: List<CheckableHandlerHolder<in T, T>>,
|
||||
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler()
|
||||
) : DefaultStatesMachine<T>(
|
||||
statesManager,
|
||||
handlers
|
||||
handlers,
|
||||
onStateHandlingErrorHandler
|
||||
), UpdatableStatesMachine<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) {
|
||||
statesJobsMutex.withLock {
|
||||
if (compare(previousState, actualState)) {
|
||||
if (shouldReplaceJob(previousState, actualState)) {
|
||||
statesJobs[actualState] ?.cancel()
|
||||
}
|
||||
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
|
||||
|
||||
group=dev.inmo
|
||||
version=0.10.3
|
||||
android_code_version=118
|
||||
version=0.11.0
|
||||
android_code_version=124
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
[versions]
|
||||
|
||||
kt = "1.6.21"
|
||||
kt-serialization = "1.3.2"
|
||||
kt-serialization = "1.3.3"
|
||||
kt-coroutines = "1.6.1"
|
||||
|
||||
jb-compose = "1.2.0-alpha01-dev683"
|
||||
jb-compose = "1.2.0-alpha01-dev686"
|
||||
jb-exposed = "0.38.2"
|
||||
jb-dokka = "1.6.21"
|
||||
|
||||
klock = "2.7.0"
|
||||
uuid = "0.4.0"
|
||||
|
||||
ktor = "2.0.1"
|
||||
ktor = "2.0.2"
|
||||
|
||||
gh-release = "2.3.7"
|
||||
|
||||
android-gradle = "7.0.4"
|
||||
dexcount = "3.0.1"
|
||||
dexcount = "3.1.0"
|
||||
|
||||
android-coreKtx = "1.7.0"
|
||||
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.*
|
||||
|
||||
suspend fun <T> doForAll(
|
||||
inline fun <T> doForAll(
|
||||
initialPagination: Pagination = FirstPagePagination(),
|
||||
paginationMapper: (PaginationResult<T>) -> Pagination?,
|
||||
block: suspend (Pagination) -> PaginationResult<T>
|
||||
block: (Pagination) -> PaginationResult<T>
|
||||
) {
|
||||
doWithPagination(initialPagination) {
|
||||
block(it).let(paginationMapper)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun <T> doForAllWithNextPaging(
|
||||
inline fun <T> doForAllWithNextPaging(
|
||||
initialPagination: Pagination = FirstPagePagination(),
|
||||
block: suspend (Pagination) -> PaginationResult<T>
|
||||
block: (Pagination) -> PaginationResult<T>
|
||||
) {
|
||||
doForAll(
|
||||
initialPagination,
|
||||
@@ -23,9 +23,9 @@ suspend fun <T> doForAllWithNextPaging(
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun <T> doAllWithCurrentPaging(
|
||||
inline fun <T> doAllWithCurrentPaging(
|
||||
initialPagination: Pagination = FirstPagePagination(),
|
||||
block: suspend (Pagination) -> PaginationResult<T>
|
||||
block: (Pagination) -> PaginationResult<T>
|
||||
) {
|
||||
doForAll(
|
||||
initialPagination,
|
||||
@@ -34,7 +34,7 @@ suspend fun <T> doAllWithCurrentPaging(
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun <T> doForAllWithCurrentPaging(
|
||||
inline fun <T> doForAllWithCurrentPaging(
|
||||
initialPagination: Pagination = FirstPagePagination(),
|
||||
block: suspend (Pagination) -> PaginationResult<T>
|
||||
block: (Pagination) -> PaginationResult<T>
|
||||
) = doAllWithCurrentPaging(initialPagination, block)
|
||||
|
||||
@@ -2,10 +2,10 @@ package dev.inmo.micro_utils.pagination.utils
|
||||
|
||||
import dev.inmo.micro_utils.pagination.*
|
||||
|
||||
suspend fun <T> getAll(
|
||||
inline fun <T> getAll(
|
||||
initialPagination: Pagination = FirstPagePagination(),
|
||||
paginationMapper: (PaginationResult<T>) -> Pagination?,
|
||||
block: suspend (Pagination) -> PaginationResult<T>
|
||||
block: (Pagination) -> PaginationResult<T>
|
||||
): List<T> {
|
||||
val results = mutableListOf<T>()
|
||||
doForAll(initialPagination, paginationMapper) {
|
||||
@@ -16,46 +16,45 @@ suspend fun <T> getAll(
|
||||
return results.toList()
|
||||
}
|
||||
|
||||
suspend fun <T, R> R.getAllBy(
|
||||
inline fun <T, R> R.getAllBy(
|
||||
initialPagination: Pagination = FirstPagePagination(),
|
||||
paginationMapper: R.(PaginationResult<T>) -> Pagination?,
|
||||
block: suspend R.(Pagination) -> PaginationResult<T>
|
||||
block: R.(Pagination) -> PaginationResult<T>
|
||||
): List<T> = getAll(
|
||||
initialPagination,
|
||||
{ paginationMapper(it) },
|
||||
{ block(it) }
|
||||
)
|
||||
|
||||
suspend fun <T> getAllWithNextPaging(
|
||||
inline fun <T> getAllWithNextPaging(
|
||||
initialPagination: Pagination = FirstPagePagination(),
|
||||
block: suspend (Pagination) -> PaginationResult<T>
|
||||
block: (Pagination) -> PaginationResult<T>
|
||||
): List<T> = getAll(
|
||||
initialPagination,
|
||||
{ it.nextPageIfNotEmpty() },
|
||||
block
|
||||
)
|
||||
|
||||
suspend fun <T, R> R.getAllByWithNextPaging(
|
||||
inline fun <T, R> R.getAllByWithNextPaging(
|
||||
initialPagination: Pagination = FirstPagePagination(),
|
||||
block: suspend R.(Pagination) -> PaginationResult<T>
|
||||
block: R.(Pagination) -> PaginationResult<T>
|
||||
): List<T> = getAllWithNextPaging(
|
||||
initialPagination,
|
||||
{ block(it) }
|
||||
)
|
||||
|
||||
suspend fun <T> getAllWithCurrentPaging(
|
||||
inline fun <T> getAllWithCurrentPaging(
|
||||
initialPagination: Pagination = FirstPagePagination(),
|
||||
block: suspend (Pagination) -> PaginationResult<T>
|
||||
block: (Pagination) -> PaginationResult<T>
|
||||
): List<T> = getAll(
|
||||
initialPagination,
|
||||
{ it.currentPageIfNotEmpty() },
|
||||
block
|
||||
)
|
||||
|
||||
suspend fun <T, R> R.getAllByWithCurrentPaging(
|
||||
inline fun <T, R> R.getAllByWithCurrentPaging(
|
||||
initialPagination: Pagination = FirstPagePagination(),
|
||||
block: suspend R.(Pagination) -> PaginationResult<T>
|
||||
block: R.(Pagination) -> PaginationResult<T>
|
||||
): List<T> = getAllWithCurrentPaging(
|
||||
initialPagination,
|
||||
{ block(it) }
|
||||
)
|
||||
initialPagination
|
||||
) { 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.builtins.serializer
|
||||
|
||||
@Deprecated("Use KtorReadStandardCrudRepoClient instead")
|
||||
class KtorReadStandardCrudRepo<ObjectType, IdType> (
|
||||
private val baseUrl: String,
|
||||
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 kotlinx.serialization.KSerializer
|
||||
|
||||
@Deprecated("Use KtorStandardCrudRepoClient instead")
|
||||
class KtorStandardCrudRepo<ObjectType, IdType, InputValue> (
|
||||
baseUrl: 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.builtins.*
|
||||
|
||||
@Deprecated("Use KtorWriteStandardCrudRepoClient instead")
|
||||
class KtorWriteStandardCrudRepo<ObjectType, IdType, InputValue> (
|
||||
private val baseUrl: String,
|
||||
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