Compare commits

...

55 Commits

Author SHA1 Message Date
62df81bb4e update uuid and partially fill changelog 2022-06-05 00:34:45 +06:00
0a8e0f6178 complete swagger templates 2022-06-04 17:12:05 +06:00
f705020aaa fixes in packages 2022-06-04 16:55:23 +06:00
78bd3b9853 replaces of new API of ktor 2022-06-04 16:52:01 +06:00
992b283597 add kv swagger template 2022-06-04 16:47:22 +06:00
8fc1ff1d59 fixes and filling of cru.yml for swagger 2022-06-04 16:18:48 +06:00
3bbde61f39 renames in crud repos and some little refactoring 2022-06-04 15:15:17 +06:00
8d955c4b9d renames in kevalues repos 2022-06-04 15:00:23 +06:00
18593c530b renames in key value repos 2022-06-04 14:42:16 +06:00
78903cd4eb complete improvements in repos ktor parts 2022-06-04 00:22:36 +06:00
eaa143f7d7 kv rework, fixes in map keyvalue repo, tests 2022-06-03 22:33:26 +06:00
bcb0e42fa2 add new started clients for crud 2022-06-03 17:52:58 +06:00
8eed435302 start improvements in ktor parts 2022-06-03 12:22:51 +06:00
0e4a63057f start 0.11.0 2022-06-02 23:50:06 +06:00
1af5faa440 Merge pull request #159 from InsanusMokrassar/0.10.8
0.10.8
2022-05-29 20:06:14 +06:00
7412217b0c add Element.isOverflow 2022-05-29 10:22:57 +06:00
3e749d75b7 start 0.10.8 2022-05-29 10:19:39 +06:00
846b5c87c9 Merge pull request #158 from InsanusMokrassar/0.10.7
0.10.7
2022-05-28 23:59:54 +06:00
7b5e84f80b doForAll and getForAll not suspend 2022-05-28 22:47:06 +06:00
27822a8a66 start 0.10.7 2022-05-28 18:48:51 +06:00
36f4e7ec37 Merge pull request #157 from InsanusMokrassar/0.10.6
0.10.6
2022-05-28 09:47:10 +06:00
187e84ad65 fill changelog and downgrade coroutines 2022-05-28 09:45:18 +06:00
195fe221c4 Update libs.versions.toml 2022-05-28 00:25:59 +06:00
6f9c19bbf6 fixes in ResizeObserver 2022-05-27 11:39:09 +06:00
65bdab4f7e ResizeObserver 2022-05-27 02:37:58 +06:00
c4d5fcfc22 start 0.10.6 2022-05-27 02:37:14 +06:00
43232afa62 Merge pull request #156 from InsanusMokrassar/0.10.5
0.10.5
2022-05-19 10:44:00 -04:00
18908a01d7 rewrite the way to use onStateHandlingErrorHandler inside of DefaultStatesMachine 2022-05-19 20:42:22 +06:00
b22fbfb3bc StateHandlingErrorHandler 2022-05-19 20:22:34 +06:00
57aaea88b6 Update gradle.properties 2022-05-17 12:38:15 +06:00
140949c5ea Update CHANGELOG.md 2022-05-17 12:32:59 +06:00
639241e0d3 Update libs.versions.toml 2022-05-17 12:31:50 +06:00
e0eb42bc2d update dexcount 2022-05-16 17:38:49 +06:00
7990b21cc5 add SharedPreferencesKeyValueRepo 2022-05-16 17:34:34 +06:00
2ba5c97709 start 0.10.5 2022-05-16 17:33:49 +06:00
33b7c85fc2 Merge pull request #154 from InsanusMokrassar/0.10.4
0.10.4
2022-05-12 17:24:13 +06:00
7f6c02ffdf update serialization 2022-05-12 17:04:53 +06:00
f368616e6f start 0.10.4 2022-05-12 17:03:59 +06:00
dd632f4203 Merge pull request #153 from InsanusMokrassar/0.10.3
0.10.3
2022-05-11 08:42:24 +06:00
a8f3ae501b Update CHANGELOG.md 2022-05-11 08:34:44 +06:00
ea76963ac2 Update libs.versions.toml 2022-05-11 08:33:55 +06:00
99dfa97958 Merge pull request #152 from InsanusMokrassar/0.10.3
0.10.3
2022-05-11 02:49:35 +06:00
f68270a5b3 fixes in AccumulatorFlow 2022-05-11 02:38:48 +06:00
542ed81034 start 0.10.3 2022-05-11 01:18:48 +06:00
404a11f5e7 Merge pull request #151 from InsanusMokrassar/0.10.2
0.10.2
2022-05-10 23:44:39 +06:00
411221070e Update CHANGELOG.md 2022-05-10 23:44:13 +06:00
25d35d0c76 Update compose 2022-05-10 15:03:04 +06:00
c72904d61c start 0.10.2 2022-05-10 15:00:56 +06:00
b94c9acd26 Merge pull request #150 from InsanusMokrassar/0.10.1
0.10.1
2022-04-29 23:20:27 +06:00
bdb4988569 fixes 2022-04-29 19:46:15 +06:00
1dafd1352a hotfix 2022-04-29 18:47:23 +06:00
31fbd3cad7 hmacSha256 and hex 2022-04-29 18:42:59 +06:00
848bc5ec10 Update gradle.properties 2022-04-28 23:45:57 +06:00
4d0ad826a0 Update libs.versions.toml 2022-04-28 23:32:35 +06:00
6955820fcc Merge pull request #149 from InsanusMokrassar/0.10.0
0.10.0
2022-04-28 20:30:52 +06:00
100 changed files with 3267 additions and 308 deletions

View File

@@ -1,5 +1,73 @@
# Changelog
## 0.11.0
* `Versions`
* `UUID`: `0.4.0` -> `0.4.1`
* `Ktor`
* `Client`:
* New extension fun `HttpResponse#throwOnUnsuccess`
* All old functions, classes and extensions has been rewritten with new ktor-way with types info and keeping `ContentNegotiation` in mind
* `Server`:
* All old functions, classes and extensions has been rewritten with new ktor-way with types info and keeping `ContentNegotiation` in mind
* `Repos`
* `Ktor`:
* Fully rewritten work with all declared repositories
* All old functions, classes and extensions has been rewritten with new ktor-way with types info and keeping `ContentNegotiation` in mind
## 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
* `Versions`:
* `Compose`: `1.2.0-alpha01-dev675` -> `1.2.0-alpha01-dev682`
## 0.10.1
* `Versions`:
* `Ktor`: `2.0.0` -> `2.0.1`
* `Crypto`:
* Add `hmacSha256`
* Add `hex`
## 0.10.0
* `Versions`:

View File

@@ -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

View File

@@ -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"
}
}
}

View File

@@ -6,11 +6,12 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlin.coroutines.cancellation.CancellationException
private sealed interface AccumulatorFlowStep
private data class DataRetrievedAccumulatorFlowStep(val data: Any) : AccumulatorFlowStep
private data class SubscribeAccumulatorFlowStep(val channel: Channel<Any>) : AccumulatorFlowStep
private data class UnsubscribeAccumulatorFlowStep(val channel: Channel<Any>) : AccumulatorFlowStep
private sealed interface AccumulatorFlowStep<T>
private data class DataRetrievedAccumulatorFlowStep<T>(val data: T) : AccumulatorFlowStep<T>
private data class SubscribeAccumulatorFlowStep<T>(val channel: Channel<T>) : AccumulatorFlowStep<T>
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:
@@ -26,12 +27,12 @@ class AccumulatorFlow<T>(
private val subscope = scope.LinkedSupervisorScope()
private val activeData = ArrayDeque<T>()
private val dataMutex = Mutex()
private val channelsForBroadcast = mutableListOf<Channel<Any>>()
private val channelsForBroadcast = mutableListOf<Channel<T>>()
private val channelsMutex = Mutex()
private val steps = subscope.actor<AccumulatorFlowStep> { step ->
private val steps = subscope.actor<AccumulatorFlowStep<T>> { step ->
when (step) {
is DataRetrievedAccumulatorFlowStep -> {
if (activeData.first() === step.data) {
if (activeData.firstOrNull() === step.data) {
dataMutex.withLock {
activeData.removeFirst()
}
@@ -42,7 +43,7 @@ class AccumulatorFlow<T>(
dataMutex.withLock {
val dataToSend = activeData.toList()
safelyWithoutExceptions {
dataToSend.forEach { step.channel.send(it as Any) }
dataToSend.forEach { step.channel.send(it) }
}
}
}
@@ -58,24 +59,29 @@ class AccumulatorFlow<T>(
channelsMutex.withLock {
channelsForBroadcast.forEach { channel ->
safelyWithResult {
channel.send(it as Any)
channel.send(it)
}
}
}
}
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))
for (data in channel) {
try {
collector.emit(data as T)
steps.send(DataRetrievedAccumulatorFlowStep(data))
} finally {
channel.cancel()
steps.send(UnsubscribeAccumulatorFlowStep(channel))
val result = runCatchingSafely {
for (data in channel) {
val emitResult = runCatchingSafely {
collector.emit(data)
}
if (emitResult.isSuccess || emitResult.exceptionOrNull() is CancellationException) {
steps.send(DataRetrievedAccumulatorFlowStep(data))
}
emitResult.getOrThrow()
}
}
channel.cancel()
steps.send(UnsubscribeAccumulatorFlowStep(channel))
result.getOrThrow()
}
}

View File

@@ -0,0 +1,15 @@
package dev.inmo.micro_utils.crypto
val HEX_ARRAY = "0123456789abcdef".toCharArray()
fun SourceBytes.hex(): String {
val hexChars = CharArray(size * 2)
for (j in indices) {
val v: Int = this[j].toInt() and 0xFF
hexChars[j * 2] = HEX_ARRAY[v ushr 4]
hexChars[j * 2 + 1] = HEX_ARRAY[v and 0x0F]
}
return hexChars.concatToString()
}
fun SourceString.hex(): String = encodeToByteArray().hex()

View File

@@ -0,0 +1,3 @@
package dev.inmo.micro_utils.crypto
expect fun SourceString.hmacSha256(key: String): String

View File

@@ -0,0 +1,15 @@
package dev.inmo.micro_utils.crypto
import kotlin.test.*
class Hex {
@Test
fun testSimpleHmacSHA256Message() {
val text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
val resultHex = text.hex()
assertEquals(
"4c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742c2073656420646f20656975736d6f642074656d706f7220696e6369646964756e74207574206c61626f726520657420646f6c6f7265206d61676e6120616c697175612e20557420656e696d206164206d696e696d2076656e69616d2c2071756973206e6f737472756420657865726369746174696f6e20756c6c616d636f206c61626f726973206e69736920757420616c697175697020657820656120636f6d6d6f646f20636f6e7365717561742e2044756973206175746520697275726520646f6c6f7220696e20726570726568656e646572697420696e20766f6c7570746174652076656c697420657373652063696c6c756d20646f6c6f726520657520667567696174206e756c6c612070617269617475722e204578636570746575722073696e74206f6363616563617420637570696461746174206e6f6e2070726f6964656e742c2073756e7420696e2063756c706120717569206f666669636961206465736572756e74206d6f6c6c697420616e696d20696420657374206c61626f72756d2e",
resultHex
)
}
}

View File

@@ -0,0 +1,12 @@
package dev.inmo.micro_utils.crypto
import kotlin.test.*
class HmacSHA256 {
@Test
fun testSimpleHmacSHA256Message() {
val text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
val resultSha = text.hmacSha256("Example")
assertEquals("5a481d59329ef862b158eedc95392ebb22492ba3014661a3379d8201db992484", resultSha)
}
}

View File

@@ -7,3 +7,7 @@ external interface CryptoJs {
@JsModule("crypto-js")
@JsNonModule
external val CryptoJS: CryptoJs
actual fun SourceString.hmacSha256(key: String): String {
return CryptoJS.asDynamic().HmacSHA256(this, key).toString().unsafeCast<String>()
}

View File

@@ -0,0 +1,13 @@
package dev.inmo.micro_utils.crypto
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
actual fun SourceString.hmacSha256(key: String): String {
val mac = Mac.getInstance("HmacSHA256")
val secretKey = SecretKeySpec(key.toByteArray(), "HmacSHA256")
mac.init(secretKey)
return mac.doFinal(toByteArray()).hex()
}

View File

@@ -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
*/

View File

@@ -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 {

View File

@@ -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>

View File

@@ -14,5 +14,5 @@ crypto_js_version=4.1.1
# Project data
group=dev.inmo
version=0.10.0
android_code_version=115
version=0.11.0
android_code_version=124

View File

@@ -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-dev675"
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"
uuid = "0.4.1"
ktor = "2.0.0"
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"
@@ -37,17 +37,24 @@ kt-serialization-cbor = { module = "org.jetbrains.kotlinx:kotlinx-serialization-
kt-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kt-coroutines" }
kt-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kt-coroutines" }
kt-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kt-coroutines" }
ktor-io = { module = "io.ktor:ktor-io", version.ref = "ktor" }
ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
ktor-client = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
ktor-client-java = { module = "io.ktor:ktor-client-java", version.ref = "ktor" }
ktor-client-websockets = { module = "io.ktor:ktor-client-websockets", version.ref = "ktor" }
ktor-client-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" }
ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
ktor-server = { module = "io.ktor:ktor-server", version.ref = "ktor" }
ktor-server-cio = { module = "io.ktor:ktor-server-cio", version.ref = "ktor" }
ktor-server-host-common = { module = "io.ktor:ktor-server-host-common", version.ref = "ktor" }
ktor-websockets = { module = "io.ktor:ktor-websockets", version.ref = "ktor" }
ktor-server-websockets = { module = "io.ktor:ktor-server-websockets", version.ref = "ktor" }
ktor-server-statusPages = { module = "io.ktor:ktor-server-status-pages", version.ref = "ktor" }
ktor-server-content-negotiation = { module = "io.ktor:ktor-server-content-negotiation", version.ref = "ktor" }
klock = { module = "com.soywiz.korlibs.klock:klock", version.ref = "klock" }

View File

@@ -0,0 +1,15 @@
package dev.inmo.micro_utils.ktor.client
import io.ktor.client.plugins.ClientRequestException
import io.ktor.client.statement.HttpResponse
import io.ktor.http.isSuccess
inline fun HttpResponse.throwOnUnsuccess(
unsuccessMessage: () -> String
) {
if (status.isSuccess()) {
return
}
throw ClientRequestException(this, unsuccessMessage())
}

View File

@@ -0,0 +1,55 @@
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 io.ktor.websocket.serialization.sendSerializedBase
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,
noinline 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()
}
}
}
}

View File

@@ -0,0 +1,15 @@
package dev.inmo.micro_utils.ktor.server
import io.ktor.server.application.ApplicationCall
import io.ktor.server.response.responseType
import io.ktor.util.InternalAPI
import io.ktor.util.reflect.TypeInfo
@InternalAPI
suspend fun <T : Any> ApplicationCall.respond(
message: T,
typeInfo: TypeInfo
) {
response.responseType = typeInfo
response.pipeline.execute(this, message as Any)
}

View File

@@ -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)
}
}
}
}

View File

@@ -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)

View File

@@ -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) }

View File

@@ -4,8 +4,6 @@ import dev.inmo.micro_utils.repos.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
open class ReadKeyValueCacheRepo<Key,Value>(
protected val parentRepo: ReadKeyValueRepo<Key, Value>,

View File

@@ -8,8 +8,6 @@ import dev.inmo.micro_utils.repos.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
open class ReadKeyValuesCacheRepo<Key,Value>(
protected val parentRepo: ReadKeyValuesRepo<Key, Value>,

View File

@@ -1,11 +1,10 @@
package dev.inmo.micro_utils.repos
import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.pagination.utils.doForAllWithCurrentPaging
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
import kotlinx.coroutines.flow.Flow
interface ReadOneToManyKeyValueRepo<Key, Value> : Repo {
interface ReadKeyValuesRepo<Key, Value> : Repo {
suspend fun get(k: Key, pagination: Pagination, reversed: Boolean = false): PaginationResult<Value>
suspend fun keys(pagination: Pagination, reversed: Boolean = false): PaginationResult<Key>
suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean = false): PaginationResult<Key>
@@ -36,9 +35,9 @@ interface ReadOneToManyKeyValueRepo<Key, Value> : Repo {
}
}
}
typealias ReadKeyValuesRepo<Key,Value> = ReadOneToManyKeyValueRepo<Key, Value>
typealias ReadOneToManyKeyValueRepo<Key,Value> = ReadKeyValuesRepo<Key, Value>
interface WriteOneToManyKeyValueRepo<Key, Value> : Repo {
interface WriteKeyValuesRepo<Key, Value> : Repo {
val onNewValue: Flow<Pair<Key, Value>>
val onValueRemoved: Flow<Pair<Key, Value>>
val onDataCleared: Flow<Key>
@@ -55,41 +54,41 @@ interface WriteOneToManyKeyValueRepo<Key, Value> : Repo {
add(toSet)
}
}
typealias WriteKeyValuesRepo<Key,Value> = WriteOneToManyKeyValueRepo<Key, Value>
typealias WriteOneToManyKeyValueRepo<Key,Value> = WriteKeyValuesRepo<Key, Value>
suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.add(
suspend inline fun <Key, Value, REPO : WriteKeyValuesRepo<Key, Value>> REPO.add(
keysAndValues: List<Pair<Key, List<Value>>>
) = add(keysAndValues.toMap())
suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.add(
suspend inline fun <Key, Value, REPO : WriteKeyValuesRepo<Key, Value>> REPO.add(
vararg keysAndValues: Pair<Key, List<Value>>
) = add(keysAndValues.toMap())
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.add(
suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.add(
k: Key, v: List<Value>
) = add(mapOf(k to v))
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.add(
suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.add(
k: Key, vararg v: Value
) = add(k, v.toList())
suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.set(
suspend inline fun <Key, Value, REPO : WriteKeyValuesRepo<Key, Value>> REPO.set(
keysAndValues: List<Pair<Key, List<Value>>>
) = set(keysAndValues.toMap())
suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.set(
suspend inline fun <Key, Value, REPO : WriteKeyValuesRepo<Key, Value>> REPO.set(
vararg keysAndValues: Pair<Key, List<Value>>
) = set(keysAndValues.toMap())
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.set(
suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.set(
k: Key, v: List<Value>
) = set(mapOf(k to v))
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.set(
suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.set(
k: Key, vararg v: Value
) = set(k, v.toList())
interface OneToManyKeyValueRepo<Key, Value> : ReadOneToManyKeyValueRepo<Key, Value>, WriteOneToManyKeyValueRepo<Key, Value> {
interface KeyValuesRepo<Key, Value> : ReadKeyValuesRepo<Key, Value>, WriteKeyValuesRepo<Key, Value> {
override suspend fun clearWithValue(v: Value) {
doWithPagination {
val keysResult = keys(v, it)
@@ -102,22 +101,29 @@ interface OneToManyKeyValueRepo<Key, Value> : ReadOneToManyKeyValueRepo<Key, Val
}
}
}
typealias KeyValuesRepo<Key,Value> = OneToManyKeyValueRepo<Key, Value>
typealias OneToManyKeyValueRepo<Key,Value> = KeyValuesRepo<Key, Value>
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.remove(
class DelegateBasedKeyValuesRepo<Key, Value>(
readDelegate: ReadKeyValuesRepo<Key, Value>,
writeDelegate: WriteKeyValuesRepo<Key, Value>
) : KeyValuesRepo<Key, Value>,
ReadKeyValuesRepo<Key, Value> by readDelegate,
WriteKeyValuesRepo<Key, Value> by writeDelegate
suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.remove(
keysAndValues: List<Pair<Key, List<Value>>>
) = remove(keysAndValues.toMap())
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.remove(
suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.remove(
vararg keysAndValues: Pair<Key, List<Value>>
) = remove(keysAndValues.toMap())
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.remove(
suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.remove(
k: Key,
v: List<Value>
) = remove(mapOf(k to v))
suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.remove(
suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.remove(
k: Key,
vararg v: Value
) = remove(k, v.toList())

View File

@@ -4,13 +4,13 @@ import dev.inmo.micro_utils.pagination.Pagination
import dev.inmo.micro_utils.pagination.PaginationResult
import kotlinx.coroutines.flow.Flow
interface ReadStandardCRUDRepo<ObjectType, IdType> : Repo {
interface ReadCRUDRepo<ObjectType, IdType> : Repo {
suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType>
suspend fun getById(id: IdType): ObjectType?
suspend fun contains(id: IdType): Boolean
suspend fun count(): Long
}
typealias ReadCRUDRepo<ObjectType, IdType> = ReadStandardCRUDRepo<ObjectType, IdType>
typealias ReadStandardCRUDRepo<ObjectType, IdType> = ReadCRUDRepo<ObjectType, IdType>
typealias UpdatedValuePair<IdType, ValueType> = Pair<IdType, ValueType>
val <IdType> UpdatedValuePair<IdType, *>.id
@@ -18,7 +18,7 @@ val <IdType> UpdatedValuePair<IdType, *>.id
val <ValueType> UpdatedValuePair<*, ValueType>.value
get() = second
interface WriteStandardCRUDRepo<ObjectType, IdType, InputValueType> : Repo {
interface WriteCRUDRepo<ObjectType, IdType, InputValueType> : Repo {
val newObjectsFlow: Flow<ObjectType>
val updatedObjectsFlow: Flow<ObjectType>
val deletedObjectsIdsFlow: Flow<IdType>
@@ -28,18 +28,25 @@ interface WriteStandardCRUDRepo<ObjectType, IdType, InputValueType> : Repo {
suspend fun update(values: List<UpdatedValuePair<IdType, InputValueType>>): List<ObjectType>
suspend fun deleteById(ids: List<IdType>)
}
typealias WriteCRUDRepo<ObjectType, IdType, InputValueType> = WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>
typealias WriteStandardCRUDRepo<ObjectType, IdType, InputValueType> = WriteCRUDRepo<ObjectType, IdType, InputValueType>
suspend fun <ObjectType, IdType, InputValueType> WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>.create(
suspend fun <ObjectType, IdType, InputValueType> WriteCRUDRepo<ObjectType, IdType, InputValueType>.create(
vararg values: InputValueType
): List<ObjectType> = create(values.toList())
suspend fun <ObjectType, IdType, InputValueType> WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>.update(
suspend fun <ObjectType, IdType, InputValueType> WriteCRUDRepo<ObjectType, IdType, InputValueType>.update(
vararg values: UpdatedValuePair<IdType, InputValueType>
): List<ObjectType> = update(values.toList())
suspend fun <ObjectType, IdType, InputValueType> WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>.deleteById(
suspend fun <ObjectType, IdType, InputValueType> WriteCRUDRepo<ObjectType, IdType, InputValueType>.deleteById(
vararg ids: IdType
) = deleteById(ids.toList())
interface StandardCRUDRepo<ObjectType, IdType, InputValueType> : ReadStandardCRUDRepo<ObjectType, IdType>,
WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>
typealias CRUDRepo<ObjectType, IdType, InputValueType> = StandardCRUDRepo<ObjectType, IdType, InputValueType>
interface CRUDRepo<ObjectType, IdType, InputValueType> : ReadCRUDRepo<ObjectType, IdType>,
WriteCRUDRepo<ObjectType, IdType, InputValueType>
typealias StandardCRUDRepo<ObjectType, IdType, InputValueType> = CRUDRepo<ObjectType, IdType, InputValueType>
class DelegateBasedCRUDRepo<ObjectType, IdType, InputValueType>(
readDelegate: ReadCRUDRepo<ObjectType, IdType>,
writeDelegate: WriteCRUDRepo<ObjectType, IdType, InputValueType>
) : CRUDRepo<ObjectType, IdType, InputValueType>,
ReadCRUDRepo<ObjectType, IdType> by readDelegate,
WriteCRUDRepo<ObjectType, IdType, InputValueType> by writeDelegate

View File

@@ -4,7 +4,7 @@ import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.pagination.utils.doAllWithCurrentPaging
import kotlinx.coroutines.flow.Flow
interface ReadStandardKeyValueRepo<Key, Value> : Repo {
interface ReadKeyValueRepo<Key, Value> : Repo {
suspend fun get(k: Key): Value?
suspend fun values(pagination: Pagination, reversed: Boolean = false): PaginationResult<Value>
suspend fun keys(pagination: Pagination, reversed: Boolean = false): PaginationResult<Key>
@@ -12,9 +12,9 @@ interface ReadStandardKeyValueRepo<Key, Value> : Repo {
suspend fun contains(key: Key): Boolean
suspend fun count(): Long
}
typealias ReadKeyValueRepo<Key,Value> = ReadStandardKeyValueRepo<Key, Value>
typealias ReadStandardKeyValueRepo<Key,Value> = ReadKeyValueRepo<Key, Value>
interface WriteStandardKeyValueRepo<Key, Value> : Repo {
interface WriteKeyValueRepo<Key, Value> : Repo {
val onNewValue: Flow<Pair<Key, Value>>
val onValueRemoved: Flow<Key>
@@ -22,25 +22,25 @@ interface WriteStandardKeyValueRepo<Key, Value> : Repo {
suspend fun unset(toUnset: List<Key>)
suspend fun unsetWithValues(toUnset: List<Value>)
}
typealias WriteKeyValueRepo<Key,Value> = WriteStandardKeyValueRepo<Key, Value>
typealias WriteStandardKeyValueRepo<Key,Value> = WriteKeyValueRepo<Key, Value>
suspend inline fun <Key, Value> WriteStandardKeyValueRepo<Key, Value>.set(
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.set(
vararg toSet: Pair<Key, Value>
) = set(toSet.toMap())
suspend inline fun <Key, Value> WriteStandardKeyValueRepo<Key, Value>.set(
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.set(
k: Key, v: Value
) = set(k to v)
suspend inline fun <Key, Value> WriteStandardKeyValueRepo<Key, Value>.unset(
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.unset(
vararg k: Key
) = unset(k.toList())
suspend inline fun <Key, Value> WriteStandardKeyValueRepo<Key, Value>.unsetWithValues(
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.unsetWithValues(
vararg v: Value
) = unsetWithValues(v.toList())
interface StandardKeyValueRepo<Key, Value> : ReadStandardKeyValueRepo<Key, Value>, WriteStandardKeyValueRepo<Key, Value> {
interface KeyValueRepo<Key, Value> : ReadKeyValueRepo<Key, Value>, WriteKeyValueRepo<Key, Value> {
override suspend fun unsetWithValues(toUnset: List<Value>) = toUnset.forEach { v ->
doAllWithCurrentPaging {
keys(v, it).also {
@@ -49,4 +49,11 @@ interface StandardKeyValueRepo<Key, Value> : ReadStandardKeyValueRepo<Key, Value
}
}
}
typealias KeyValueRepo<Key,Value> = StandardKeyValueRepo<Key, Value>
typealias StandardKeyValueRepo<Key,Value> = KeyValueRepo<Key, Value>
class DelegateBasedKeyValueRepo<Key, Value>(
readDelegate: ReadKeyValueRepo<Key, Value>,
writeDelegate: WriteKeyValueRepo<Key, Value>
) : KeyValueRepo<Key, Value>,
ReadKeyValueRepo<Key, Value> by readDelegate,
WriteKeyValueRepo<Key, Value> by writeDelegate

View File

@@ -6,10 +6,12 @@ import dev.inmo.micro_utils.repos.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
open class MapperReadStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
private val to: ReadStandardKeyValueRepo<ToKey, ToValue>,
@Deprecated("Renamed", ReplaceWith("MapperReadKeyValueRepo", "dev.inmo.micro_utils.repos.mappers.MapperReadKeyValueRepo"))
typealias MapperReadStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue> = MapperReadKeyValueRepo<FromKey, FromValue, ToKey, ToValue>
open class MapperReadKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
private val to: ReadKeyValueRepo<ToKey, ToValue>,
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
) : ReadStandardKeyValueRepo<FromKey, FromValue>, MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper {
) : ReadKeyValueRepo<FromKey, FromValue>, MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper {
override suspend fun get(k: FromKey): FromValue? = to.get(
k.toOutKey()
) ?.toInnerValue()
@@ -69,24 +71,26 @@ open class MapperReadStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
}
@Suppress("NOTHING_TO_INLINE")
inline fun <FromKey, FromValue, ToKey, ToValue> ReadStandardKeyValueRepo<ToKey, ToValue>.withMapper(
inline fun <FromKey, FromValue, ToKey, ToValue> ReadKeyValueRepo<ToKey, ToValue>.withMapper(
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
): ReadStandardKeyValueRepo<FromKey, FromValue> = MapperReadStandardKeyValueRepo(this, mapper)
): ReadKeyValueRepo<FromKey, FromValue> = MapperReadKeyValueRepo(this, mapper)
@Suppress("NOTHING_TO_INLINE")
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> ReadStandardKeyValueRepo<ToKey, ToValue>.withMapper(
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> ReadKeyValueRepo<ToKey, ToValue>.withMapper(
crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
): ReadStandardKeyValueRepo<FromKey, FromValue> = withMapper(
): ReadKeyValueRepo<FromKey, FromValue> = withMapper(
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
)
open class MapperWriteStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
private val to: WriteStandardKeyValueRepo<ToKey, ToValue>,
@Deprecated("Renamed", ReplaceWith("MapperWriteKeyValueRepo", "dev.inmo.micro_utils.repos.mappers.MapperWriteKeyValueRepo"))
typealias MapperWriteStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue> = MapperWriteKeyValueRepo<FromKey, FromValue, ToKey, ToValue>
open class MapperWriteKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
private val to: WriteKeyValueRepo<ToKey, ToValue>,
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
) : WriteStandardKeyValueRepo<FromKey, FromValue>, MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper {
) : WriteKeyValueRepo<FromKey, FromValue>, MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper {
override val onNewValue: Flow<Pair<FromKey, FromValue>> = to.onNewValue.map { (k, v) ->
k.toInnerKey() to v.toInnerValue()
}
@@ -112,40 +116,42 @@ open class MapperWriteStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
}
@Suppress("NOTHING_TO_INLINE")
inline fun <FromKey, FromValue, ToKey, ToValue> WriteStandardKeyValueRepo<ToKey, ToValue>.withMapper(
inline fun <FromKey, FromValue, ToKey, ToValue> WriteKeyValueRepo<ToKey, ToValue>.withMapper(
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
): WriteStandardKeyValueRepo<FromKey, FromValue> = MapperWriteStandardKeyValueRepo(this, mapper)
): WriteKeyValueRepo<FromKey, FromValue> = MapperWriteKeyValueRepo(this, mapper)
@Suppress("NOTHING_TO_INLINE")
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> WriteStandardKeyValueRepo<ToKey, ToValue>.withMapper(
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> WriteKeyValueRepo<ToKey, ToValue>.withMapper(
crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
): WriteStandardKeyValueRepo<FromKey, FromValue> = withMapper(
): WriteKeyValueRepo<FromKey, FromValue> = withMapper(
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
)
@Deprecated("Renamed", ReplaceWith("MapperKeyValueRepo", "dev.inmo.micro_utils.repos.mappers.MapperKeyValueRepo"))
typealias MapperStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue> = MapperKeyValueRepo<FromKey, FromValue, ToKey, ToValue>
@Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE")
open class MapperStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
private val to: StandardKeyValueRepo<ToKey, ToValue>,
open class MapperKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
private val to: KeyValueRepo<ToKey, ToValue>,
private val mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
) : StandardKeyValueRepo<FromKey, FromValue>,
) : KeyValueRepo<FromKey, FromValue>,
MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper,
ReadStandardKeyValueRepo<FromKey, FromValue> by MapperReadStandardKeyValueRepo(to, mapper),
WriteStandardKeyValueRepo<FromKey, FromValue> by MapperWriteStandardKeyValueRepo(to, mapper)
ReadKeyValueRepo<FromKey, FromValue> by MapperReadKeyValueRepo(to, mapper),
WriteKeyValueRepo<FromKey, FromValue> by MapperWriteKeyValueRepo(to, mapper)
@Suppress("NOTHING_TO_INLINE")
inline fun <FromKey, FromValue, ToKey, ToValue> StandardKeyValueRepo<ToKey, ToValue>.withMapper(
inline fun <FromKey, FromValue, ToKey, ToValue> KeyValueRepo<ToKey, ToValue>.withMapper(
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
): StandardKeyValueRepo<FromKey, FromValue> = MapperStandardKeyValueRepo(this, mapper)
): KeyValueRepo<FromKey, FromValue> = MapperKeyValueRepo(this, mapper)
@Suppress("NOTHING_TO_INLINE")
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> StandardKeyValueRepo<ToKey, ToValue>.withMapper(
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> KeyValueRepo<ToKey, ToValue>.withMapper(
crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
): StandardKeyValueRepo<FromKey, FromValue> = withMapper(
): KeyValueRepo<FromKey, FromValue> = withMapper(
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
)

View File

@@ -6,10 +6,12 @@ import dev.inmo.micro_utils.repos.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
open class MapperReadOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
private val to: ReadOneToManyKeyValueRepo<ToKey, ToValue>,
@Deprecated("Renamed", ReplaceWith("MapperReadKeyValuesRepo", "dev.inmo.micro_utils.repos.mappers.MapperReadKeyValuesRepo"))
typealias MapperReadOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue> = MapperReadKeyValuesRepo<FromKey, FromValue, ToKey, ToValue>
open class MapperReadKeyValuesRepo<FromKey, FromValue, ToKey, ToValue>(
private val to: ReadKeyValuesRepo<ToKey, ToValue>,
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
) : ReadOneToManyKeyValueRepo<FromKey, FromValue>, MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper {
) : ReadKeyValuesRepo<FromKey, FromValue>, MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper {
override suspend fun get(
k: FromKey,
pagination: Pagination,
@@ -67,24 +69,26 @@ open class MapperReadOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
}
@Suppress("NOTHING_TO_INLINE")
inline fun <FromKey, FromValue, ToKey, ToValue> ReadOneToManyKeyValueRepo<ToKey, ToValue>.withMapper(
inline fun <FromKey, FromValue, ToKey, ToValue> ReadKeyValuesRepo<ToKey, ToValue>.withMapper(
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
): ReadOneToManyKeyValueRepo<FromKey, FromValue> = MapperReadOneToManyKeyValueRepo(this, mapper)
): ReadKeyValuesRepo<FromKey, FromValue> = MapperReadKeyValuesRepo(this, mapper)
@Suppress("NOTHING_TO_INLINE")
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> ReadOneToManyKeyValueRepo<ToKey, ToValue>.withMapper(
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> ReadKeyValuesRepo<ToKey, ToValue>.withMapper(
crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
): ReadOneToManyKeyValueRepo<FromKey, FromValue> = withMapper(
): ReadKeyValuesRepo<FromKey, FromValue> = withMapper(
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
)
open class MapperWriteOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
private val to: WriteOneToManyKeyValueRepo<ToKey, ToValue>,
@Deprecated("Renamed", ReplaceWith("MapperWriteKeyValuesRepo", "dev.inmo.micro_utils.repos.mappers.MapperWriteKeyValuesRepo"))
typealias MapperWriteOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue> = MapperWriteKeyValuesRepo<FromKey, FromValue, ToKey, ToValue>
open class MapperWriteKeyValuesRepo<FromKey, FromValue, ToKey, ToValue>(
private val to: WriteKeyValuesRepo<ToKey, ToValue>,
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
) : WriteOneToManyKeyValueRepo<FromKey, FromValue>, MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper {
) : WriteKeyValuesRepo<FromKey, FromValue>, MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper {
override val onNewValue: Flow<Pair<FromKey, FromValue>> = to.onNewValue.map { (k, v) ->
k.toInnerKey() to v.toInnerValue()
}
@@ -118,40 +122,42 @@ open class MapperWriteOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
}
@Suppress("NOTHING_TO_INLINE")
inline fun <FromKey, FromValue, ToKey, ToValue> WriteOneToManyKeyValueRepo<ToKey, ToValue>.withMapper(
inline fun <FromKey, FromValue, ToKey, ToValue> WriteKeyValuesRepo<ToKey, ToValue>.withMapper(
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
): WriteOneToManyKeyValueRepo<FromKey, FromValue> = MapperWriteOneToManyKeyValueRepo(this, mapper)
): WriteKeyValuesRepo<FromKey, FromValue> = MapperWriteKeyValuesRepo(this, mapper)
@Suppress("NOTHING_TO_INLINE")
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> WriteOneToManyKeyValueRepo<ToKey, ToValue>.withMapper(
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> WriteKeyValuesRepo<ToKey, ToValue>.withMapper(
crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
): WriteOneToManyKeyValueRepo<FromKey, FromValue> = withMapper(
): WriteKeyValuesRepo<FromKey, FromValue> = withMapper(
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
)
@Deprecated("Renamed", ReplaceWith("MapperKeyValuesRepo", "dev.inmo.micro_utils.repos.mappers.MapperKeyValuesRepo"))
typealias MapperOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue> = MapperKeyValuesRepo<FromKey, FromValue, ToKey, ToValue>
@Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE")
open class MapperOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
private val to: OneToManyKeyValueRepo<ToKey, ToValue>,
open class MapperKeyValuesRepo<FromKey, FromValue, ToKey, ToValue>(
private val to: KeyValuesRepo<ToKey, ToValue>,
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
) : OneToManyKeyValueRepo<FromKey, FromValue>,
) : KeyValuesRepo<FromKey, FromValue>,
MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper,
ReadOneToManyKeyValueRepo<FromKey, FromValue> by MapperReadOneToManyKeyValueRepo(to, mapper),
WriteOneToManyKeyValueRepo<FromKey, FromValue> by MapperWriteOneToManyKeyValueRepo(to, mapper)
ReadKeyValuesRepo<FromKey, FromValue> by MapperReadKeyValuesRepo(to, mapper),
WriteKeyValuesRepo<FromKey, FromValue> by MapperWriteKeyValuesRepo(to, mapper)
@Suppress("NOTHING_TO_INLINE")
inline fun <FromKey, FromValue, ToKey, ToValue> OneToManyKeyValueRepo<ToKey, ToValue>.withMapper(
inline fun <FromKey, FromValue, ToKey, ToValue> KeyValuesRepo<ToKey, ToValue>.withMapper(
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
): OneToManyKeyValueRepo<FromKey, FromValue> = MapperOneToManyKeyValueRepo(this, mapper)
): KeyValuesRepo<FromKey, FromValue> = MapperKeyValuesRepo(this, mapper)
@Suppress("NOTHING_TO_INLINE")
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> OneToManyKeyValueRepo<ToKey, ToValue>.withMapper(
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> KeyValuesRepo<ToKey, ToValue>.withMapper(
crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
): OneToManyKeyValueRepo<FromKey, FromValue> = withMapper(
): KeyValuesRepo<FromKey, FromValue> = withMapper(
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
)

View File

@@ -1,11 +1,10 @@
package dev.inmo.micro_utils.repos.pagination
import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
import dev.inmo.micro_utils.repos.ReadCRUDRepo
suspend inline fun <T, ID, REPO : ReadStandardCRUDRepo<T, ID>> REPO.getAll(
suspend inline fun <T, ID, REPO : ReadCRUDRepo<T, ID>> REPO.getAll(
@Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<T>
): List<T> = getAllWithNextPaging {

View File

@@ -2,9 +2,9 @@ package dev.inmo.micro_utils.repos.pagination
import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
suspend inline fun <Key, Value, REPO : ReadStandardKeyValueRepo<Key, Value>> REPO.getAll(
suspend inline fun <Key, Value, REPO : ReadKeyValueRepo<Key, Value>> REPO.getAll(
@Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key>
): List<Pair<Key, Value>> = getAllWithNextPaging {

View File

@@ -2,9 +2,9 @@ package dev.inmo.micro_utils.repos.pagination
import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
suspend inline fun <Key, Value, REPO : ReadOneToManyKeyValueRepo<Key, Value>> REPO.getAll(
suspend inline fun <Key, Value, REPO : ReadKeyValuesRepo<Key, Value>> REPO.getAll(
@Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key>
): List<Pair<Key, List<Value>>> = getAllWithNextPaging {

View File

@@ -1,10 +1,10 @@
package dev.inmo.micro_utils.repos.versions
import dev.inmo.micro_utils.repos.StandardKeyValueRepo
import dev.inmo.micro_utils.repos.KeyValueRepo
import dev.inmo.micro_utils.repos.set
class KeyValueBasedVersionsRepoProxy<T>(
private val keyValueStore: StandardKeyValueRepo<String, Int>,
private val keyValueStore: KeyValueRepo<String, Int>,
override val database: T
) : StandardVersionsRepoProxy<T> {
override suspend fun getTableVersion(tableName: String): Int? = keyValueStore.get(tableName)

View File

@@ -13,9 +13,12 @@ import java.nio.file.StandardWatchEventKinds.*
private inline val String.isAbsolute
get() = startsWith(File.separator)
class FileReadStandardKeyValueRepo(
@Deprecated("Renamed", ReplaceWith("FileReadKeyValueRepo", "dev.inmo.micro_utils.repos.FileReadKeyValueRepo"))
typealias FileReadStandardKeyValueRepo = FileReadKeyValueRepo
class FileReadKeyValueRepo(
private val folder: File
) : ReadStandardKeyValueRepo<String, File> {
) : ReadKeyValueRepo<String, File> {
init {
folder.mkdirs()
}
@@ -79,14 +82,17 @@ class FileReadStandardKeyValueRepo(
override suspend fun count(): Long = folder.list() ?.size ?.toLong() ?: 0L
}
@Deprecated("Renamed", ReplaceWith("FileWriteKeyValueRepo", "dev.inmo.micro_utils.repos.FileWriteKeyValueRepo"))
typealias FileWriteStandardKeyValueRepo = FileWriteKeyValueRepo
/**
* Files watching will not correctly works on Android with version of API lower than API 26
*/
@Warning("Files watching will not correctly works on Android Platform with version of API lower than API 26")
class FileWriteStandardKeyValueRepo(
class FileWriteKeyValueRepo(
private val folder: File,
filesChangedProcessingScope: CoroutineScope? = null
) : WriteStandardKeyValueRepo<String, File> {
) : WriteKeyValueRepo<String, File> {
private val _onNewValue = MutableSharedFlow<Pair<String, File>>()
override val onNewValue: Flow<Pair<String, File>> = _onNewValue.asSharedFlow()
private val _onValueRemoved = MutableSharedFlow<String>()
@@ -174,12 +180,15 @@ class FileWriteStandardKeyValueRepo(
}
}
@Deprecated("Renamed", ReplaceWith("FileKeyValueRepo", "dev.inmo.micro_utils.repos.FileKeyValueRepo"))
typealias FileStandardKeyValueRepo = FileKeyValueRepo
@Warning("Files watching will not correctly works on Android Platform with version of API lower than API 26")
@Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE")
class FileStandardKeyValueRepo(
class FileKeyValueRepo(
folder: File,
filesChangedProcessingScope: CoroutineScope? = null
) : StandardKeyValueRepo<String, File>,
WriteStandardKeyValueRepo<String, File> by FileWriteStandardKeyValueRepo(folder, filesChangedProcessingScope),
ReadStandardKeyValueRepo<String, File> by FileReadStandardKeyValueRepo(folder) {
) : KeyValueRepo<String, File>,
WriteKeyValueRepo<String, File> by FileWriteKeyValueRepo(folder, filesChangedProcessingScope),
ReadKeyValueRepo<String, File> by FileReadKeyValueRepo(folder) {
}

View File

@@ -12,7 +12,7 @@ val <T> T.asId: String
abstract class AbstractAndroidCRUDRepo<ObjectType, IdType>(
protected val helper: StandardSQLHelper
) : ReadStandardCRUDRepo<ObjectType, IdType> {
) : ReadCRUDRepo<ObjectType, IdType> {
protected abstract val tableName: String
protected abstract val idColumnName: String
protected abstract suspend fun Cursor.toObject(): ObjectType
@@ -64,4 +64,4 @@ abstract class AbstractAndroidCRUDRepo<ObjectType, IdType>(
}
}
}
}
}

View File

@@ -9,9 +9,9 @@ abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType
helper: StandardSQLHelper,
replyInFlows: Int = 0,
extraBufferCapacityInFlows: Int = 64
) : WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>,
) : WriteCRUDRepo<ObjectType, IdType, InputValueType>,
AbstractAndroidCRUDRepo<ObjectType, IdType>(helper),
StandardCRUDRepo<ObjectType, IdType, InputValueType> {
CRUDRepo<ObjectType, IdType, InputValueType> {
protected val newObjectsChannel = MutableSharedFlow<ObjectType>(replyInFlows, extraBufferCapacityInFlows)
protected val updateObjectsChannel = MutableSharedFlow<ObjectType>(replyInFlows, extraBufferCapacityInFlows)
protected val deleteObjectsIdsChannel = MutableSharedFlow<IdType>(replyInFlows, extraBufferCapacityInFlows)

View File

@@ -7,7 +7,7 @@ import dev.inmo.micro_utils.pagination.Pagination
import dev.inmo.micro_utils.pagination.PaginationResult
import dev.inmo.micro_utils.pagination.utils.paginate
import dev.inmo.micro_utils.pagination.utils.reverse
import dev.inmo.micro_utils.repos.StandardKeyValueRepo
import dev.inmo.micro_utils.repos.KeyValueRepo
import kotlinx.coroutines.flow.*
private val cache = HashMap<String, KeyValueStore<*>>()
@@ -15,7 +15,7 @@ private val cache = HashMap<String, KeyValueStore<*>>()
fun <T : Any> Context.keyValueStore(
name: String = "default",
cacheValues: Boolean = false
): StandardKeyValueRepo<String, T> {
): KeyValueRepo<String, T> {
@Suppress("UNCHECKED_CAST")
return cache.getOrPut(name) {
KeyValueStore<T>(this, name, cacheValues)
@@ -26,7 +26,7 @@ class KeyValueStore<T : Any> internal constructor (
c: Context,
preferencesName: String,
useCache: Boolean = false
) : SharedPreferences.OnSharedPreferenceChangeListener, StandardKeyValueRepo<String, T> {
) : SharedPreferences.OnSharedPreferenceChangeListener, KeyValueRepo<String, T> {
private val sharedPreferences = c.getSharedPreferences(preferencesName, Context.MODE_PRIVATE)
private val cachedData = if (useCache) {
@@ -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)

View File

@@ -9,7 +9,6 @@ import dev.inmo.micro_utils.repos.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.KSerializer
import kotlinx.serialization.json.Json
@@ -26,7 +25,7 @@ class OneToManyAndroidRepo<Key, Value>(
private val keyFromString: String.() -> Key,
private val valueFromString: String.() -> Value,
private val helper: SQLiteOpenHelper
) : OneToManyKeyValueRepo<Key, Value> {
) : KeyValuesRepo<Key, Value> {
private val _onNewValue: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow()
override val onNewValue: Flow<Pair<Key, Value>> = _onNewValue.asSharedFlow()
private val _onValueRemoved: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow()

View File

@@ -4,13 +4,11 @@ package dev.inmo.micro_utils.repos.versions
import android.content.Context
import android.database.sqlite.SQLiteOpenHelper
import androidx.core.content.contentValuesOf
import dev.inmo.micro_utils.repos.*
import dev.inmo.micro_utils.repos.keyvalue.keyValueStore
import kotlinx.coroutines.runBlocking
/**
* Will create [VersionsRepo] based on [T], but versions will be stored in [StandardKeyValueRepo]
* Will create [VersionsRepo] based on [T], but versions will be stored in [KeyValueRepo]
*
* @receiver Will be used to create [KeyValueBasedVersionsRepoProxy] via [keyValueStore] and pass it to [StandardVersionsRepo]
*
@@ -26,9 +24,9 @@ inline fun <T> Context.versionsKeyValueRepo(
)
)
/**
* Will create [VersionsRepo] based on [SQLiteOpenHelper], but versions will be stored in [StandardKeyValueRepo]
* Will create [VersionsRepo] based on [SQLiteOpenHelper], but versions will be stored in [KeyValueRepo]
*
* @receiver Will be used to create [StandardKeyValueRepo] via [keyValueStore] and pass it to [StandardVersionsRepo]
* @receiver Will be used to create [KeyValueRepo] via [keyValueStore] and pass it to [StandardVersionsRepo]
*
* @see [keyValueStore]
*/
@@ -37,9 +35,9 @@ inline fun Context.versionsKeyValueRepoForSQL(
) = versionsKeyValueRepo(database)
/**
* Will create [VersionsRepo] based on [SQLiteOpenHelper], but versions will be stored in [StandardKeyValueRepo]
* Will create [VersionsRepo] based on [SQLiteOpenHelper], but versions will be stored in [KeyValueRepo]
*
* @param context Will be used to create [StandardKeyValueRepo] via [keyValueStore] and pass it to [StandardVersionsRepo]
* @param context Will be used to create [KeyValueRepo] via [keyValueStore] and pass it to [StandardVersionsRepo]
*
* @see [keyValueStore]
*/

View File

@@ -1,6 +1,6 @@
package dev.inmo.micro_utils.repos.exposed
import dev.inmo.micro_utils.repos.StandardCRUDRepo
import dev.inmo.micro_utils.repos.CRUDRepo
abstract class AbstractExposedCRUDRepo<ObjectType, IdType, InputValueType>(
flowsChannelsSize: Int = 0,
@@ -11,4 +11,4 @@ abstract class AbstractExposedCRUDRepo<ObjectType, IdType, InputValueType>(
tableName
),
ExposedCRUDRepo<ObjectType, IdType>,
StandardCRUDRepo<ObjectType, IdType, InputValueType>
CRUDRepo<ObjectType, IdType, InputValueType>

View File

@@ -1,14 +1,14 @@
package dev.inmo.micro_utils.repos.exposed
import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
import dev.inmo.micro_utils.repos.ReadCRUDRepo
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.transaction
abstract class AbstractExposedReadCRUDRepo<ObjectType, IdType>(
tableName: String
) :
ReadStandardCRUDRepo<ObjectType, IdType>,
ReadCRUDRepo<ObjectType, IdType>,
ExposedCRUDRepo<ObjectType, IdType>,
Table(tableName)
{

View File

@@ -1,7 +1,7 @@
package dev.inmo.micro_utils.repos.exposed
import dev.inmo.micro_utils.repos.UpdatedValuePair
import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo
import dev.inmo.micro_utils.repos.WriteCRUDRepo
import kotlinx.coroutines.flow.*
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.statements.InsertStatement
@@ -15,7 +15,7 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
) :
AbstractExposedReadCRUDRepo<ObjectType, IdType>(tableName),
ExposedCRUDRepo<ObjectType, IdType>,
WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>
WriteCRUDRepo<ObjectType, IdType, InputValueType>
{
protected val _newObjectsFlow = MutableSharedFlow<ObjectType>(replyCacheInFlows, flowsChannelsSize)
protected val _updatedObjectsFlow = MutableSharedFlow<ObjectType>(replyCacheInFlows, flowsChannelsSize)

View File

@@ -1,9 +1,7 @@
package dev.inmo.micro_utils.repos.exposed.keyvalue
import dev.inmo.micro_utils.repos.StandardKeyValueRepo
import dev.inmo.micro_utils.repos.KeyValueRepo
import dev.inmo.micro_utils.repos.exposed.ColumnAllocator
import dev.inmo.micro_utils.repos.exposed.initTable
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.*
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.transaction
@@ -13,7 +11,7 @@ open class ExposedKeyValueRepo<Key, Value>(
keyColumnAllocator: ColumnAllocator<Key>,
valueColumnAllocator: ColumnAllocator<Value>,
tableName: String? = null
) : StandardKeyValueRepo<Key, Value>, ExposedReadKeyValueRepo<Key, Value>(
) : KeyValueRepo<Key, Value>, ExposedReadKeyValueRepo<Key, Value>(
database,
keyColumnAllocator,
valueColumnAllocator,

View File

@@ -1,7 +1,7 @@
package dev.inmo.micro_utils.repos.exposed.keyvalue
import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
import dev.inmo.micro_utils.repos.exposed.*
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.transaction
@@ -11,7 +11,7 @@ open class ExposedReadKeyValueRepo<Key, Value>(
keyColumnAllocator: ColumnAllocator<Key>,
valueColumnAllocator: ColumnAllocator<Value>,
tableName: String? = null
) : ReadStandardKeyValueRepo<Key, Value>, ExposedRepo, Table(tableName ?: "") {
) : ReadKeyValueRepo<Key, Value>, ExposedRepo, Table(tableName ?: "") {
val keyColumn: Column<Key> = keyColumnAllocator()
val valueColumn: Column<Value> = valueColumnAllocator()
override val primaryKey: PrimaryKey = PrimaryKey(keyColumn, valueColumn)

View File

@@ -1,18 +1,18 @@
package dev.inmo.micro_utils.repos.exposed.onetomany
import dev.inmo.micro_utils.repos.OneToManyKeyValueRepo
import dev.inmo.micro_utils.repos.KeyValuesRepo
import dev.inmo.micro_utils.repos.exposed.ColumnAllocator
import kotlinx.coroutines.flow.*
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.transaction
typealias ExposedKeyValuesRepo<Key, Value> = ExposedOneToManyKeyValueRepo<Key, Value>
open class ExposedOneToManyKeyValueRepo<Key, Value>(
typealias ExposedOneToManyKeyValueRepo1<Key, Value> = ExposedKeyValuesRepo<Key, Value>
open class ExposedKeyValuesRepo<Key, Value>(
database: Database,
keyColumnAllocator: ColumnAllocator<Key>,
valueColumnAllocator: ColumnAllocator<Value>,
tableName: String? = null
) : OneToManyKeyValueRepo<Key, Value>, ExposedReadOneToManyKeyValueRepo<Key, Value>(
) : KeyValuesRepo<Key, Value>, ExposedReadKeyValuesRepo<Key, Value>(
database,
keyColumnAllocator,
valueColumnAllocator,

View File

@@ -1,20 +1,19 @@
package dev.inmo.micro_utils.repos.exposed.onetomany
import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
import dev.inmo.micro_utils.repos.exposed.*
import dev.inmo.micro_utils.repos.exposed.keyvalue.ExposedReadKeyValueRepo
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.transaction
typealias ExposedReadKeyValuesRepo<Key, Value> = ExposedReadOneToManyKeyValueRepo<Key, Value>
typealias ExposedReadOneToManyKeyValueRepo<Key, Value> = ExposedReadKeyValuesRepo<Key, Value>
open class ExposedReadOneToManyKeyValueRepo<Key, Value>(
open class ExposedReadKeyValuesRepo<Key, Value>(
override val database: Database,
keyColumnAllocator: ColumnAllocator<Key>,
valueColumnAllocator: ColumnAllocator<Value>,
tableName: String? = null
) : ReadOneToManyKeyValueRepo<Key, Value>, ExposedRepo, Table(tableName ?: "") {
) : ReadKeyValuesRepo<Key, Value>, ExposedRepo, Table(tableName ?: "") {
val keyColumn: Column<Key> = keyColumnAllocator()
val valueColumn: Column<Value> = valueColumnAllocator()

View File

@@ -5,7 +5,7 @@ import kotlinx.coroutines.flow.*
class ReadMapCRUDRepo<ObjectType, IdType>(
private val map: Map<IdType, ObjectType> = emptyMap()
) : ReadStandardCRUDRepo<ObjectType, IdType> {
) : ReadCRUDRepo<ObjectType, IdType> {
override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> {
return map.keys.drop(pagination.firstIndex).take(pagination.size).mapNotNull {
map[it]
@@ -24,7 +24,7 @@ class ReadMapCRUDRepo<ObjectType, IdType>(
abstract class WriteMapCRUDRepo<ObjectType, IdType, InputValueType>(
protected val map: MutableMap<IdType, ObjectType> = mutableMapOf()
) : WriteStandardCRUDRepo<ObjectType, IdType, InputValueType> {
) : WriteCRUDRepo<ObjectType, IdType, InputValueType> {
protected val _newObjectsFlow: MutableSharedFlow<ObjectType> = MutableSharedFlow()
override val newObjectsFlow: Flow<ObjectType> = _newObjectsFlow.asSharedFlow()
protected val _updatedObjectsFlow: MutableSharedFlow<ObjectType> = MutableSharedFlow()
@@ -68,25 +68,30 @@ abstract class WriteMapCRUDRepo<ObjectType, IdType, InputValueType>(
abstract class MapCRUDRepo<ObjectType, IdType, InputValueType>(
map: MutableMap<IdType, ObjectType>
) : StandardCRUDRepo<ObjectType, IdType, InputValueType>,
ReadStandardCRUDRepo<ObjectType, IdType> by ReadMapCRUDRepo(map),
) : CRUDRepo<ObjectType, IdType, InputValueType>,
ReadCRUDRepo<ObjectType, IdType> by ReadMapCRUDRepo(map),
WriteMapCRUDRepo<ObjectType, IdType, InputValueType>(map)
fun <ObjectType, IdType, InputValueType> MapCRUDRepo(
map: MutableMap<IdType, ObjectType>,
updateCallback: suspend (newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType,
createCallback: suspend (newValue: InputValueType) -> Pair<IdType, ObjectType>
updateCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType,
createCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType) -> Pair<IdType, ObjectType>
) = object : MapCRUDRepo<ObjectType, IdType, InputValueType>(map) {
override suspend fun updateObject(
newValue: InputValueType,
id: IdType,
old: ObjectType
): ObjectType = updateCallback(newValue, id, old)
): ObjectType = map.updateCallback(newValue, id, old)
override suspend fun createObject(newValue: InputValueType): Pair<IdType, ObjectType> = createCallback(newValue)
override suspend fun createObject(newValue: InputValueType): Pair<IdType, ObjectType> = map.createCallback(newValue)
}
fun <ObjectType, IdType, InputValueType> MapCRUDRepo(
updateCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType,
createCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType) -> Pair<IdType, ObjectType>
) = MapCRUDRepo(mutableMapOf(), updateCallback, createCallback)
fun <ObjectType, IdType, InputValueType> MutableMap<IdType, ObjectType>.asCrudRepo(
updateCallback: suspend (newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType,
createCallback: suspend (newValue: InputValueType) -> Pair<IdType, ObjectType>
updateCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType,
createCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType) -> Pair<IdType, ObjectType>
) = MapCRUDRepo(this, updateCallback, createCallback)

View File

@@ -9,7 +9,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
class ReadMapKeyValueRepo<Key, Value>(
protected val map: Map<Key, Value> = emptyMap()
) : ReadStandardKeyValueRepo<Key, Value> {
) : ReadKeyValueRepo<Key, Value> {
override suspend fun get(k: Key): Value? = map[k]
override suspend fun values(
@@ -58,7 +58,7 @@ class ReadMapKeyValueRepo<Key, Value>(
class WriteMapKeyValueRepo<Key, Value>(
private val map: MutableMap<Key, Value> = mutableMapOf()
) : WriteStandardKeyValueRepo<Key, Value> {
) : WriteKeyValueRepo<Key, Value> {
private val _onNewValue: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow()
override val onNewValue: Flow<Pair<Key, Value>>
get() = _onNewValue
@@ -78,19 +78,19 @@ class WriteMapKeyValueRepo<Key, Value>(
}
override suspend fun unsetWithValues(toUnset: List<Value>) {
map.forEach {
if (it.value in toUnset) {
map.remove(it.key)
_onValueRemoved.emit(it.key)
}
map.mapNotNull { (k, v) ->
k.takeIf { v in toUnset }
}.forEach {
map.remove(it)
_onValueRemoved.emit(it)
}
}
}
class MapKeyValueRepo<Key, Value>(
private val map: MutableMap<Key, Value> = mutableMapOf()
) : StandardKeyValueRepo<Key, Value>,
ReadStandardKeyValueRepo<Key, Value> by ReadMapKeyValueRepo(map),
WriteStandardKeyValueRepo<Key, Value> by WriteMapKeyValueRepo(map)
) : KeyValueRepo<Key, Value>,
ReadKeyValueRepo<Key, Value> by ReadMapKeyValueRepo(map),
WriteKeyValueRepo<Key, Value> by WriteMapKeyValueRepo(map)
fun <K, V> MutableMap<K, V>.asKeyValueRepo(): StandardKeyValueRepo<K, V> = MapKeyValueRepo(this)
fun <K, V> MutableMap<K, V>.asKeyValueRepo(): KeyValueRepo<K, V> = MapKeyValueRepo(this)

View File

@@ -5,9 +5,11 @@ import dev.inmo.micro_utils.pagination.utils.paginate
import dev.inmo.micro_utils.pagination.utils.reverse
import kotlinx.coroutines.flow.*
class MapReadOneToManyKeyValueRepo<Key, Value>(
@Deprecated("Renamed", ReplaceWith("MapReadKeyValuesRepo", "dev.inmo.micro_utils.repos.MapReadKeyValuesRepo"))
typealias MapReadOneToManyKeyValueRepo<Key, Value> = MapReadKeyValuesRepo<Key, Value>
class MapReadKeyValuesRepo<Key, Value>(
private val map: Map<Key, List<Value>> = emptyMap()
) : ReadOneToManyKeyValueRepo<Key, Value> {
) : ReadKeyValuesRepo<Key, Value> {
override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
val list = map[k] ?: return emptyPaginationResult()
@@ -53,9 +55,11 @@ class MapReadOneToManyKeyValueRepo<Key, Value>(
override suspend fun count(): Long = map.size.toLong()
}
class MapWriteOneToManyKeyValueRepo<Key, Value>(
@Deprecated("Renamed", ReplaceWith("MapWriteKeyValuesRepo", "dev.inmo.micro_utils.repos.MapWriteKeyValuesRepo"))
typealias MapWriteOneToManyKeyValueRepo<Key, Value> = MapWriteKeyValuesRepo<Key, Value>
class MapWriteKeyValuesRepo<Key, Value>(
private val map: MutableMap<Key, MutableList<Value>> = mutableMapOf()
) : WriteOneToManyKeyValueRepo<Key, Value> {
) : WriteKeyValuesRepo<Key, Value> {
private val _onNewValue: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow()
override val onNewValue: Flow<Pair<Key, Value>> = _onNewValue.asSharedFlow()
private val _onValueRemoved: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow()
@@ -80,6 +84,10 @@ class MapWriteOneToManyKeyValueRepo<Key, Value>(
_onValueRemoved.emit(k to v)
}
}
if (map[k] ?.isEmpty() == true) {
map.remove(k)
_onDataCleared.emit(k)
}
}
}
@@ -94,12 +102,17 @@ class MapWriteOneToManyKeyValueRepo<Key, Value>(
}
}
class MapOneToManyKeyValueRepo<Key, Value>(
@Deprecated("Renamed", ReplaceWith("MapKeyValuesRepo", "dev.inmo.micro_utils.repos.MapKeyValuesRepo"))
typealias MapOneToManyKeyValueRepo1<Key, Value> = MapKeyValuesRepo<Key, Value>
class MapKeyValuesRepo<Key, Value>(
private val map: MutableMap<Key, MutableList<Value>> = mutableMapOf()
) : OneToManyKeyValueRepo<Key, Value>,
ReadOneToManyKeyValueRepo<Key, Value> by MapReadOneToManyKeyValueRepo(map),
WriteOneToManyKeyValueRepo<Key, Value> by MapWriteOneToManyKeyValueRepo(map)
) : KeyValuesRepo<Key, Value>,
ReadKeyValuesRepo<Key, Value> by MapReadKeyValuesRepo(map),
WriteKeyValuesRepo<Key, Value> by MapWriteKeyValuesRepo(map)
fun <K, V> MutableMap<K, List<V>>.asOneToManyKeyValueRepo(): OneToManyKeyValueRepo<K, V> = MapOneToManyKeyValueRepo(
fun <K, V> MutableMap<K, List<V>>.asKeyValuesRepo(): KeyValuesRepo<K, V> = MapKeyValuesRepo(
map { (k, v) -> k to v.toMutableList() }.toMap().toMutableMap()
)
@Deprecated("Renamed", ReplaceWith("asKeyValuesRepo", "dev.inmo.micro_utils.repos.asKeyValuesRepo"))
fun <K, V> MutableMap<K, List<V>>.asOneToManyKeyValueRepo(): KeyValuesRepo<K, V> = asKeyValuesRepo()

View File

@@ -0,0 +1,121 @@
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.http.ContentType
import io.ktor.util.reflect.TypeInfo
import io.ktor.util.reflect.typeInfo
import kotlinx.serialization.*
class KtorCRUDRepoClient<ObjectType, IdType, InputValue> (
readDelegate: ReadCRUDRepo<ObjectType, IdType>,
writeDelegate: WriteCRUDRepo<ObjectType, IdType, InputValue>
) : CRUDRepo<ObjectType, IdType, InputValue> by DelegateBasedCRUDRepo(
readDelegate,
writeDelegate
) {
companion object {
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,
contentType,
idSerializer
),
KtorWriteCrudRepoClient<ObjectType, IdType, InputValue>(
baseUrl,
httpClient,
contentType
)
)
inline operator fun <reified ObjectType, reified IdType, reified InputValue> invoke(
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,
idsSerializer: KSerializer<IdType>,
serialFormat: StringFormat,
contentType: ContentType,
) = KtorCRUDRepoClient<ObjectType, IdType, InputValue>(baseUrl, httpClient, contentType) {
serialFormat.encodeToString(idsSerializer, it)
}
inline fun <reified ObjectType, reified IdType, reified InputValue> KtorCRUDRepoClient(
baseUrl: String,
httpClient: HttpClient,
idsSerializer: KSerializer<IdType>,
serialFormat: BinaryFormat,
contentType: ContentType,
) = KtorCRUDRepoClient<ObjectType, IdType, InputValue>(baseUrl, httpClient, contentType) {
serialFormat.encodeHex(idsSerializer, it)
}
inline fun <reified ObjectType, reified IdType, reified InputValue> KtorCRUDRepoClient(
baseUrl: String,
subpart: String,
httpClient: HttpClient,
contentType: ContentType,
noinline idSerializer: suspend (IdType) -> String
) = KtorCRUDRepoClient<ObjectType, IdType, InputValue>(
buildStandardUrl(baseUrl, subpart),
httpClient,
contentType,
idSerializer
)
inline fun <reified ObjectType, reified IdType, reified InputValue> KtorCRUDRepoClient(
baseUrl: String,
subpart: String,
httpClient: HttpClient,
idsSerializer: KSerializer<IdType>,
serialFormat: StringFormat,
contentType: ContentType,
) = KtorCRUDRepoClient<ObjectType, IdType, InputValue>(buildStandardUrl(baseUrl, subpart), httpClient, idsSerializer, serialFormat, contentType)
inline fun <reified ObjectType, reified IdType, reified InputValue> KtorCRUDRepoClient(
baseUrl: String,
subpart: String,
httpClient: HttpClient,
idsSerializer: KSerializer<IdType>,
serialFormat: BinaryFormat,
contentType: ContentType,
) = KtorCRUDRepoClient<ObjectType, IdType, InputValue>(buildStandardUrl(baseUrl, subpart), httpClient, idsSerializer, serialFormat, contentType)

View File

@@ -0,0 +1,95 @@
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.ReadCRUDRepo
import dev.inmo.micro_utils.repos.ktor.common.countRouting
import dev.inmo.micro_utils.repos.ktor.common.crud.*
import dev.inmo.micro_utils.repos.ktor.common.idParameterName
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.request.get
import io.ktor.http.*
import io.ktor.util.reflect.TypeInfo
import io.ktor.util.reflect.typeInfo
import kotlinx.serialization.*
class KtorReadCRUDRepoClient<ObjectType, IdType> (
private val baseUrl: String,
private val httpClient: HttpClient,
private val objectType: TypeInfo,
private val contentType: ContentType,
private val idSerializer: suspend (IdType) -> String
) : ReadCRUDRepo<ObjectType, IdType> {
override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> = httpClient.get(
buildStandardUrl(baseUrl, getByPaginationRouting, pagination.asUrlQueryParts)
) {
contentType(contentType)
}.body()
override suspend fun getById(id: IdType): ObjectType? = httpClient.get(
buildStandardUrl(
baseUrl,
getByIdRouting,
mapOf(
idParameterName to idSerializer(id)
)
)
) {
contentType(contentType)
}.takeIf { it.status != HttpStatusCode.NoContent } ?.body<ObjectType>(objectType)
override suspend fun contains(id: IdType): Boolean = httpClient.get(
buildStandardUrl(
baseUrl,
containsRouting,
mapOf(
idParameterName to idSerializer(id)
)
)
) {
contentType(contentType)
}.body()
override suspend fun count(): Long = httpClient.get(
buildStandardUrl(
baseUrl,
countRouting
)
) {
contentType(contentType)
}.body()
}
inline fun <reified ObjectType, IdType> KtorReadCRUDRepoClient(
baseUrl: String,
httpClient: HttpClient,
contentType: ContentType,
noinline idSerializer: suspend (IdType) -> String
) = KtorReadCRUDRepoClient<ObjectType, IdType>(
baseUrl,
httpClient,
typeInfo<ObjectType>(),
contentType,
idSerializer
)
inline fun <reified ObjectType, IdType> KtorReadCRUDRepoClient(
baseUrl: String,
httpClient: HttpClient,
idsSerializer: KSerializer<IdType>,
serialFormat: StringFormat,
contentType: ContentType,
) = KtorReadCRUDRepoClient<ObjectType, IdType>(baseUrl, httpClient, contentType) {
serialFormat.encodeToString(idsSerializer, it)
}
inline fun <reified ObjectType, IdType> KtorReadCRUDRepoClient(
baseUrl: String,
httpClient: HttpClient,
idsSerializer: KSerializer<IdType>,
serialFormat: BinaryFormat,
contentType: ContentType,
) = KtorReadCRUDRepoClient<ObjectType, IdType>(baseUrl, httpClient, contentType) {
serialFormat.encodeHex(idsSerializer, it)
}

View File

@@ -3,19 +3,22 @@ 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.pagination.*
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
import dev.inmo.micro_utils.repos.ReadCRUDRepo
import dev.inmo.micro_utils.repos.ktor.common.countRouting
import dev.inmo.micro_utils.repos.ktor.common.crud.*
import dev.inmo.micro_utils.repos.ktor.common.idParameterName
import io.ktor.client.HttpClient
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.serializer
@Deprecated("Use KtorReadCRUDRepoClient instead")
class KtorReadStandardCrudRepo<ObjectType, IdType> (
private val baseUrl: String,
private val unifiedRequester: UnifiedRequester,
private val objectsSerializer: KSerializer<ObjectType>,
private val objectsSerializerNullable: KSerializer<ObjectType?>,
private val idsSerializer: KSerializer<IdType>
) : ReadStandardCRUDRepo<ObjectType, IdType> {
) : ReadCRUDRepo<ObjectType, IdType> {
private val paginationResultSerializer = PaginationResult.serializer(objectsSerializer)
constructor(
@@ -38,9 +41,7 @@ class KtorReadStandardCrudRepo<ObjectType, IdType> (
buildStandardUrl(
baseUrl,
getByIdRouting,
mapOf(
"id" to unifiedRequester.encodeUrlQueryValue(idsSerializer, id)
)
idParameterName to unifiedRequester.encodeUrlQueryValue(idsSerializer, id)
),
objectsSerializerNullable
)
@@ -49,9 +50,7 @@ class KtorReadStandardCrudRepo<ObjectType, IdType> (
buildStandardUrl(
baseUrl,
containsRouting,
mapOf(
"id" to unifiedRequester.encodeUrlQueryValue(idsSerializer, id)
)
idParameterName to unifiedRequester.encodeUrlQueryValue(idsSerializer, id)
),
Boolean.serializer()
)

View File

@@ -7,6 +7,7 @@ import dev.inmo.micro_utils.repos.*
import io.ktor.client.HttpClient
import kotlinx.serialization.KSerializer
@Deprecated("Use KtorCRUDRepoClient instead")
class KtorStandardCrudRepo<ObjectType, IdType, InputValue> (
baseUrl: String,
baseSubpart: String,
@@ -15,15 +16,15 @@ class KtorStandardCrudRepo<ObjectType, IdType, InputValue> (
objectsNullableSerializer: KSerializer<ObjectType?>,
inputsSerializer: KSerializer<InputValue>,
idsSerializer: KSerializer<IdType>
) : StandardCRUDRepo<ObjectType, IdType, InputValue>,
ReadStandardCRUDRepo<ObjectType, IdType> by KtorReadStandardCrudRepo(
) : CRUDRepo<ObjectType, IdType, InputValue>,
ReadCRUDRepo<ObjectType, IdType> by KtorReadStandardCrudRepo(
"$baseUrl/$baseSubpart",
unifiedRequester,
objectsSerializer,
objectsNullableSerializer,
idsSerializer
),
WriteStandardCRUDRepo<ObjectType, IdType, InputValue> by KtorWriteStandardCrudRepo(
WriteCRUDRepo<ObjectType, IdType, InputValue> by KtorWriteStandardCrudRepo(
"$baseUrl/$baseSubpart",
unifiedRequester,
objectsSerializer,

View File

@@ -0,0 +1,85 @@
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.WriteCRUDRepo
import dev.inmo.micro_utils.repos.ktor.common.crud.*
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.request.*
import io.ktor.client.statement.HttpResponse
import io.ktor.http.ContentType
import io.ktor.http.contentType
import kotlinx.coroutines.flow.Flow
class KtorWriteCrudRepoClient<ObjectType, IdType, InputValue> (
private val baseUrl: String,
private val httpClient: HttpClient,
override val newObjectsFlow: Flow<ObjectType>,
override val updatedObjectsFlow: Flow<ObjectType>,
override val deletedObjectsIdsFlow: Flow<IdType>,
private val createSetup: suspend HttpRequestBuilder.(List<InputValue>) -> Unit,
private val updateSetup: suspend HttpRequestBuilder.(List<UpdatedValuePair<IdType, InputValue>>) -> Unit,
private val deleteByIdSetup: suspend HttpRequestBuilder.(List<IdType>) -> Unit,
private val createBodyGetter: suspend HttpResponse.() -> List<ObjectType>,
private val updateBodyGetter: suspend HttpResponse.() -> List<ObjectType>
) : WriteCRUDRepo<ObjectType, IdType, InputValue> {
override suspend fun create(values: List<InputValue>): List<ObjectType> = httpClient.post(
buildStandardUrl(baseUrl, createRouting)
) {
createSetup(values)
}.createBodyGetter()
override suspend fun update(
values: List<UpdatedValuePair<IdType, InputValue>>
): List<ObjectType> = httpClient.post(
buildStandardUrl(baseUrl, updateRouting)
) {
updateSetup(values)
}.updateBodyGetter()
override suspend fun update(id: IdType, value: InputValue): ObjectType? = update(listOf(id to value)).firstOrNull()
override suspend fun deleteById(ids: List<IdType>) {
httpClient.post(
buildStandardUrl(baseUrl, deleteByIdRouting)
) {
deleteByIdSetup(ids)
}.throwOnUnsuccess { "Unable to delete $ids" }
}
companion object {
inline operator fun <reified ObjectType, reified IdType, reified InputValue> invoke(
baseUrl: String,
httpClient: HttpClient,
contentType: ContentType
) = KtorWriteCrudRepoClient<ObjectType, IdType, InputValue>(
baseUrl,
httpClient,
httpClient.createStandardWebsocketFlow(
buildStandardUrl(baseUrl, newObjectsFlowRouting),
),
httpClient.createStandardWebsocketFlow(
buildStandardUrl(baseUrl, updatedObjectsFlowRouting),
),
httpClient.createStandardWebsocketFlow(
buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting),
),
{
contentType(contentType)
setBody(it)
},
{
contentType(contentType)
setBody(it)
},
{
contentType(contentType)
setBody(it)
},
{ body() },
{ body() }
)
}
}

View File

@@ -3,13 +3,14 @@ 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.WriteCRUDRepo
import dev.inmo.micro_utils.repos.ktor.common.crud.*
import io.ktor.client.HttpClient
import kotlinx.coroutines.flow.Flow
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.*
@Deprecated("Use KtorWriteCRUDRepoClient instead")
class KtorWriteStandardCrudRepo<ObjectType, IdType, InputValue> (
private val baseUrl: String,
private val unifiedRequester: UnifiedRequester,
@@ -17,7 +18,7 @@ class KtorWriteStandardCrudRepo<ObjectType, IdType, InputValue> (
private val objectsNullableSerializer: KSerializer<ObjectType?>,
private val inputsSerializer: KSerializer<InputValue>,
private val idsSerializer: KSerializer<IdType>
) : WriteStandardCRUDRepo<ObjectType, IdType, InputValue> {
) : WriteCRUDRepo<ObjectType, IdType, InputValue> {
private val listObjectsSerializer = ListSerializer(objectsSerializer)
private val listInputSerializer = ListSerializer(inputsSerializer)
private val listIdsSerializer = ListSerializer(idsSerializer)

View File

@@ -0,0 +1,85 @@
package dev.inmo.micro_utils.repos.ktor.client.key.value
import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.repos.*
import io.ktor.client.HttpClient
import io.ktor.http.ContentType
import io.ktor.http.encodeURLQueryComponent
import kotlinx.serialization.*
class KtorKeyValueRepoClient<Key, Value> (
readDelegate: ReadKeyValueRepo<Key, Value>,
writeDelegate: WriteKeyValueRepo<Key, Value>
) : KeyValueRepo<Key, Value> by DelegateBasedKeyValueRepo(
readDelegate,
writeDelegate
) {
companion object {
inline operator fun <reified Key, reified Value> invoke(
baseUrl: String,
httpClient: HttpClient,
contentType: ContentType,
noinline idSerializer: suspend (Key) -> String,
noinline valueSerializer: suspend (Value) -> String
) = KtorKeyValueRepoClient(
KtorReadKeyValueRepoClient(
baseUrl, httpClient, contentType, idSerializer, valueSerializer
),
KtorWriteKeyValueRepoClient(
baseUrl,
httpClient,
contentType
)
)
inline operator fun <reified Key, reified Value> invoke(
baseUrl: String,
subpart: String,
httpClient: HttpClient,
contentType: ContentType,
noinline idSerializer: suspend (Key) -> String,
noinline valueSerializer: suspend (Value) -> String
) = KtorKeyValueRepoClient(
buildStandardUrl(baseUrl, subpart),
httpClient,
contentType,
idSerializer,
valueSerializer
)
}
}
inline fun <reified Key, reified Value> KtorKeyValueRepoClient(
baseUrl: String,
httpClient: HttpClient,
contentType: ContentType,
idSerializer: SerializationStrategy<Key>,
valueSerializer: SerializationStrategy<Value>,
serialFormat: StringFormat,
) = KtorKeyValueRepoClient<Key, Value>(
baseUrl,
httpClient,
contentType,
{
serialFormat.encodeToString(idSerializer, it).encodeURLQueryComponent()
}
) {
serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent()
}
inline fun <reified Key, reified Value> KtorKeyValueRepoClient(
baseUrl: String,
httpClient: HttpClient,
contentType: ContentType,
idSerializer: SerializationStrategy<Key>,
valueSerializer: SerializationStrategy<Value>,
serialFormat: BinaryFormat,
) = KtorKeyValueRepoClient<Key, Value>(
baseUrl,
httpClient,
contentType,
{
serialFormat.encodeHex(idSerializer, it)
}
) {
serialFormat.encodeHex(valueSerializer, it)
}

View File

@@ -0,0 +1,144 @@
package dev.inmo.micro_utils.repos.ktor.client.key.value
import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
import dev.inmo.micro_utils.repos.ktor.common.*
import dev.inmo.micro_utils.repos.ktor.common.containsRoute
import dev.inmo.micro_utils.repos.ktor.common.keyParameterName
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.request.get
import io.ktor.http.*
import io.ktor.util.reflect.TypeInfo
import io.ktor.util.reflect.typeInfo
import kotlinx.serialization.*
class KtorReadKeyValueRepoClient<Key, Value>(
private val baseUrl: String,
private val httpClient: HttpClient,
private val contentType: ContentType,
private val objectType: TypeInfo,
private val paginationResultObjectsTypeInfo: TypeInfo,
private val paginationResultIdsTypeInfo: TypeInfo,
private val idSerializer: suspend (Key) -> String,
private val valueSerializer: suspend (Value) -> String
) : ReadKeyValueRepo<Key, Value> {
override suspend fun get(k: Key): Value? = httpClient.get(
buildStandardUrl(
baseUrl,
getRoute,
mapOf(
keyParameterName to idSerializer(k)
)
)
) {
contentType(contentType)
}.takeIf { it.status != HttpStatusCode.NoContent } ?.body<Value>(objectType)
override suspend fun contains(key: Key): Boolean = httpClient.get(
buildStandardUrl(
baseUrl,
containsRoute,
keyParameterName to idSerializer(key)
)
) {
contentType(contentType)
}.body()
override suspend fun values(
pagination: Pagination,
reversed: Boolean
): PaginationResult<Value> = httpClient.get(
buildStandardUrl(baseUrl, valuesRoute, pagination.asUrlQueryParts + (reversedParameterName to reversed.toString()))
) {
contentType(contentType)
}.body(paginationResultObjectsTypeInfo)
override suspend fun keys(
pagination: Pagination,
reversed: Boolean
): PaginationResult<Key> = httpClient.get(
buildStandardUrl(baseUrl, keysRoute, pagination.asUrlQueryParts + (reversedParameterName to reversed.toString()))
) {
contentType(contentType)
}.body(paginationResultIdsTypeInfo)
override suspend fun keys(
v: Value,
pagination: Pagination,
reversed: Boolean
): PaginationResult<Key> = httpClient.get(
buildStandardUrl(
baseUrl,
keysRoute,
pagination.asUrlQueryParts + (reversedParameterName to reversed.toString()) + (valueParameterName to valueSerializer(v))
)
) {
contentType(contentType)
}.body(paginationResultIdsTypeInfo)
override suspend fun count(): Long = httpClient.get(
buildStandardUrl(
baseUrl,
dev.inmo.micro_utils.repos.ktor.common.countRoute
)
) {
contentType(contentType)
}.body()
}
inline fun <reified Key, reified Value> KtorReadKeyValueRepoClient(
baseUrl: String,
httpClient: HttpClient,
contentType: ContentType,
noinline idSerializer: suspend (Key) -> String,
noinline valueSerializer: suspend (Value) -> String
) = KtorReadKeyValueRepoClient<Key, Value>(
baseUrl,
httpClient,
contentType,
typeInfo<Value>(),
typeInfo<PaginationResult<Value>>(),
typeInfo<PaginationResult<Key>>(),
idSerializer,
valueSerializer
)
inline fun <reified Key, reified Value> KtorReadKeyValueRepoClient(
baseUrl: String,
httpClient: HttpClient,
idsSerializer: KSerializer<Key>,
valueSerializer: KSerializer<Value>,
serialFormat: StringFormat,
contentType: ContentType,
) = KtorReadKeyValueRepoClient<Key, Value>(
baseUrl,
httpClient,
contentType,
{
serialFormat.encodeToString(idsSerializer, it).encodeURLQueryComponent()
}
) {
serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent()
}
inline fun <reified Key, reified Value> KtorReadKeyValueRepoClient(
baseUrl: String,
httpClient: HttpClient,
idsSerializer: KSerializer<Key>,
valuesSerializer: KSerializer<Value>,
serialFormat: BinaryFormat,
contentType: ContentType,
) = KtorReadKeyValueRepoClient<Key, Value>(
baseUrl,
httpClient,
contentType,
{
serialFormat.encodeHex(idsSerializer, it)
}
) {
serialFormat.encodeHex(valuesSerializer, it)
}

View File

@@ -0,0 +1,79 @@
package dev.inmo.micro_utils.repos.ktor.client.key.value
import dev.inmo.micro_utils.ktor.client.createStandardWebsocketFlow
import dev.inmo.micro_utils.ktor.client.throwOnUnsuccess
import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.repos.WriteKeyValueRepo
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
import io.ktor.client.HttpClient
import io.ktor.client.request.post
import io.ktor.http.*
import io.ktor.util.InternalAPI
import io.ktor.util.reflect.TypeInfo
import io.ktor.util.reflect.typeInfo
import kotlinx.coroutines.flow.Flow
class KtorWriteKeyValueRepoClient<Key, Value>(
private val baseUrl: String,
private val httpClient: HttpClient,
private val contentType: ContentType,
override val onNewValue: Flow<Pair<Key, Value>>,
override val onValueRemoved: Flow<Key>,
private val idsListTypeInfo: TypeInfo,
private val objectsListTypeInfo: TypeInfo,
private val idsToObjectsMapTypeInfo: TypeInfo
) : WriteKeyValueRepo<Key, Value> {
@OptIn(InternalAPI::class)
override suspend fun unsetWithValues(toUnset: List<Value>) {
httpClient.post(
buildStandardUrl(baseUrl, unsetWithValuesRoute)
) {
body = toUnset
bodyType = objectsListTypeInfo
contentType(contentType)
}.throwOnUnsuccess { "Unable to unset data with values $toUnset" }
}
@OptIn(InternalAPI::class)
override suspend fun unset(toUnset: List<Key>) {
httpClient.post(
buildStandardUrl(baseUrl, unsetRoute)
) {
body = toUnset
bodyType = idsListTypeInfo
contentType(contentType)
}.throwOnUnsuccess { "Unable to unset $toUnset" }
}
@OptIn(InternalAPI::class)
override suspend fun set(toSet: Map<Key, Value>) {
httpClient.post(
buildStandardUrl(baseUrl, setRoute)
) {
body = toSet
bodyType = idsToObjectsMapTypeInfo
contentType(contentType)
}.throwOnUnsuccess { "Unable to set $toSet" }
}
companion object {
inline operator fun <reified Key, reified Value> invoke(
baseUrl: String,
httpClient: HttpClient,
contentType: ContentType
) = KtorWriteKeyValueRepoClient<Key, Value>(
baseUrl,
httpClient,
contentType,
httpClient.createStandardWebsocketFlow(
buildStandardUrl(baseUrl, onNewValueRoute),
),
httpClient.createStandardWebsocketFlow(
buildStandardUrl(baseUrl, onValueRemovedRoute),
),
typeInfo<List<Key>>(),
typeInfo<List<Value>>(),
typeInfo<Map<Key, Value>>()
)
}
}

View File

@@ -0,0 +1,89 @@
package dev.inmo.micro_utils.repos.ktor.client.key.values
import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.repos.*
import io.ktor.client.HttpClient
import io.ktor.http.ContentType
import io.ktor.http.encodeURLQueryComponent
import kotlinx.serialization.*
class KtorKeyValuesRepoClient<Key, Value> (
readDelegate: ReadKeyValuesRepo<Key, Value>,
writeDelegate: WriteKeyValuesRepo<Key, Value>
) : KeyValuesRepo<Key, Value> by DelegateBasedKeyValuesRepo(
readDelegate,
writeDelegate
) {
companion object {
inline operator fun <reified Key : Any, reified Value : Any> invoke(
baseUrl: String,
httpClient: HttpClient,
contentType: ContentType,
noinline keySerializer: suspend (Key) -> String,
noinline valueSerializer: suspend (Value) -> String
) = KtorKeyValuesRepoClient(
KtorReadKeyValuesRepoClient(
baseUrl,
httpClient,
contentType,
keySerializer,
valueSerializer
),
KtorWriteKeyValuesRepoClient(
baseUrl,
httpClient,
contentType
)
)
inline operator fun <reified Key : Any, reified Value : Any> invoke(
baseUrl: String,
subpart: String,
httpClient: HttpClient,
contentType: ContentType,
noinline keySerializer: suspend (Key) -> String,
noinline valueSerializer: suspend (Value) -> String
) = KtorKeyValuesRepoClient(
buildStandardUrl(baseUrl, subpart),
httpClient,
contentType,
keySerializer,
valueSerializer
)
}
}
inline fun <reified Key : Any, reified Value : Any> KtorKeyValuesRepoClient(
baseUrl: String,
httpClient: HttpClient,
contentType: ContentType,
keySerializer: SerializationStrategy<Key>,
valueSerializer: SerializationStrategy<Value>,
serialFormat: StringFormat,
) = KtorKeyValuesRepoClient<Key, Value>(
baseUrl,
httpClient,
contentType,
{
serialFormat.encodeToString(keySerializer, it).encodeURLQueryComponent()
}
) {
serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent()
}
inline fun <reified Key : Any, reified Value : Any> KtorKeyValuesRepoClient(
baseUrl: String,
httpClient: HttpClient,
contentType: ContentType,
keySerializer: SerializationStrategy<Key>,
valueSerializer: SerializationStrategy<Value>,
serialFormat: BinaryFormat,
) = KtorKeyValuesRepoClient<Key, Value>(
baseUrl,
httpClient,
contentType,
{
serialFormat.encodeHex(keySerializer, it)
}
) {
serialFormat.encodeHex(valueSerializer, it)
}

View File

@@ -0,0 +1,158 @@
package dev.inmo.micro_utils.repos.ktor.client.key.values
import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
import dev.inmo.micro_utils.repos.ktor.common.*
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.request.get
import io.ktor.http.*
import io.ktor.util.reflect.TypeInfo
import io.ktor.util.reflect.typeInfo
import kotlinx.serialization.*
class KtorReadKeyValuesRepoClient<Key, Value>(
private val baseUrl: String,
private val httpClient: HttpClient,
private val contentType: ContentType,
private val paginationResultValuesTypeInfo: TypeInfo,
private val paginationResultKeysTypeInfo: TypeInfo,
private val keySerializer: suspend (Key) -> String,
private val valueSerializer: suspend (Value) -> String
) : ReadKeyValuesRepo<Key, Value> {
override suspend fun get(
k: Key,
pagination: Pagination,
reversed: Boolean
): PaginationResult<Value> = httpClient.get(
buildStandardUrl(
baseUrl,
getRoute,
pagination.asUrlQueryParts + (reversedParameterName to reversed.toString()) + (keyParameterName to keySerializer(k))
)
) {
contentType(contentType)
}.body(paginationResultValuesTypeInfo)
override suspend fun keys(
pagination: Pagination,
reversed: Boolean
): PaginationResult<Key> = httpClient.get(
buildStandardUrl(
baseUrl,
keysRoute,
pagination.asUrlQueryParts + (reversedParameterName to reversed.toString())
)
) {
contentType(contentType)
}.body(paginationResultKeysTypeInfo)
override suspend fun keys(
v: Value,
pagination: Pagination,
reversed: Boolean
): PaginationResult<Key> = httpClient.get(
buildStandardUrl(
baseUrl,
keysRoute,
pagination.asUrlQueryParts + (reversedParameterName to reversed.toString()) + (valueParameterName to valueSerializer(v))
)
) {
contentType(contentType)
}.body(paginationResultKeysTypeInfo)
override suspend fun contains(k: Key): Boolean = httpClient.get(
buildStandardUrl(
baseUrl,
containsRoute,
keyParameterName to keySerializer(k)
)
) {
contentType(contentType)
}.body()
override suspend fun contains(k: Key, v: Value): Boolean = httpClient.get(
buildStandardUrl(
baseUrl,
containsRoute,
keyParameterName to keySerializer(k),
valueParameterName to valueSerializer(v)
)
) {
contentType(contentType)
}.body()
override suspend fun count(): Long = httpClient.get(
buildStandardUrl(
baseUrl,
countRouting
)
) {
contentType(contentType)
}.body()
override suspend fun count(k: Key): Long = httpClient.get(
buildStandardUrl(
baseUrl,
countRouting,
keyParameterName to keySerializer(k),
)
) {
contentType(contentType)
}.body()
}
inline fun <reified Key, reified Value> KtorReadKeyValuesRepoClient(
baseUrl: String,
httpClient: HttpClient,
contentType: ContentType,
noinline keySerializer: suspend (Key) -> String,
noinline valueSerializer: suspend (Value) -> String
) = KtorReadKeyValuesRepoClient<Key, Value>(
baseUrl,
httpClient,
contentType,
typeInfo<PaginationResult<Value>>(),
typeInfo<PaginationResult<Key>>(),
keySerializer,
valueSerializer
)
inline fun <reified Key, reified Value> KtorReadKeyValuesRepoClient(
baseUrl: String,
httpClient: HttpClient,
idsSerializer: KSerializer<Key>,
valueSerializer: KSerializer<Value>,
serialFormat: StringFormat,
contentType: ContentType,
) = KtorReadKeyValuesRepoClient<Key, Value>(
baseUrl,
httpClient,
contentType,
{
serialFormat.encodeToString(idsSerializer, it).encodeURLQueryComponent()
}
) {
serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent()
}
inline fun <reified Key, reified Value> KtorReadKeyValuesRepoClient(
baseUrl: String,
httpClient: HttpClient,
idsSerializer: KSerializer<Key>,
valuesSerializer: KSerializer<Value>,
serialFormat: BinaryFormat,
contentType: ContentType,
) = KtorReadKeyValuesRepoClient<Key, Value>(
baseUrl,
httpClient,
contentType,
{
serialFormat.encodeHex(idsSerializer, it)
}
) {
serialFormat.encodeHex(valuesSerializer, it)
}

View File

@@ -0,0 +1,106 @@
package dev.inmo.micro_utils.repos.ktor.client.key.values
import dev.inmo.micro_utils.ktor.client.createStandardWebsocketFlow
import dev.inmo.micro_utils.ktor.client.throwOnUnsuccess
import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.repos.WriteKeyValuesRepo
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
import io.ktor.client.HttpClient
import io.ktor.client.request.post
import io.ktor.http.*
import io.ktor.util.InternalAPI
import io.ktor.util.reflect.TypeInfo
import io.ktor.util.reflect.typeInfo
import kotlinx.coroutines.flow.Flow
class KtorWriteKeyValuesRepoClient<Key : Any, Value : Any>(
private val baseUrl: String,
private val httpClient: HttpClient,
private val contentType: ContentType,
override val onNewValue: Flow<Pair<Key, Value>>,
override val onValueRemoved: Flow<Pair<Key, Value>>,
override val onDataCleared: Flow<Key>,
private val keyTypeInfo: TypeInfo,
private val valueTypeInfo: TypeInfo,
private val keyToValuesMapTypeInfo: TypeInfo
) : WriteKeyValuesRepo<Key, Value> {
@OptIn(InternalAPI::class)
override suspend fun add(toAdd: Map<Key, List<Value>>) {
httpClient.post(
buildStandardUrl(baseUrl, addRoute)
) {
body = toAdd
bodyType = keyToValuesMapTypeInfo
contentType(contentType)
}.throwOnUnsuccess { "Unable to add $toAdd" }
}
@OptIn(InternalAPI::class)
override suspend fun remove(toRemove: Map<Key, List<Value>>) {
httpClient.post(
buildStandardUrl(baseUrl, removeRoute)
) {
body = toRemove
bodyType = keyToValuesMapTypeInfo
contentType(contentType)
}.throwOnUnsuccess { "Unable to remove $toRemove" }
}
@OptIn(InternalAPI::class)
override suspend fun clear(k: Key) {
httpClient.post(
buildStandardUrl(baseUrl, clearRoute)
) {
body = k
bodyType = keyTypeInfo
contentType(contentType)
}.throwOnUnsuccess { "Unable to clear data with key $k" }
}
@OptIn(InternalAPI::class)
override suspend fun clearWithValue(v: Value) {
httpClient.post(
buildStandardUrl(baseUrl, clearWithValueRoute)
) {
body = v
bodyType = valueTypeInfo
contentType(contentType)
}.throwOnUnsuccess { "Unable to clear data with value $v" }
}
@OptIn(InternalAPI::class)
override suspend fun set(toSet: Map<Key, List<Value>>) {
httpClient.post(
buildStandardUrl(baseUrl, setRoute)
) {
body = toSet
bodyType = keyToValuesMapTypeInfo
contentType(contentType)
}.throwOnUnsuccess { "Unable to set data $toSet" }
}
companion object {
inline operator fun <reified Key : Any, reified Value : Any> invoke(
baseUrl: String,
httpClient: HttpClient,
contentType: ContentType
) = KtorWriteKeyValuesRepoClient<Key, Value>(
baseUrl,
httpClient,
contentType,
httpClient.createStandardWebsocketFlow(
buildStandardUrl(baseUrl, onNewValueRoute),
),
httpClient.createStandardWebsocketFlow(
buildStandardUrl(baseUrl, onValueRemovedRoute),
),
httpClient.createStandardWebsocketFlow(
buildStandardUrl(baseUrl, onDataClearedRoute),
),
typeInfo<Key>(),
typeInfo<Value>(),
typeInfo<Map<Key, List<Value>>>()
)
}
}

View File

@@ -3,20 +3,25 @@ package dev.inmo.micro_utils.repos.ktor.client.key_value
import dev.inmo.micro_utils.ktor.client.*
import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
import dev.inmo.micro_utils.repos.ktor.common.*
import dev.inmo.micro_utils.repos.ktor.common.containsRoute
import dev.inmo.micro_utils.repos.ktor.common.countRoute
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
import dev.inmo.micro_utils.repos.ktor.common.valueParameterName
import dev.inmo.micro_utils.repos.ktor.common.key_value.keyParameterName
import dev.inmo.micro_utils.repos.ktor.common.key_value.reversedParameterName
import io.ktor.client.HttpClient
import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer
@Deprecated("Replaced with KtorReadKeyValueRepoClient")
class KtorReadStandardKeyValueRepo<Key, Value> (
private val baseUrl: String,
private val unifiedRequester: UnifiedRequester,
private val keySerializer: KSerializer<Key>,
private val valueSerializer: KSerializer<Value>,
private val valueNullableSerializer: KSerializer<Value?>
) : ReadStandardKeyValueRepo<Key, Value> {
) : ReadKeyValueRepo<Key, Value> {
constructor(
baseUrl: String,
client: HttpClient,

View File

@@ -7,6 +7,7 @@ import dev.inmo.micro_utils.repos.*
import io.ktor.client.HttpClient
import kotlinx.serialization.*
@Deprecated("Replaced with KtorKeyValueRepoClient")
@Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE")
class KtorStandartKeyValueRepo<K, V> (
baseUrl: String,
@@ -15,15 +16,15 @@ class KtorStandartKeyValueRepo<K, V> (
keySerializer: KSerializer<K>,
valueSerializer: KSerializer<V>,
valueNullableSerializer: KSerializer<V?>
) : StandardKeyValueRepo<K, V>,
ReadStandardKeyValueRepo<K, V> by KtorReadStandardKeyValueRepo(
) : KeyValueRepo<K, V>,
ReadKeyValueRepo<K, V> by KtorReadStandardKeyValueRepo(
"$baseUrl/$baseSubpart",
unifiedRequester,
keySerializer,
valueSerializer,
valueNullableSerializer
),
WriteStandardKeyValueRepo<K, V> by KtorWriteStandardKeyValueRepo(
WriteKeyValueRepo<K, V> by KtorWriteStandardKeyValueRepo(
"$baseUrl/$baseSubpart",
unifiedRequester,
keySerializer,
@@ -38,4 +39,4 @@ class KtorStandartKeyValueRepo<K, V> (
valueNullableSerializer: KSerializer<V?>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
) : this(baseUrl, baseSubpart, UnifiedRequester(client, serialFormat), keySerializer, valueSerializer, valueNullableSerializer)
}
}

View File

@@ -2,19 +2,20 @@ package dev.inmo.micro_utils.repos.ktor.client.key_value
import dev.inmo.micro_utils.ktor.client.*
import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.repos.WriteStandardKeyValueRepo
import dev.inmo.micro_utils.repos.WriteKeyValueRepo
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
import io.ktor.client.HttpClient
import kotlinx.coroutines.flow.Flow
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.*
@Deprecated("Replaced with KtorWriteKeyValueRepoClient")
class KtorWriteStandardKeyValueRepo<K, V> (
private var baseUrl: String,
private var unifiedRequester: UnifiedRequester,
private var keySerializer: KSerializer<K>,
private var valueSerializer: KSerializer<V>,
) : WriteStandardKeyValueRepo<K, V> {
) : WriteKeyValueRepo<K, V> {
private val keyValueMapSerializer = MapSerializer(keySerializer, valueSerializer)
private val keysListSerializer = ListSerializer(keySerializer)
private val valuesListSerializer = ListSerializer(valueSerializer)

View File

@@ -7,20 +7,21 @@ import dev.inmo.micro_utils.repos.*
import io.ktor.client.HttpClient
import kotlinx.serialization.KSerializer
@Deprecated("Should be replaced with KtorKeyValuesRepoClient")
class KtorOneToManyKeyValueRepo<Key, Value>(
baseUrl: String,
baseSubpart: String,
unifiedRequester: UnifiedRequester,
keySerializer: KSerializer<Key>,
valueSerializer: KSerializer<Value>,
) : OneToManyKeyValueRepo<Key, Value>,
ReadOneToManyKeyValueRepo<Key, Value> by KtorReadOneToManyKeyValueRepo<Key, Value> (
) : KeyValuesRepo<Key, Value>,
ReadKeyValuesRepo<Key, Value> by KtorReadOneToManyKeyValueRepo<Key, Value> (
"$baseUrl/$baseSubpart",
unifiedRequester,
keySerializer,
valueSerializer,
),
WriteOneToManyKeyValueRepo<Key, Value> by KtorWriteOneToManyKeyValueRepo<Key, Value> (
WriteKeyValuesRepo<Key, Value> by KtorWriteOneToManyKeyValueRepo<Key, Value> (
"$baseUrl/$baseSubpart",
unifiedRequester,
keySerializer,
@@ -34,4 +35,4 @@ class KtorOneToManyKeyValueRepo<Key, Value>(
valueSerializer: KSerializer<Value>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
) : this (baseUrl, baseSubpart, UnifiedRequester(client, serialFormat), keySerializer, valueSerializer)
}
}

View File

@@ -3,7 +3,7 @@ package dev.inmo.micro_utils.repos.ktor.client.one_to_many
import dev.inmo.micro_utils.ktor.client.*
import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
import dev.inmo.micro_utils.repos.ktor.common.keyParameterName
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName
@@ -12,12 +12,13 @@ import io.ktor.client.HttpClient
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.serializer
@Deprecated("Should be replaced with KtorReadKeyValuesRepoClient")
class KtorReadOneToManyKeyValueRepo<Key, Value> (
private val baseUrl: String,
private val unifiedRequester: UnifiedRequester,
private val keySerializer: KSerializer<Key>,
private val valueSerializer: KSerializer<Value>
) : ReadOneToManyKeyValueRepo<Key, Value> {
) : ReadKeyValuesRepo<Key, Value> {
private val paginationValueResultSerializer = PaginationResult.serializer(valueSerializer)
private val paginationKeyResultSerializer = PaginationResult.serializer(keySerializer)
@@ -104,4 +105,4 @@ class KtorReadOneToManyKeyValueRepo<Key, Value> (
Long.serializer()
)
}
}

View File

@@ -2,19 +2,20 @@ package dev.inmo.micro_utils.repos.ktor.client.one_to_many
import dev.inmo.micro_utils.ktor.client.*
import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.repos.WriteOneToManyKeyValueRepo
import dev.inmo.micro_utils.repos.WriteKeyValuesRepo
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
import io.ktor.client.HttpClient
import kotlinx.coroutines.flow.Flow
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.*
@Deprecated("Should be replaced with KtorWriteKeyValuesRepoClient")
class KtorWriteOneToManyKeyValueRepo<Key, Value> (
private val baseUrl: String,
private val unifiedRequester: UnifiedRequester,
private val keySerializer: KSerializer<Key>,
private val valueSerializer: KSerializer<Value>
) : WriteOneToManyKeyValueRepo<Key, Value> {
) : WriteKeyValuesRepo<Key, Value> {
private val keyValueSerializer = PairSerializer(keySerializer, valueSerializer)
private val keyValueMapSerializer = MapSerializer(keySerializer, ListSerializer(valueSerializer))

View File

@@ -13,5 +13,22 @@ kotlin {
api internalProject("micro_utils.repos.common")
}
}
jvmTest {
dependencies {
implementation internalProject("micro_utils.repos.common")
implementation internalProject("micro_utils.repos.ktor.client")
implementation internalProject("micro_utils.repos.ktor.server")
implementation internalProject("micro_utils.repos.inmemory")
implementation libs.kt.coroutines.test
implementation libs.ktor.server.cio
implementation libs.ktor.client.cio
implementation libs.ktor.server.content.negotiation
implementation libs.ktor.serialization.kotlinx.json
implementation libs.ktor.client.content.negotiation
implementation libs.ktor.client.logging
implementation libs.ktor.client.websockets
}
}
}
}

View File

@@ -0,0 +1,3 @@
package dev.inmo.micro_utils.repos.ktor.common
const val containsRoute = "contains"

View File

@@ -0,0 +1,3 @@
package dev.inmo.micro_utils.repos.ktor.common
const val countRoute = "count"

View File

@@ -0,0 +1,3 @@
package dev.inmo.micro_utils.repos.ktor.common
const val countRouting = "count"

View File

@@ -1,5 +1,6 @@
package dev.inmo.micro_utils.repos.ktor.common
const val idParameterName = "id"
const val keyParameterName = "key"
const val valueParameterName = "value"
const val reversedParameterName = "reversed"
const val reversedParameterName = "reversed"

View File

@@ -3,4 +3,3 @@ package dev.inmo.micro_utils.repos.ktor.common.crud
const val getByPaginationRouting = "getByPagination"
const val getByIdRouting = "getById"
const val containsRouting = "contains"
const val countRouting = "count"

View File

@@ -3,11 +3,11 @@ package dev.inmo.micro_utils.repos.ktor.common.key_value
const val getRoute = "get"
const val valuesRoute = "values"
const val keysRoute = "keys"
const val containsRoute = "contains"
const val countRoute = "count"
const val containsRoute = dev.inmo.micro_utils.repos.ktor.common.containsRoute
const val countRoute = dev.inmo.micro_utils.repos.ktor.common.countRoute
const val onNewValueRoute = "onNewValue"
const val onValueRemovedRoute = "onValueRemoved"
const val setRoute = "set"
const val unsetRoute = "unset"
const val unsetWithValuesRoute = "unsetWithValues"
const val unsetWithValuesRoute = "unsetWithValues"

View File

@@ -5,7 +5,7 @@ const val keysRoute = "keys"
const val containsByKeyRoute = "containsByKey"
const val containsByKeyValueRoute = "containsByKeyValue"
const val countByKeyRoute = "countByKey"
const val countRoute = "count"
const val countRoute = dev.inmo.micro_utils.repos.ktor.common.countRoute
const val onNewValueRoute = "onNewValue"
const val onValueRemovedRoute = "onValueRemoved"

View File

@@ -0,0 +1,89 @@
import dev.inmo.micro_utils.repos.*
import dev.inmo.micro_utils.repos.ktor.client.crud.KtorCRUDRepoClient
import dev.inmo.micro_utils.repos.ktor.server.crud.configureCRUDRepoRoutes
import io.ktor.client.HttpClient
import io.ktor.client.plugins.logging.Logging
import io.ktor.http.ContentType
import io.ktor.serialization.kotlinx.KotlinxWebsocketSerializationConverter
import io.ktor.serialization.kotlinx.json.json
import io.ktor.server.application.install
import io.ktor.server.cio.CIO
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import io.ktor.server.routing.routing
import io.ktor.server.websocket.WebSockets
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.Json
import kotlin.test.Test
import kotlin.test.assertEquals
class CRUDTests {
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testCRUDFunctions() {
runTest {
val map = mutableMapOf<Int, ComplexData>()
val repo = MapCRUDRepo<ComplexData, Int, SimpleData>(
map,
{ newValue, id, oldValue ->
oldValue.copy(title = newValue.title)
}
) {
size to ComplexData(size, title = it.title)
}
val server = io.ktor.server.engine.embeddedServer(
CIO,
23456,
"127.0.0.1"
) {
install(ContentNegotiation) {
json()
}
install(WebSockets) {
contentConverter = KotlinxWebsocketSerializationConverter(Json)
}
routing {
configureCRUDRepoRoutes(
repo
) {
it.toInt()
}
}
}.start(false)
val client = HttpClient {
install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) {
json()
}
install(Logging)
install(io.ktor.client.plugins.websocket.WebSockets) {
contentConverter = KotlinxWebsocketSerializationConverter(Json)
}
}
val crudClient = KtorCRUDRepoClient<ComplexData, Int, SimpleData>(
"http://127.0.0.1:23456",
client,
ContentType.Application.Json
) {
it.toString()
}
val created = crudClient.create(SimpleData("Example")).single()
assertEquals(map.size, 1)
assertEquals(map.size.toLong(), crudClient.count())
assertEquals(1, crudClient.count())
assertEquals(map.getValue(map.keys.first()), created)
val updated = crudClient.update(created.id, SimpleData("Example2"))
assertEquals(map.size, 1)
assertEquals(map.size.toLong(), crudClient.count())
assertEquals(1, crudClient.count())
assertEquals(map.getValue(map.keys.first()), updated)
crudClient.deleteById(created.id)
assertEquals(map.size, 0)
assertEquals(map.size.toLong(), crudClient.count())
assertEquals(0, crudClient.count())
server.stop()
}
}
}

View File

@@ -0,0 +1,10 @@
import com.benasher44.uuid.uuid4
import kotlinx.serialization.Serializable
@Serializable
data class ComplexData(
val id: Int,
val simple: SimpleData = SimpleData(),
val simples: List<SimpleData> = (0 until 100).map { SimpleData(("$it")) },
val title: String = uuid4().toString()
)

View File

@@ -0,0 +1,139 @@
import dev.inmo.micro_utils.pagination.firstPageWithOneElementPagination
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
import dev.inmo.micro_utils.repos.*
import dev.inmo.micro_utils.repos.ktor.client.key.value.KtorKeyValueRepoClient
import dev.inmo.micro_utils.repos.ktor.server.key.value.configureKeyValueRepoRoutes
import io.ktor.client.HttpClient
import io.ktor.client.plugins.logging.Logging
import io.ktor.http.ContentType
import io.ktor.serialization.kotlinx.KotlinxWebsocketSerializationConverter
import io.ktor.serialization.kotlinx.json.json
import io.ktor.server.application.install
import io.ktor.server.cio.CIO
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import io.ktor.server.routing.routing
import io.ktor.server.websocket.WebSockets
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.json.Json
import kotlin.test.*
class KVTests {
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testKVFunctions() {
runTest {
val map = mutableMapOf<Int, ComplexData>()
val repo = MapKeyValueRepo<Int, ComplexData>(map)
val server = io.ktor.server.engine.embeddedServer(
CIO,
23456,
"127.0.0.1"
) {
install(ContentNegotiation) {
json()
}
install(WebSockets) {
contentConverter = KotlinxWebsocketSerializationConverter(Json)
}
routing {
configureKeyValueRepoRoutes(
repo,
Int.serializer(),
ComplexData.serializer(),
Json {}
)
}
}.start(false)
val client = HttpClient {
install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) {
json()
}
install(Logging)
install(io.ktor.client.plugins.websocket.WebSockets) {
contentConverter = KotlinxWebsocketSerializationConverter(Json)
}
}
val crudClient = KtorKeyValueRepoClient<Int, ComplexData>(
"http://127.0.0.1:23456",
client,
ContentType.Application.Json,
Int.serializer(),
ComplexData.serializer(),
Json
)
val dataInOneKey = ComplexData(1, title = "Example1")
val dataInMultipleKeys = ComplexData(2, title = "Example2")
val repeatCount = 3
val dataList = listOf(
1 to dataInOneKey
) + (0 until repeatCount).map {
(it + 2) to dataInMultipleKeys
}
dataList.forEachIndexed { i, (id, data) ->
crudClient.set(id, data)
assertEquals(map.size, i + 1)
assertEquals(map.size.toLong(), crudClient.count())
assertEquals(i + 1L, crudClient.count())
dataList.take(i + 1).forEach { (id, data) ->
assertEquals(data, map[id])
assertEquals(data, crudClient.get(id))
assertEquals(map[id], crudClient.get(id))
}
}
dataList.forEach { (id, data) ->
assertTrue(crudClient.contains(id))
assertEquals(data, crudClient.get(id))
}
assertEquals(
dataList.mapNotNull { if (it.second == dataInMultipleKeys) it.first else null },
getAllWithNextPaging(firstPageWithOneElementPagination) {
crudClient.keys(dataInMultipleKeys, it)
}
)
assertEquals(
dataList.mapNotNull { if (it.second == dataInOneKey) it.first else null },
getAllWithNextPaging(firstPageWithOneElementPagination) {
crudClient.keys(dataInOneKey, it)
}
)
assertEquals(
dataList.map { it.first },
getAllWithNextPaging(firstPageWithOneElementPagination) {
crudClient.keys(it)
}
)
assertEquals(
dataList.map { it.second },
getAllWithNextPaging(firstPageWithOneElementPagination) {
crudClient.values(it)
}
)
assertEquals(dataList.size.toLong(), crudClient.count())
crudClient.unsetWithValues(dataInMultipleKeys)
assertEquals(
dataList.filter { it.second == dataInOneKey }.size.toLong(),
crudClient.count()
)
crudClient.unset(dataList.first { it.second == dataInOneKey }.first)
assertEquals(
0,
crudClient.count()
)
server.stop()
}
}
}

View File

@@ -0,0 +1,140 @@
import dev.inmo.micro_utils.pagination.firstPageWithOneElementPagination
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
import dev.inmo.micro_utils.repos.*
import dev.inmo.micro_utils.repos.ktor.client.key.values.KtorKeyValuesRepoClient
import dev.inmo.micro_utils.repos.ktor.server.key.values.configureKeyValuesRepoRoutes
import io.ktor.client.HttpClient
import io.ktor.client.plugins.logging.Logging
import io.ktor.http.ContentType
import io.ktor.serialization.kotlinx.KotlinxWebsocketSerializationConverter
import io.ktor.serialization.kotlinx.json.json
import io.ktor.server.application.install
import io.ktor.server.cio.CIO
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import io.ktor.server.routing.routing
import io.ktor.server.websocket.WebSockets
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.json.Json
import kotlin.test.*
class KVsTests {
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testKVsFunctions() {
runTest {
val map = mutableMapOf<Int, MutableList<ComplexData>>()
val repo = MapKeyValuesRepo(map)
val server = io.ktor.server.engine.embeddedServer(
CIO,
23456,
"127.0.0.1"
) {
install(ContentNegotiation) {
json()
}
install(WebSockets) {
contentConverter = KotlinxWebsocketSerializationConverter(Json)
}
routing {
configureKeyValuesRepoRoutes(
repo,
Int.serializer(),
ComplexData.serializer(),
Json {}
)
}
}.start(false)
val client = HttpClient {
install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) {
json()
}
install(Logging)
install(io.ktor.client.plugins.websocket.WebSockets) {
contentConverter = KotlinxWebsocketSerializationConverter(Json)
}
}
val crudClient = KtorKeyValuesRepoClient(
"http://127.0.0.1:23456",
client,
ContentType.Application.Json,
Int.serializer(),
ComplexData.serializer(),
Json
)
val dataInOneKey = ComplexData(1, title = "Example1")
val dataInMultipleKeys = ComplexData(2, title = "Example2")
val repeatCount = 3
val dataList = listOf(
1 to listOf(dataInOneKey)
) + (0 until repeatCount).map {
(it + 2) to listOf(dataInMultipleKeys)
}
dataList.forEachIndexed { i, (id, data) ->
crudClient.set(id, data)
assertEquals(i + 1, map.size)
assertEquals(map.size.toLong(), crudClient.count())
assertEquals(i + 1L, crudClient.count())
dataList.take(i + 1).forEach { (id, data) ->
assertContentEquals(data, map[id])
assertContentEquals(data, crudClient.getAll(id))
assertContentEquals(map[id], crudClient.getAll(id))
}
}
dataList.forEach { (key, data) ->
assertTrue(crudClient.contains(key))
assertContentEquals(data, crudClient.getAll(key))
}
assertEquals(
dataList.mapNotNull { if (it.second.contains(dataInMultipleKeys)) it.first else null },
getAllWithNextPaging(firstPageWithOneElementPagination) {
crudClient.keys(dataInMultipleKeys, it)
}
)
assertEquals(
dataList.mapNotNull { if (it.second.contains(dataInOneKey)) it.first else null },
getAllWithNextPaging(firstPageWithOneElementPagination) {
crudClient.keys(dataInOneKey, it)
}
)
assertEquals(
dataList.map { it.first },
getAllWithNextPaging(firstPageWithOneElementPagination) {
crudClient.keys(it)
}
)
assertEquals(
dataList.map { it.first },
getAllWithNextPaging(firstPageWithOneElementPagination) {
crudClient.keys(it)
}
)
assertEquals(dataList.size.toLong(), crudClient.count())
crudClient.remove(dataList.filter { it.second.contains(dataInMultipleKeys) })
println(map)
assertEquals(
dataList.filter { it.second.contains(dataInOneKey) }.size.toLong(),
crudClient.count()
)
crudClient.remove(dataList.filter { it.second.contains(dataInOneKey) })
assertEquals(
0,
crudClient.count()
)
server.stop()
}
}
}

View File

@@ -0,0 +1,7 @@
import com.benasher44.uuid.uuid4
import kotlinx.serialization.Serializable
@Serializable
data class SimpleData(
val title: String = uuid4().toString()
)

187
repos/ktor/crud.yml Normal file
View File

@@ -0,0 +1,187 @@
swagger: "2.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"
title: "CRUD Repo"
contact:
email: "ovsyannikov.alexey95@gmail.com"
tags:
- name: "Read"
description: "Operations with `get` request in most cases"
- 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
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
paths:
/getByPagination:
get:
tags:
- "Read"
parameters:
- $ref: "#/parameters/PaginationInQueryPage"
- $ref: "#/parameters/PaginationInQuerySize"
responses:
"200":
description: "Pagination with elements"
schema:
allOf:
- $ref: "#/definitions/PaginationResult"
- properties:
results:
items:
$ref: "#/definitions/Value"
/getById:
get:
tags:
- "Read"
parameters:
- $ref: "#/parameters/IdInQuery"
required: true
responses:
"200":
description: "Result object"
schema:
$ref: "#/definitions/Value"
"204":
description: "No value by id"
/contains:
get:
tags:
- "Read"
parameters:
- $ref: "#/parameters/IdInQuery"
required: true
responses:
"200":
description: "Object with id availability in repo"
schema:
type: boolean
/count:
get:
tags:
- "Read"
responses:
"200":
description: "Amount of objects in repo"
schema:
type: integer
/create:
post:
tags:
- "Write"
parameters:
- $ref: "#/parameters/NewValuesInBody"
responses:
"200":
description: "Objects has been created and saved"
schema:
$ref: "#/definitions/Values"
/update:
post:
tags:
- "Write"
parameters:
- $ref: "#/parameters/NewValuesWithIdsInBody"
responses:
"200":
description: "Objects has been updated"
schema:
$ref: "#/definitions/Values"
/deleteById:
post:
tags:
- "Write"
parameters:
- $ref: "#/parameters/IdsInBody"
responses:
"200":
description: "Objects has been updated"
schema:
$ref: "#/definitions/Values"

196
repos/ktor/kv.yml Normal file
View File

@@ -0,0 +1,196 @@
swagger: "2.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"
title: "KeyValue Repo"
contact:
email: "ovsyannikov.alexey95@gmail.com"
tags:
- name: "Read"
description: "Operations with `get` request in most cases"
- 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:
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:
get:
tags:
- "Read"
parameters:
- $ref: "#/parameters/KeyInQuery"
required: true
responses:
"200":
description: "Element by key"
schema:
$ref: "#/definitions/Value"
"204":
description: "No value by id"
/values:
get:
tags:
- "Read"
parameters:
- $ref: "#/parameters/PaginationInQueryPage"
- $ref: "#/parameters/PaginationInQuerySize"
- $ref: "#/parameters/ReversedInQuery"
responses:
"200":
description: "Pagination with elements"
schema:
allOf:
- $ref: "#/definitions/PaginationResult"
- properties:
results:
items:
$ref: "#/definitions/Value"
/keys:
get:
tags:
- "Read"
parameters:
- $ref: "#/parameters/PaginationInQueryPage"
- $ref: "#/parameters/PaginationInQuerySize"
- $ref: "#/parameters/ReversedInQuery"
- $ref: "#/parameters/ValueInQuery"
required: false
responses:
"200":
description: "Pagination with elements"
schema:
allOf:
- $ref: "#/definitions/PaginationResult"
- properties:
results:
items:
$ref: "#/definitions/Key"
/contains:
get:
tags:
- "Read"
parameters:
- $ref: "#/parameters/KeyInQuery"
required: true
responses:
"200":
description: "Object with id availability in repo"
schema:
type: boolean
/count:
get:
tags:
- "Read"
responses:
"200":
description: "Amount of objects in repo"
schema:
type: integer
/set:
post:
tags:
- "Write"
parameters:
- allOf:
- $ref: "#/parameters/MapInBody"
- additionalProperties:
$ref: "#/definitions/Value"
description: "Map with new elements to set. Use keys as a keys of this map"
responses:
"200":
description: "Will return 200 if everything has been completed ok"
/unset:
post:
tags:
- "Write"
parameters:
- $ref: "#/parameters/KeysInBody"
responses:
"200":
description: "Objects with keys from body has been unset"
/unsetWithValues:
post:
tags:
- "Write"
parameters:
- $ref: "#/parameters/ValuesInBody"
responses:
"200":
description: "Objects with values from body has been unset"

222
repos/ktor/kvs.yml Normal file
View File

@@ -0,0 +1,222 @@
swagger: "2.0"
info:
description: "This is a template for the KeyValues repositories from [microutils](https://github.com/InsanusMokrassar/MicroUtils/tree/master/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key/values)"
version: "0.11.0"
title: "KeyValues Repo"
contact:
email: "ovsyannikov.alexey95@gmail.com"
tags:
- name: "Read"
description: "Operations with `get` request in most cases"
- name: "Write"
description: "Operations with `post` request in most cases"
parameters:
KeyInQuery:
in: "query"
name: "key"
allOf:
- $ref: "#/definitions/Key"
KeyInBody:
in: "body"
name: "body"
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"
ValueInBody:
in: "body"
name: "body"
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:
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:
get:
tags:
- "Read"
parameters:
- $ref: "#/parameters/KeyInQuery"
required: true
- $ref: "#/parameters/PaginationInQueryPage"
- $ref: "#/parameters/PaginationInQuerySize"
- $ref: "#/parameters/ReversedInQuery"
responses:
"200":
description: "Elements by query"
schema:
allOf:
- $ref: "#/definitions/PaginationResult"
- properties:
results:
items:
$ref: "#/definitions/Value"
/keys:
get:
tags:
- "Read"
parameters:
- $ref: "#/parameters/PaginationInQueryPage"
- $ref: "#/parameters/PaginationInQuerySize"
- $ref: "#/parameters/ReversedInQuery"
- $ref: "#/parameters/ValueInQuery"
required: false
responses:
"200":
description: "Pagination with elements"
schema:
allOf:
- $ref: "#/definitions/PaginationResult"
- properties:
results:
items:
$ref: "#/definitions/Key"
/contains:
get:
tags:
- "Read"
parameters:
- $ref: "#/parameters/KeyInQuery"
required: true
- $ref: "#/parameters/ValueInQuery"
required: false
responses:
"200":
description: "Object with key and optionally availability in repo"
schema:
type: boolean
/count:
get:
tags:
- "Read"
responses:
"200":
description: "Amount of objects in repo"
schema:
type: integer
/add:
post:
tags:
- "Write"
parameters:
- allOf:
- $ref: "#/parameters/MapInBody"
- additionalProperties:
$ref: "#/definitions/Value"
description: "Map with new elements to add. Use keys as a keys of this map. That values will be added to the end of current data by their keys"
responses:
"200":
description: "Will return 200 if everything has been completed ok"
/set:
post:
tags:
- "Write"
parameters:
- allOf:
- $ref: "#/parameters/MapInBody"
- additionalProperties:
$ref: "#/definitions/Value"
description: "Map with new elements to set. Use keys as a keys of this map. That values will overwrite all exists data by their keys"
responses:
"200":
description: "Will return 200 if everything has been completed ok"
/remove:
post:
tags:
- "Write"
parameters:
- allOf:
- $ref: "#/parameters/MapInBody"
- additionalProperties:
$ref: "#/definitions/Value"
description: "Map with data to remove. Removing will be processed by each value for its key"
responses:
"200":
description: "Objects with keys and values from body has been unset"
/clear:
post:
tags:
- "Write"
parameters:
- $ref: "#/parameters/KeyInBody"
responses:
"200":
description: "Data with corresponding key has been removed"
/clearWithValues:
post:
tags:
- "Write"
parameters:
- $ref: "#/parameters/ValueInBody"
responses:
"200":
description: "Will remove value from all keys data"

View File

@@ -0,0 +1,30 @@
package dev.inmo.micro_utils.repos.ktor.server.crud
import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.repos.CRUDRepo
import io.ktor.server.routing.Route
import kotlinx.serialization.*
inline fun <reified ObjectType : Any, reified IdType : Any, reified InputValue : Any> Route.configureCRUDRepoRoutes(
originalRepo: CRUDRepo<ObjectType, IdType, InputValue>,
noinline idDeserializer: suspend (String) -> IdType
) {
configureReadCRUDRepoRoutes(originalRepo, idDeserializer)
configureWriteCRUDRepoRoutes(originalRepo)
}
inline fun <reified ObjectType : Any, reified IdType : Any, reified InputValue : Any> Route.configureCRUDRepoRoutes(
originalRepo: CRUDRepo<ObjectType, IdType, InputValue>,
idsSerializer: KSerializer<IdType>,
serialFormat: StringFormat
) = configureCRUDRepoRoutes(originalRepo) {
serialFormat.decodeFromString(idsSerializer, it)
}
inline fun <reified ObjectType : Any, reified IdType : Any, reified InputValue : Any> Route.configureCRUDRepoRoutes(
originalRepo: CRUDRepo<ObjectType, IdType, InputValue>,
idsSerializer: KSerializer<IdType>,
serialFormat: BinaryFormat
) = configureCRUDRepoRoutes(originalRepo) {
serialFormat.decodeHex(idsSerializer, it)
}

View File

@@ -0,0 +1,72 @@
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.ReadCRUDRepo
import dev.inmo.micro_utils.repos.ktor.common.countRouting
import dev.inmo.micro_utils.repos.ktor.common.crud.*
import dev.inmo.micro_utils.repos.ktor.common.idParameterName
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.configureReadCRUDRepoRoutes(
originalRepo: ReadCRUDRepo<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(idParameterName) ?: 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(idParameterName) ?: return@get
)
call.respond(
originalRepo.contains(id)
)
}
get(countRouting) {
call.respond(
originalRepo.count()
)
}
}
inline fun <reified ObjectType, reified IdType> Route.configureReadCRUDRepoRoutes(
originalRepo: ReadCRUDRepo<ObjectType, IdType>,
idsSerializer: KSerializer<IdType>,
serialFormat: StringFormat
) = configureReadCRUDRepoRoutes(originalRepo) {
serialFormat.decodeFromString(idsSerializer, it)
}
inline fun <reified ObjectType, reified IdType> Route.configureReadCRUDRepoRoutes(
originalRepo: ReadCRUDRepo<ObjectType, IdType>,
idsSerializer: KSerializer<IdType>,
serialFormat: BinaryFormat
) = configureReadCRUDRepoRoutes(originalRepo) {
serialFormat.decodeHex(idsSerializer, it)
}

View File

@@ -5,7 +5,8 @@ import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.pagination.PaginationResult
import dev.inmo.micro_utils.pagination.extractPagination
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
import dev.inmo.micro_utils.repos.ReadCRUDRepo
import dev.inmo.micro_utils.repos.ktor.common.countRouting
import dev.inmo.micro_utils.repos.ktor.common.crud.*
import io.ktor.http.ContentType
import io.ktor.server.application.call
@@ -14,8 +15,8 @@ import io.ktor.server.routing.get
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.serializer
fun <ObjectType, IdType> Route.configureReadStandardCrudRepoRoutes(
originalRepo: ReadStandardCRUDRepo<ObjectType, IdType>,
fun <ObjectType, IdType> Route.configureReadCRUDRepoRoutes(
originalRepo: ReadCRUDRepo<ObjectType, IdType>,
objectsSerializer: KSerializer<ObjectType>,
objectsNullableSerializer: KSerializer<ObjectType?>,
idsSerializer: KSerializer<IdType>,
@@ -72,11 +73,11 @@ fun <ObjectType, IdType> Route.configureReadStandardCrudRepoRoutes(
}
}
inline fun <ObjectType, IdType> Route.configureReadStandardCrudRepoRoutes(
originalRepo: ReadStandardCRUDRepo<ObjectType, IdType>,
inline fun <ObjectType, IdType> Route.configureReadCRUDRepoRoutes(
originalRepo: ReadCRUDRepo<ObjectType, IdType>,
objectsSerializer: KSerializer<ObjectType>,
objectsNullableSerializer: KSerializer<ObjectType?>,
idsSerializer: KSerializer<IdType>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
) = configureReadStandardCrudRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, idsSerializer, UnifiedRouter(serialFormat, serialFormatContentType))
) = configureReadCRUDRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, idsSerializer, UnifiedRouter(serialFormat, serialFormatContentType))

View File

@@ -4,15 +4,15 @@ import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.UnifiedRouter
import dev.inmo.micro_utils.ktor.server.standardKtorSerialFormatContentType
import dev.inmo.micro_utils.repos.StandardCRUDRepo
import dev.inmo.micro_utils.repos.CRUDRepo
import io.ktor.http.ContentType
import io.ktor.server.routing.Route
import io.ktor.server.routing.route
import kotlinx.serialization.KSerializer
fun <ObjectType, IdType, InputValue> Route.configureStandardCrudRepoRoutes(
fun <ObjectType, IdType, InputValue> Route.configureCRUDRepoRoutes(
baseSubpart: String,
originalRepo: StandardCRUDRepo<ObjectType, IdType, InputValue>,
originalRepo: CRUDRepo<ObjectType, IdType, InputValue>,
objectsSerializer: KSerializer<ObjectType>,
objectsNullableSerializer: KSerializer<ObjectType?>,
inputsSerializer: KSerializer<InputValue>,
@@ -20,20 +20,20 @@ fun <ObjectType, IdType, InputValue> Route.configureStandardCrudRepoRoutes(
unifiedRouter: UnifiedRouter
) {
route(baseSubpart) {
configureReadStandardCrudRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, idsSerializer, unifiedRouter)
configureWriteStandardCrudRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer, unifiedRouter)
configureReadCRUDRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, idsSerializer, unifiedRouter)
configureWriteCRUDRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer, unifiedRouter)
}
}
fun <ObjectType, IdType, InputValue> Route.configureStandardCrudRepoRoutes(
fun <ObjectType, IdType, InputValue> Route.configureCRUDRepoRoutes(
baseSubpart: String,
originalRepo: StandardCRUDRepo<ObjectType, IdType, InputValue>,
originalRepo: CRUDRepo<ObjectType, IdType, InputValue>,
objectsSerializer: KSerializer<ObjectType>,
objectsNullableSerializer: KSerializer<ObjectType?>,
inputsSerializer: KSerializer<InputValue>,
idsSerializer: KSerializer<IdType>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
) = configureStandardCrudRepoRoutes(
) = configureCRUDRepoRoutes(
baseSubpart, originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer, UnifiedRouter(serialFormat, serialFormatContentType)
)

View File

@@ -0,0 +1,41 @@
package dev.inmo.micro_utils.repos.ktor.server.crud
import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.repos.WriteCRUDRepo
import dev.inmo.micro_utils.repos.ktor.common.crud.*
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.call
import io.ktor.server.request.receive
import io.ktor.server.response.respond
import io.ktor.server.routing.Route
import io.ktor.server.routing.post
inline fun <reified ObjectType : Any, reified IdType : Any, reified InputValue : Any> Route.configureWriteCRUDRepoRoutes(
originalRepo: WriteCRUDRepo<ObjectType, IdType, InputValue>
) {
includeWebsocketHandling(
newObjectsFlowRouting,
originalRepo.newObjectsFlow,
)
includeWebsocketHandling(
updatedObjectsFlowRouting,
originalRepo.updatedObjectsFlow
)
includeWebsocketHandling(
deletedObjectsIdsFlowRouting,
originalRepo.deletedObjectsIdsFlow
)
post(createRouting) {
call.respond(originalRepo.create(call.receive()))
}
post(updateRouting) {
call.respond(originalRepo.update(call.receive()))
}
post(deleteByIdRouting) {
originalRepo.deleteById(call.receive())
call.respond(HttpStatusCode.OK)
}
}

View File

@@ -3,7 +3,7 @@ package dev.inmo.micro_utils.repos.ktor.server.crud
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo
import dev.inmo.micro_utils.repos.WriteCRUDRepo
import dev.inmo.micro_utils.repos.ktor.common.crud.*
import io.ktor.http.ContentType
import io.ktor.server.routing.Route
@@ -11,8 +11,8 @@ import io.ktor.server.routing.post
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.*
fun <ObjectType, IdType, InputValue> Route.configureWriteStandardCrudRepoRoutes(
originalRepo: WriteStandardCRUDRepo<ObjectType, IdType, InputValue>,
fun <ObjectType, IdType, InputValue> Route.configureWriteCRUDRepoRoutes(
originalRepo: WriteCRUDRepo<ObjectType, IdType, InputValue>,
objectsSerializer: KSerializer<ObjectType>,
objectsNullableSerializer: KSerializer<ObjectType?>,
inputsSerializer: KSerializer<InputValue>,
@@ -94,14 +94,14 @@ fun <ObjectType, IdType, InputValue> Route.configureWriteStandardCrudRepoRoutes(
}
}
fun <ObjectType, IdType, InputValue> Route.configureWriteStandardCrudRepoRoutes(
originalRepo: WriteStandardCRUDRepo<ObjectType, IdType, InputValue>,
fun <ObjectType, IdType, InputValue> Route.configureWriteCRUDRepoRoutes(
originalRepo: WriteCRUDRepo<ObjectType, IdType, InputValue>,
objectsSerializer: KSerializer<ObjectType>,
objectsNullableSerializer: KSerializer<ObjectType?>,
inputsSerializer: KSerializer<InputValue>,
idsSerializer: KSerializer<IdType>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
) = configureWriteStandardCrudRepoRoutes(
) = configureWriteCRUDRepoRoutes(
originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer, UnifiedRouter(serialFormat, serialFormatContentType)
)

View File

@@ -0,0 +1,47 @@
package dev.inmo.micro_utils.repos.ktor.server.key.value
import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.repos.KeyValueRepo
import io.ktor.http.*
import io.ktor.server.routing.Route
import kotlinx.serialization.*
inline fun <reified Key : Any, reified Value : Any> Route.configureKeyValueRepoRoutes (
originalRepo: KeyValueRepo<Key, Value>,
noinline idDeserializer: suspend (String) -> Key,
noinline valueDeserializer: suspend (String) -> Value
) {
configureReadKeyValueRepoRoutes(originalRepo, idDeserializer, valueDeserializer)
configureWriteKeyValueRepoRoutes(originalRepo)
}
inline fun <reified Key : Any, reified Value : Any> Route.configureKeyValueRepoRoutes(
originalRepo: KeyValueRepo<Key, Value>,
idsSerializer: DeserializationStrategy<Key>,
valueSerializer: DeserializationStrategy<Value>,
serialFormat: StringFormat
) = configureKeyValueRepoRoutes(
originalRepo,
{
serialFormat.decodeFromString(idsSerializer, it.decodeURLQueryComponent())
},
{
serialFormat.decodeFromString(valueSerializer, it.decodeURLQueryComponent())
}
)
inline fun <reified Key : Any, reified Value : Any> Route.configureKeyValueRepoRoutes(
originalRepo: KeyValueRepo<Key, Value>,
idsSerializer: DeserializationStrategy<Key>,
valueSerializer: DeserializationStrategy<Value>,
serialFormat: BinaryFormat
) = configureKeyValueRepoRoutes(
originalRepo,
{
serialFormat.decodeHex(idsSerializer, it)
},
{
serialFormat.decodeHex(valueSerializer, it)
}
)

View File

@@ -0,0 +1,107 @@
package dev.inmo.micro_utils.repos.ktor.server.key.value
import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.pagination.PaginationResult
import dev.inmo.micro_utils.pagination.extractPagination
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
import dev.inmo.micro_utils.repos.ktor.common.*
import dev.inmo.micro_utils.repos.ktor.common.containsRoute
import dev.inmo.micro_utils.repos.ktor.common.countRoute
import dev.inmo.micro_utils.repos.ktor.common.keyParameterName
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName
import io.ktor.http.*
import io.ktor.server.application.call
import io.ktor.server.response.respond
import io.ktor.server.routing.Route
import io.ktor.server.routing.get
import io.ktor.util.InternalAPI
import io.ktor.util.reflect.typeInfo
import kotlinx.serialization.*
@OptIn(InternalAPI::class)
inline fun <reified Key, reified Value> Route.configureReadKeyValueRepoRoutes (
originalRepo: ReadKeyValueRepo<Key, Value>,
noinline idDeserializer: suspend (String) -> Key,
noinline valueDeserializer: suspend (String) -> Value
) {
val paginationWithValuesTypeInfo = typeInfo<PaginationResult<Value>>()
val paginationWithKeysTypeInfo = typeInfo<PaginationResult<Key>>()
get(getRoute) {
val key = idDeserializer(
call.getQueryParameterOrSendError(keyParameterName) ?: return@get
)
originalRepo.get(key) ?.let {
call.respond(it)
} ?: call.respond(HttpStatusCode.NoContent)
}
get(valuesRoute) {
val pagination = call.request.queryParameters.extractPagination
val reversed = call.getQueryParameter(reversedParameterName) ?.toBoolean() ?: false
call.respond(
originalRepo.values(pagination, reversed),
paginationWithValuesTypeInfo
)
}
get(keysRoute) {
val pagination = call.request.queryParameters.extractPagination
val reversed = call.getQueryParameterOrSendError(reversedParameterName) ?.toBoolean() ?: false
val value = call.getQueryParameter(valueParameterName) ?.let {
valueDeserializer(it)
}
call.respond(
value ?.let { originalRepo.keys(value, pagination, reversed) } ?: originalRepo.keys(pagination, reversed),
paginationWithKeysTypeInfo
)
}
get(containsRoute) {
val key = idDeserializer(
call.getQueryParameterOrSendError(keyParameterName) ?: return@get
)
call.respond(originalRepo.contains(key))
}
get(countRoute) {
call.respond(originalRepo.count())
}
}
inline fun <reified Key, reified Value> Route.configureReadKeyValueRepoRoutes(
originalRepo: ReadKeyValueRepo<Key, Value>,
idsSerializer: DeserializationStrategy<Key>,
valueSerializer: DeserializationStrategy<Value>,
serialFormat: StringFormat
) = configureReadKeyValueRepoRoutes(
originalRepo,
{
serialFormat.decodeFromString(idsSerializer, it.decodeURLQueryComponent())
},
{
serialFormat.decodeFromString(valueSerializer, it.decodeURLQueryComponent())
}
)
inline fun <reified Key, reified Value> Route.configureReadKeyValueRepoRoutes(
originalRepo: ReadKeyValueRepo<Key, Value>,
idsSerializer: DeserializationStrategy<Key>,
valueSerializer: DeserializationStrategy<Value>,
serialFormat: BinaryFormat
) = configureReadKeyValueRepoRoutes(
originalRepo,
{
serialFormat.decodeHex(idsSerializer, it)
},
{
serialFormat.decodeHex(valueSerializer, it)
}
)

View File

@@ -0,0 +1,45 @@
package dev.inmo.micro_utils.repos.ktor.server.key.value
import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.repos.WriteKeyValueRepo
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.call
import io.ktor.server.request.receive
import io.ktor.server.response.respond
import io.ktor.server.routing.Route
import io.ktor.server.routing.post
import io.ktor.util.reflect.typeInfo
inline fun <reified Key : Any, reified Value : Any> Route.configureWriteKeyValueRepoRoutes (
originalRepo: WriteKeyValueRepo<Key, Value>
) {
includeWebsocketHandling(
onNewValueRoute,
originalRepo.onNewValue
)
includeWebsocketHandling(
onValueRemovedRoute,
originalRepo.onValueRemoved
)
val mapType = typeInfo<Map<Key, Value>>()
val listKeysType = typeInfo<List<Key>>()
val listValuesType = typeInfo<List<Value>>()
post(setRoute) {
originalRepo.set(call.receive(mapType))
call.respond(HttpStatusCode.OK)
}
post(unsetRoute) {
originalRepo.unset(call.receive(listKeysType))
call.respond(HttpStatusCode.OK)
}
post(unsetWithValuesRoute) {
originalRepo.unsetWithValues(call.receive(listValuesType))
call.respond(HttpStatusCode.OK)
}
}

View File

@@ -0,0 +1,47 @@
package dev.inmo.micro_utils.repos.ktor.server.key.values
import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.repos.*
import io.ktor.http.*
import io.ktor.server.routing.Route
import kotlinx.serialization.*
inline fun <reified Key : Any, reified Value : Any> Route.configureKeyValuesRepoRoutes (
originalRepo: KeyValuesRepo<Key, Value>,
noinline keyDeserializer: suspend (String) -> Key,
noinline valueDeserializer: suspend (String) -> Value
) {
configureReadKeyValuesRepoRoutes(originalRepo, keyDeserializer, valueDeserializer)
configureWriteKeyValuesRepoRoutes(originalRepo)
}
inline fun <reified Key : Any, reified Value : Any> Route.configureKeyValuesRepoRoutes(
originalRepo: KeyValuesRepo<Key, Value>,
keySerializer: DeserializationStrategy<Key>,
valueSerializer: DeserializationStrategy<Value>,
serialFormat: StringFormat
) = configureKeyValuesRepoRoutes(
originalRepo,
{
serialFormat.decodeFromString(keySerializer, it.decodeURLQueryComponent())
},
{
serialFormat.decodeFromString(valueSerializer, it.decodeURLQueryComponent())
}
)
inline fun <reified Key : Any, reified Value : Any> Route.configureKeyValuesRepoRoutes(
originalRepo: KeyValuesRepo<Key, Value>,
keySerializer: DeserializationStrategy<Key>,
valueSerializer: DeserializationStrategy<Value>,
serialFormat: BinaryFormat
) = configureKeyValuesRepoRoutes(
originalRepo,
{
serialFormat.decodeHex(keySerializer, it)
},
{
serialFormat.decodeHex(valueSerializer, it)
}
)

View File

@@ -0,0 +1,108 @@
package dev.inmo.micro_utils.repos.ktor.server.key.values
import dev.inmo.micro_utils.ktor.common.*
import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.pagination.PaginationResult
import dev.inmo.micro_utils.pagination.extractPagination
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
import dev.inmo.micro_utils.repos.ktor.common.*
import dev.inmo.micro_utils.repos.ktor.common.containsRoute
import dev.inmo.micro_utils.repos.ktor.common.countRoute
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
import io.ktor.http.*
import io.ktor.server.application.call
import io.ktor.server.response.respond
import io.ktor.server.routing.Route
import io.ktor.server.routing.get
import io.ktor.util.InternalAPI
import io.ktor.util.reflect.typeInfo
import kotlinx.serialization.*
@OptIn(InternalAPI::class)
inline fun <reified Key, reified Value> Route.configureReadKeyValuesRepoRoutes (
originalRepo: ReadKeyValuesRepo<Key, Value>,
noinline keyDeserializer: suspend (String) -> Key,
noinline valueDeserializer: suspend (String) -> Value
) {
val paginationWithValuesTypeInfo = typeInfo<PaginationResult<Value>>()
val paginationWithKeysTypeInfo = typeInfo<PaginationResult<Key>>()
get(getRoute) {
val key = keyDeserializer(
call.getQueryParameterOrSendError(keyParameterName) ?: return@get
)
val pagination = call.request.queryParameters.extractPagination
val reversed = call.getQueryParameter(reversedParameterName) ?.toBoolean() ?: false
call.respond(
originalRepo.get(key, pagination, reversed),
paginationWithValuesTypeInfo
)
}
get(keysRoute) {
val pagination = call.request.queryParameters.extractPagination
val reversed = call.getQueryParameterOrSendError(reversedParameterName) ?.toBoolean() ?: false
val value = call.getQueryParameter(valueParameterName) ?.let {
valueDeserializer(it)
}
call.respond(
value ?.let { originalRepo.keys(value, pagination, reversed) } ?: originalRepo.keys(pagination, reversed),
paginationWithKeysTypeInfo
)
}
get(containsRoute) {
val key = keyDeserializer(
call.getQueryParameterOrSendError(keyParameterName) ?: return@get
)
val value = call.getQueryParameter(valueParameterName) ?.let {
valueDeserializer(it)
}
call.respond(
value ?.let { originalRepo.contains(key, value) } ?: originalRepo.contains(key)
)
}
get(countRoute) {
val id = call.getQueryParameter(keyParameterName) ?.let {
keyDeserializer(it)
}
call.respond(
id ?.let { originalRepo.count(it) } ?: originalRepo.count()
)
}
}
inline fun <reified Key, reified Value> Route.configureReadKeyValuesRepoRoutes(
originalRepo: ReadKeyValuesRepo<Key, Value>,
keySerializer: DeserializationStrategy<Key>,
valueSerializer: DeserializationStrategy<Value>,
serialFormat: StringFormat
) = configureReadKeyValuesRepoRoutes(
originalRepo,
{
serialFormat.decodeFromString(keySerializer, it.decodeURLQueryComponent())
},
{
serialFormat.decodeFromString(valueSerializer, it.decodeURLQueryComponent())
}
)
inline fun <reified Key, reified Value> Route.configureReadKeyValuesRepoRoutes(
originalRepo: ReadKeyValuesRepo<Key, Value>,
keySerializer: DeserializationStrategy<Key>,
valueSerializer: DeserializationStrategy<Value>,
serialFormat: BinaryFormat
) = configureReadKeyValuesRepoRoutes(
originalRepo,
{
serialFormat.decodeHex(keySerializer, it)
},
{
serialFormat.decodeHex(valueSerializer, it)
}
)

View File

@@ -0,0 +1,58 @@
package dev.inmo.micro_utils.repos.ktor.server.key.values
import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.repos.WriteKeyValuesRepo
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.call
import io.ktor.server.request.receive
import io.ktor.server.response.respond
import io.ktor.server.routing.Route
import io.ktor.server.routing.post
import io.ktor.util.reflect.typeInfo
inline fun <reified Key : Any, reified Value : Any> Route.configureWriteKeyValuesRepoRoutes (
originalRepo: WriteKeyValuesRepo<Key, Value>
) {
includeWebsocketHandling(
onNewValueRoute,
originalRepo.onNewValue
)
includeWebsocketHandling(
onValueRemovedRoute,
originalRepo.onValueRemoved
)
includeWebsocketHandling(
onDataClearedRoute,
originalRepo.onDataCleared
)
val mapType = typeInfo<Map<Key, List<Value>>>()
post(addRoute) {
originalRepo.add(call.receive(mapType))
call.respond(HttpStatusCode.OK)
}
post(setRoute) {
originalRepo.set(call.receive(mapType))
call.respond(HttpStatusCode.OK)
}
post(removeRoute) {
originalRepo.remove(call.receive(mapType))
call.respond(HttpStatusCode.OK)
}
post(clearRoute) {
originalRepo.clear(call.receive())
call.respond(HttpStatusCode.OK)
}
post(clearWithValueRoute) {
originalRepo.clearWithValue(call.receive())
call.respond(HttpStatusCode.OK)
}
}

View File

@@ -4,15 +4,15 @@ import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.UnifiedRouter
import dev.inmo.micro_utils.ktor.server.standardKtorSerialFormatContentType
import dev.inmo.micro_utils.repos.StandardKeyValueRepo
import dev.inmo.micro_utils.repos.KeyValueRepo
import io.ktor.http.ContentType
import io.ktor.server.routing.Route
import io.ktor.server.routing.route
import kotlinx.serialization.KSerializer
fun <K, V> Route.configureStandardKeyValueRepoRoutes(
fun <K, V> Route.configureKeyValueRepoRoutes(
baseSubpart: String,
originalRepo: StandardKeyValueRepo<K, V>,
originalRepo: KeyValueRepo<K, V>,
keySerializer: KSerializer<K>,
valueSerializer: KSerializer<V>,
valueNullableSerializer: KSerializer<V?>,
@@ -26,7 +26,7 @@ fun <K, V> Route.configureStandardKeyValueRepoRoutes(
valueNullableSerializer,
unifiedRouter
)
configureWriteStandardKeyValueRepoRoutes(
configureWriteKeyValueRepoRoutes(
originalRepo,
keySerializer,
valueSerializer,
@@ -37,10 +37,10 @@ fun <K, V> Route.configureStandardKeyValueRepoRoutes(
fun <K, V> Route.configureStandartKeyValueRepoRoutes(
baseSubpart: String,
originalRepo: StandardKeyValueRepo<K, V>,
originalRepo: KeyValueRepo<K, V>,
keySerializer: KSerializer<K>,
valueSerializer: KSerializer<V>,
valueNullableSerializer: KSerializer<V?>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
) = configureStandardKeyValueRepoRoutes(baseSubpart, originalRepo, keySerializer, valueSerializer, valueNullableSerializer, UnifiedRouter(serialFormat, serialFormatContentType))
) = configureKeyValueRepoRoutes(baseSubpart, originalRepo, keySerializer, valueSerializer, valueNullableSerializer, UnifiedRouter(serialFormat, serialFormatContentType))

View File

@@ -5,9 +5,13 @@ import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.pagination.PaginationResult
import dev.inmo.micro_utils.pagination.extractPagination
import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
import dev.inmo.micro_utils.repos.ktor.common.*
import dev.inmo.micro_utils.repos.ktor.common.containsRoute
import dev.inmo.micro_utils.repos.ktor.common.countRoute
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
import dev.inmo.micro_utils.repos.ktor.common.valueParameterName
import dev.inmo.micro_utils.repos.ktor.common.key_value.keyParameterName
import dev.inmo.micro_utils.repos.ktor.common.key_value.reversedParameterName
import io.ktor.http.ContentType
import io.ktor.server.application.call
import io.ktor.server.routing.Route
@@ -16,7 +20,7 @@ import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.serializer
fun <K, V> Route.configureReadStandartKeyValueRepoRoutes (
originalRepo: ReadStandardKeyValueRepo<K, V>,
originalRepo: ReadKeyValueRepo<K, V>,
keySerializer: KSerializer<K>,
valueSerializer: KSerializer<V>,
valueNullableSerializer: KSerializer<V?>,
@@ -92,7 +96,7 @@ fun <K, V> Route.configureReadStandartKeyValueRepoRoutes (
}
inline fun <K, V> Route.configureReadStandartKeyValueRepoRoutes (
originalRepo: ReadStandardKeyValueRepo<K, V>,
originalRepo: ReadKeyValueRepo<K, V>,
keySerializer: KSerializer<K>,
valueSerializer: KSerializer<V>,
valueNullableSerializer: KSerializer<V?>,

View File

@@ -3,7 +3,7 @@ package dev.inmo.micro_utils.repos.ktor.server.key_value
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.repos.WriteStandardKeyValueRepo
import dev.inmo.micro_utils.repos.WriteKeyValueRepo
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
import io.ktor.http.ContentType
import io.ktor.server.routing.Route
@@ -11,8 +11,8 @@ import io.ktor.server.routing.post
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.*
fun <K, V> Route.configureWriteStandardKeyValueRepoRoutes (
originalRepo: WriteStandardKeyValueRepo<K, V>,
fun <K, V> Route.configureWriteKeyValueRepoRoutes (
originalRepo: WriteKeyValueRepo<K, V>,
keySerializer: KSerializer<K>,
valueSerializer: KSerializer<V>,
unifiedRouter: UnifiedRouter
@@ -62,9 +62,9 @@ fun <K, V> Route.configureWriteStandardKeyValueRepoRoutes (
}
fun <K, V> Route.configureWriteStandartKeyValueRepoRoutes (
originalRepo: WriteStandardKeyValueRepo<K, V>,
originalRepo: WriteKeyValueRepo<K, V>,
keySerializer: KSerializer<K>,
valueSerializer: KSerializer<V>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,
serialFormatContentType: ContentType = standardKtorSerialFormatContentType
) = configureWriteStandardKeyValueRepoRoutes(originalRepo, keySerializer, valueSerializer, UnifiedRouter(serialFormat, serialFormatContentType))
) = configureWriteKeyValueRepoRoutes(originalRepo, keySerializer, valueSerializer, UnifiedRouter(serialFormat, serialFormatContentType))

View File

@@ -4,7 +4,7 @@ import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.UnifiedRouter
import dev.inmo.micro_utils.ktor.server.standardKtorSerialFormatContentType
import dev.inmo.micro_utils.repos.OneToManyKeyValueRepo
import dev.inmo.micro_utils.repos.KeyValuesRepo
import io.ktor.http.ContentType
import io.ktor.server.routing.Route
import io.ktor.server.routing.route
@@ -12,7 +12,7 @@ import kotlinx.serialization.KSerializer
fun <Key, Value> Route.configureOneToManyKeyValueRepoRoutes(
baseSubpart: String,
originalRepo: OneToManyKeyValueRepo<Key, Value>,
originalRepo: KeyValuesRepo<Key, Value>,
keySerializer: KSerializer<Key>,
valueSerializer: KSerializer<Value>,
unifiedRouter: UnifiedRouter
@@ -25,7 +25,7 @@ fun <Key, Value> Route.configureOneToManyKeyValueRepoRoutes(
fun <Key, Value> Route.configureOneToManyKeyValueRepoRoutes(
baseSubpart: String,
originalRepo: OneToManyKeyValueRepo<Key, Value>,
originalRepo: KeyValuesRepo<Key, Value>,
keySerializer: KSerializer<Key>,
valueSerializer: KSerializer<Value>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,

View File

@@ -5,7 +5,7 @@ import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.pagination.PaginationResult
import dev.inmo.micro_utils.pagination.extractPagination
import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
import dev.inmo.micro_utils.repos.ktor.common.keyParameterName
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
import dev.inmo.micro_utils.repos.ktor.common.valueParameterName
@@ -18,7 +18,7 @@ import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.serializer
fun <Key, Value> Route.configureOneToManyReadKeyValueRepoRoutes(
originalRepo: ReadOneToManyKeyValueRepo<Key, Value>,
originalRepo: ReadKeyValuesRepo<Key, Value>,
keySerializer: KSerializer<Key>,
valueSerializer: KSerializer<Value>,
unifiedRouter: UnifiedRouter
@@ -121,7 +121,7 @@ fun <Key, Value> Route.configureOneToManyReadKeyValueRepoRoutes(
}
inline fun <Key, Value> Route.configureOneToManyReadKeyValueRepoRoutes(
originalRepo: ReadOneToManyKeyValueRepo<Key, Value>,
originalRepo: ReadKeyValuesRepo<Key, Value>,
keySerializer: KSerializer<Key>,
valueSerializer: KSerializer<Value>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,

View File

@@ -3,7 +3,7 @@ package dev.inmo.micro_utils.repos.ktor.server.one_to_many
import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.repos.WriteOneToManyKeyValueRepo
import dev.inmo.micro_utils.repos.WriteKeyValuesRepo
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.*
import io.ktor.http.ContentType
import io.ktor.server.routing.Route
@@ -12,7 +12,7 @@ import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.*
fun <Key, Value> Route.configureOneToManyWriteKeyValueRepoRoutes(
originalRepo: WriteOneToManyKeyValueRepo<Key, Value>,
originalRepo: WriteKeyValuesRepo<Key, Value>,
keySerializer: KSerializer<Key>,
valueSerializer: KSerializer<Value>,
unifiedRouter: UnifiedRouter
@@ -95,7 +95,7 @@ fun <Key, Value> Route.configureOneToManyWriteKeyValueRepoRoutes(
}
fun <Key, Value> Route.configureOneToManyWriteKeyValueRepoRoutes(
originalRepo: WriteOneToManyKeyValueRepo<Key, Value>,
originalRepo: WriteKeyValuesRepo<Key, Value>,
keySerializer: KSerializer<Key>,
valueSerializer: KSerializer<Value>,
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat,